From: Josep Orga Date: Sun, 22 Mar 2020 17:58:33 +0000 (+0100) Subject: ARM: Updated WiFi WILC1000 source code: X-Git-Tag: C0P2-H0.0--20200415~5 X-Git-Url: https://git.somdevices.com/?a=commitdiff_plain;h=4f36d1183b1707f1c0571656668ec3fba43b0810;p=linux.git ARM: Updated WiFi WILC1000 source code: · Based on tag wilc_linux_15_3_1 in https://github.com/linux4wilc/driver/tree/wilc_linux_15_3_1 · Firmware wilc1000_wifi_firmware.bin is located in https://github.com/linux4wilc/firmware/tree/wilc_linux_15_3_1 Signed-off-by: Josep Orga --- diff --git a/drivers/net/wireless/mchp/Makefile b/drivers/net/wireless/mchp/Makefile index 9f440b511960..7eb8cf09bfa2 100644 --- a/drivers/net/wireless/mchp/Makefile +++ b/drivers/net/wireless/mchp/Makefile @@ -1,9 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 ccflags-y += -I$(src)/ -DWILC_ASIC_A0 -DWILC_DEBUGFS -ccflags-y += -DDISABLE_PWRSAVE_AND_SCAN_DURING_IP wilc-objs := wilc_wfi_cfgoperations.o wilc_netdev.o wilc_mon.o \ - host_interface.o wilc_wlan_cfg.o wilc_debugfs.o \ + wilc_hif.o wilc_wlan_cfg.o wilc_debugfs.o \ wilc_wlan.o sysfs.o wilc_bt.o obj-$(CONFIG_WILC_SDIO) += wilc-sdio.o diff --git a/drivers/net/wireless/mchp/host_interface.c b/drivers/net/wireless/mchp/host_interface.c deleted file mode 100644 index c8eba4ff17e9..000000000000 --- a/drivers/net/wireless/mchp/host_interface.c +++ /dev/null @@ -1,2769 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. - * All rights reserved. - */ - -#include - -#include "wilc_wfi_netdevice.h" -#include "wilc_netdev.h" -#include "wilc_wfi_cfgoperations.h" - -#define WILC_HIF_SCAN_TIMEOUT_MS 5000 -#define WILC_HIF_CONNECT_TIMEOUT_MS 9500 - -#define WILC_FALSE_FRMWR_CHANNEL 100 -#define WILC_MAX_RATES_SUPPORTED 12 - -/* Generic success will return 0 */ -#define WILC_SUCCESS 0 /* Generic success */ - -/* Negative numbers to indicate failures */ -/* Generic Fail */ -#define WILC_FAIL -100 -/* Busy with another operation*/ -#define WILC_BUSY -101 -/* A given argument is invalid*/ -#define WILC_INVALID_ARGUMENT -102 -/* An API request would violate the Driver state machine - * (i.e. to start PID while not camped) - */ -#define WILC_INVALID_STATE -103 -/* In copy operations if the copied data is larger than the allocated buffer*/ -#define WILC_BUFFER_OVERFLOW -104 -/* null pointer is passed or used */ -#define WILC_NULL_PTR -105 -#define WILC_EMPTY -107 -#define WILC_FULL -108 -#define WILC_TIMEOUT -109 -/* The required operation have been canceled by the user*/ -#define WILC_CANCELED -110 -/* The Loaded file is corruped or having an invalid format */ -#define WILC_INVALID_FILE -112 -/* Cant find the file to load */ -#define WILC_NOT_FOUND -113 -#define WILC_NO_MEM -114 -#define WILC_UNSUPPORTED_VERSION -115 -#define WILC_FILE_EOF -116 - -#if KERNEL_VERSION(3, 17, 0) > LINUX_VERSION_CODE -struct ieee80211_wmm_ac_param { - u8 aci_aifsn; /* AIFSN, ACM, ACI */ - u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ - __le16 txop_limit; -} __packed; - -struct ieee80211_wmm_param_ie { - u8 element_id; /* Element ID: 221 (0xdd); */ - u8 len; /* Length: 24 */ - u8 oui[3]; /* 00:50:f2 */ - u8 oui_type; /* 2 */ - u8 oui_subtype; /* 1 */ - u8 version; /* 1 for WMM version 1.0 */ - u8 qos_info; /* AP/STA specific QoS info */ - u8 reserved; /* 0 */ - /* AC_BE, AC_BK, AC_VI, AC_VO */ - struct ieee80211_wmm_ac_param ac[4]; -} __packed; -#endif - -struct send_buffered_eap { - void (*deliver_to_stack)(struct wilc_vif *vif, u8 *buff, u32 size, - u32 pkt_offset, u8 status); - void (*eap_buf_param)(void *priv); - u8 *buff; - unsigned int size; - unsigned int pkt_offset; - void *user_arg; -}; - -struct wilc_rcvd_mac_info { - u8 status; -}; - -struct wilc_set_multicast { - u32 enabled; - u32 cnt; - u8 *mc_list; -}; - -struct host_if_wowlan_trigger { - u8 wowlan_trigger; -}; - -struct bt_coex_mode { - u8 bt_coex; -}; - -struct host_if_set_ant { - u8 mode; - u8 antenna1; - u8 antenna2; - u8 gpio_mode; -}; - -struct wilc_del_all_sta { - u8 assoc_sta; - u8 mac[WILC_MAX_NUM_STA][ETH_ALEN]; -}; - -struct wilc_op_mode { - __le32 mode; -}; - -struct wilc_reg_frame { - bool reg; - u8 reg_id; - __le16 frame_type; -} __packed; - -struct wilc_drv_handler { - __le32 handler; - u8 mode; -} __packed; - -struct wilc_wep_key { - u8 index; - u8 key_len; - u8 key[0]; -} __packed; - -struct wilc_sta_wpa_ptk { - u8 mac_addr[ETH_ALEN]; - u8 key_len; - u8 key[0]; -} __packed; - -struct wilc_ap_wpa_ptk { - u8 mac_addr[ETH_ALEN]; - u8 index; - u8 key_len; - u8 key[0]; -} __packed; - -struct wilc_gtk_key { - u8 mac_addr[ETH_ALEN]; - u8 rsc[8]; - u8 index; - u8 key_len; - u8 key[0]; -} __packed; - -union wilc_message_body { - struct wilc_rcvd_net_info net_info; - struct wilc_rcvd_mac_info mac_info; - struct wilc_set_multicast mc_info; - struct wilc_remain_ch remain_on_ch; - char *data; - struct send_buffered_eap send_buff_eap; - struct host_if_set_ant set_ant; - struct host_if_wowlan_trigger wow_trigger; - struct bt_coex_mode bt_coex_mode; -}; - -struct host_if_msg { - union wilc_message_body body; - struct wilc_vif *vif; - struct work_struct work; - void (*fn)(struct work_struct *ws); - struct completion work_comp; - bool is_sync; -}; - -struct wilc_noa_opp_enable { - u8 ct_window; - u8 cnt; - __le32 duration; - __le32 interval; - __le32 start_time; -} __packed; - -struct wilc_noa_opp_disable { - u8 cnt; - __le32 duration; - __le32 interval; - __le32 start_time; -} __packed; - -struct wilc_join_bss_param { - char ssid[IEEE80211_MAX_SSID_LEN]; - u8 ssid_terminator; - u8 bss_type; - u8 ch; - __le16 cap_info; - u8 sa[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - __le16 beacon_period; - u8 dtim_period; - u8 supp_rates[WILC_MAX_RATES_SUPPORTED + 1]; - u8 wmm_cap; - u8 uapsd_cap; - u8 ht_capable; - u8 rsn_found; - u8 rsn_grp_policy; - u8 mode_802_11i; - u8 p_suites[3]; - u8 akm_suites[3]; - u8 rsn_cap[2]; - u8 noa_enabled; - __le32 tsf_lo; - u8 idx; - u8 opp_enabled; - union { - struct wilc_noa_opp_disable opp_dis; - struct wilc_noa_opp_enable opp_en; - }; -} __packed; - -/* 'msg' should be free by the caller for syc */ -static struct host_if_msg* -wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *), - bool is_sync) -{ - struct host_if_msg *msg; - - if (!work_fun) - return ERR_PTR(-EINVAL); - - msg = kzalloc(sizeof(*msg), GFP_ATOMIC); - if (!msg) - return ERR_PTR(-ENOMEM); - msg->fn = work_fun; - msg->vif = vif; - msg->is_sync = is_sync; - if (is_sync) - init_completion(&msg->work_comp); - - return msg; -} - -static int wilc_enqueue_work(struct host_if_msg *msg) -{ - INIT_WORK(&msg->work, msg->fn); - - if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue) - return -EINVAL; - - if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work)) - return -EINVAL; - - return 0; -} - -/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as - * special purpose in wilc device, so we add 1 to the index to starts from 1. - * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC. - */ -int wilc_get_vif_idx(struct wilc_vif *vif) -{ - return vif->idx + 1; -} - -/* We need to minus 1 from idx which is from wilc device to get real index - * of wilc->vif[], because we add 1 when pass to wilc device in the function - * wilc_get_vif_idx. - * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1). - */ -static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx) -{ - int index = idx - 1; - - if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC) - return NULL; - - return wilc->vif[index]; -} - -static void handle_send_buffered_eap(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - struct wilc_vif *vif = msg->vif; - struct send_buffered_eap *hif_buff_eap = &msg->body.send_buff_eap; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Sending bufferd eapol to WPAS\n"); - if (!hif_buff_eap->buff) - goto out; - - if (hif_buff_eap->deliver_to_stack) - hif_buff_eap->deliver_to_stack(vif, hif_buff_eap->buff, - hif_buff_eap->size, - hif_buff_eap->pkt_offset, - PKT_STATUS_BUFFERED); - if (hif_buff_eap->eap_buf_param) - hif_buff_eap->eap_buf_param(hif_buff_eap->user_arg); - - if (hif_buff_eap->buff != NULL) { - kfree(hif_buff_eap->buff); - hif_buff_eap->buff = NULL; - } - -out: - kfree(msg); -} - -int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, - void (*scan_result_fn)(enum scan_event, - struct wilc_rcvd_net_info *, void *), - void *user_arg, struct cfg80211_scan_request *request) -{ - int result = 0; - struct wid wid_list[5]; - u32 index = 0; - u32 i, scan_timeout; - u8 *buffer; - u8 valuesize = 0; - u8 *search_ssid_vals = NULL; - struct host_if_drv *hif_drv = vif->hif_drv; - struct host_if_drv *hif_drv_p2p = get_drv_hndl_by_ifc(vif->wilc, - WILC_P2P_IFC); - struct host_if_drv *hif_drv_wlan = get_drv_hndl_by_ifc(vif->wilc, - WILC_WLAN_IFC); - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Setting SCAN params\n"); - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Scanning: In [%d] state\n", - hif_drv->hif_state); - - if (hif_drv_p2p != NULL) { - if (hif_drv_p2p->hif_state != HOST_IF_IDLE && - hif_drv_p2p->hif_state != HOST_IF_CONNECTED) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Don't scan. P2P_IFC is in state [%d]\n", - hif_drv_p2p->hif_state); - result = -EBUSY; - goto error; - } - } - - if (hif_drv_wlan != NULL) { - if (hif_drv_wlan->hif_state != HOST_IF_IDLE && - hif_drv_wlan->hif_state != HOST_IF_CONNECTED) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Don't scan. WLAN_IFC is in state [%d]\n", - hif_drv_wlan->hif_state); - result = -EBUSY; - goto error; - } - } - if (vif->connecting) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Don't do scan in (CONNECTING) state\n"); - result = -EBUSY; - goto error; - } -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - if (vif->obtaining_ip) { - PRINT_ER(vif->ndev, "Don't do obss scan\n"); - result = -EBUSY; - goto error; - } -#endif - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Setting SCAN params\n"); - hif_drv->usr_scan_req.ch_cnt = 0; - - if (request->n_ssids) { - for (i = 0; i < request->n_ssids; i++) - valuesize += ((request->ssids[i].ssid_len) + 1); - search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL); - if (search_ssid_vals) { - wid_list[index].id = WID_SSID_PROBE_REQ; - wid_list[index].type = WID_STR; - wid_list[index].val = search_ssid_vals; - buffer = wid_list[index].val; - - *buffer++ = request->n_ssids; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "In Handle_ProbeRequest number of ssid %d\n", - request->n_ssids); - for (i = 0; i < request->n_ssids; i++) { - *buffer++ = request->ssids[i].ssid_len; - memcpy(buffer, request->ssids[i].ssid, - request->ssids[i].ssid_len); - buffer += request->ssids[i].ssid_len; - } - wid_list[index].size = (s32)(valuesize + 1); - index++; - } - } - - wid_list[index].id = WID_INFO_ELEMENT_PROBE; - wid_list[index].type = WID_BIN_DATA; - wid_list[index].val = (s8 *)request->ie; - wid_list[index].size = request->ie_len; - index++; - - wid_list[index].id = WID_SCAN_TYPE; - wid_list[index].type = WID_CHAR; - wid_list[index].size = sizeof(char); - wid_list[index].val = (s8 *)&scan_type; - index++; - -#if KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE - scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS; -#else - if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) { - wid_list[index].id = WID_PASSIVE_SCAN_TIME; - wid_list[index].type = WID_SHORT; - wid_list[index].size = sizeof(u16); - wid_list[index].val = (s8 *)&request->duration; - index++; - - scan_timeout = (request->duration * ch_list_len) + 500; - } else { - scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS; - } -#endif - wid_list[index].id = WID_SCAN_CHANNEL_LIST; - wid_list[index].type = WID_BIN_DATA; - - if (ch_freq_list && ch_list_len > 0) { - for (i = 0; i < ch_list_len; i++) { - if (ch_freq_list[i] > 0) - ch_freq_list[i] -= 1; - } - } - - wid_list[index].val = ch_freq_list; - wid_list[index].size = ch_list_len; - index++; - - wid_list[index].id = WID_START_SCAN_REQ; - wid_list[index].type = WID_CHAR; - wid_list[index].size = sizeof(char); - wid_list[index].val = (s8 *)&scan_source; - index++; - - hif_drv->usr_scan_req.scan_result = scan_result_fn; - hif_drv->usr_scan_req.arg = user_arg; - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, - index, - wilc_get_vif_idx(vif)); - if (result) { - PRINT_ER(vif->ndev, "Failed to send scan parameters\n"); - goto error; - } else { - hif_drv->scan_timer_vif = vif; - PRINT_INFO(vif->ndev, HOSTINF_DBG, - ">> Starting the SCAN timer\n"); -#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE - hif_drv->scan_timer.data = (unsigned long)hif_drv; -#endif - mod_timer(&hif_drv->scan_timer, - jiffies + msecs_to_jiffies(scan_timeout)); - } - -error: - - kfree(search_ssid_vals); - - return result; -} - -s32 handle_scan_done(struct wilc_vif *vif, enum scan_event evt) -{ - s32 result = 0; - u8 abort_running_scan; - struct wid wid; - struct host_if_drv *hif_drv = vif->hif_drv; - struct wilc_user_scan_req *scan_req; - u8 null_bssid[6] = {0}; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "handling scan done\n"); - - if (!hif_drv) { - PRINT_ER(vif->ndev, "hif driver is NULL\n"); - return result; - } - - if (evt == SCAN_EVENT_DONE) { - if (memcmp(hif_drv->assoc_bssid, null_bssid, ETH_ALEN) == 0) - hif_drv->hif_state = HOST_IF_IDLE; - else - hif_drv->hif_state = HOST_IF_CONNECTED; - } else if (evt == SCAN_EVENT_ABORTED) { - PRINT_INFO(vif->ndev, GENERIC_DBG, "Abort running scan\n"); - abort_running_scan = 1; - wid.id = WID_ABORT_RUNNING_SCAN; - wid.type = WID_CHAR; - wid.val = (s8 *)&abort_running_scan; - wid.size = sizeof(char); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - - if (result) { - PRINT_ER(vif->ndev, "Failed to set abort running\n"); - result = -EFAULT; - } - } - - scan_req = &hif_drv->usr_scan_req; - if (scan_req->scan_result) { - scan_req->scan_result(evt, NULL, scan_req->arg); - scan_req->scan_result = NULL; - } - - return result; -} - -static int wilc_send_connect_wid(struct wilc_vif *vif) -{ - int result = 0; - struct wid wid_list[4]; - u32 wid_cnt = 0; - struct host_if_drv *hif_drv = vif->hif_drv; - struct wilc_conn_info *conn_attr = &hif_drv->conn_info; - struct wilc_join_bss_param *bss_param = hif_drv->conn_info.param; - struct host_if_drv *hif_drv_p2p = get_drv_hndl_by_ifc(vif->wilc, - WILC_P2P_IFC); - struct host_if_drv *hif_drv_wlan = get_drv_hndl_by_ifc(vif->wilc, - WILC_WLAN_IFC); - - if (hif_drv_p2p != NULL) { - if (hif_drv_p2p->hif_state == HOST_IF_SCANNING) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Don't scan. P2P_IFC is in state [%d]\n", - hif_drv_p2p->hif_state); - result = -EFAULT; - goto error; - } - } - if (hif_drv_wlan != NULL) { - if (hif_drv_wlan->hif_state == HOST_IF_SCANNING) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Don't scan. WLAN_IFC is in state [%d]\n", - hif_drv_wlan->hif_state); - result = -EFAULT; - goto error; - } - } - - wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE; - wid_list[wid_cnt].type = WID_BIN_DATA; - wid_list[wid_cnt].val = conn_attr->req_ies; - wid_list[wid_cnt].size = conn_attr->req_ies_len; - wid_cnt++; - - wid_list[wid_cnt].id = WID_11I_MODE; - wid_list[wid_cnt].type = WID_CHAR; - wid_list[wid_cnt].size = sizeof(char); - wid_list[wid_cnt].val = (s8 *)&conn_attr->security; - wid_cnt++; - - PRINT_D(vif->ndev, HOSTINF_DBG, "Encrypt Mode = %x\n", - conn_attr->security); - wid_list[wid_cnt].id = WID_AUTH_TYPE; - wid_list[wid_cnt].type = WID_CHAR; - wid_list[wid_cnt].size = sizeof(char); - wid_list[wid_cnt].val = (s8 *)&conn_attr->auth_type; - wid_cnt++; - - PRINT_D(vif->ndev, HOSTINF_DBG, "Authentication Type = %x\n", - conn_attr->auth_type); - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Connecting to network on channel %d\n", conn_attr->ch); - - wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED; - wid_list[wid_cnt].type = WID_STR; - wid_list[wid_cnt].size = sizeof(*bss_param); - wid_list[wid_cnt].val = (u8 *)bss_param; - wid_cnt++; - - PRINT_INFO(vif->ndev, GENERIC_DBG, "send HOST_IF_WAITING_CONN_RESP\n"); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, - wid_cnt, - wilc_get_vif_idx(vif)); - if (result) { - PRINT_ER(vif->ndev, "failed to send config packet\n"); - goto error; - } else { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "set HOST_IF_WAITING_CONN_RESP\n"); - hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP; - } - - return 0; - -error: - - kfree(conn_attr->req_ies); - conn_attr->req_ies = NULL; - - return result; -} - -static void handle_connect_timeout(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - struct wilc_vif *vif = msg->vif; - int result; - struct wid wid; - u16 dummy_reason_code = 0; - struct host_if_drv *hif_drv = vif->hif_drv; - - if (!hif_drv) { - PRINT_ER(vif->ndev, "hif driver is NULL\n"); - goto out; - } - - hif_drv->hif_state = HOST_IF_IDLE; - - if (hif_drv->conn_info.conn_result) { - hif_drv->conn_info.conn_result(EVENT_CONN_RESP, - WILC_MAC_STATUS_DISCONNECTED, - hif_drv->conn_info.arg); - - } else { - PRINT_ER(vif->ndev, "conn_result is NULL\n"); - } - - wid.id = WID_DISCONNECT; - wid.type = WID_CHAR; - wid.val = (s8 *)&dummy_reason_code; - wid.size = sizeof(char); - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Sending disconnect request\n"); - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to send disconect\n"); - - hif_drv->conn_info.req_ies_len = 0; - kfree(hif_drv->conn_info.req_ies); - hif_drv->conn_info.req_ies = NULL; - -out: - kfree(msg); -} - -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, - struct cfg80211_crypto_settings *crypto) -{ - struct wilc_join_bss_param *param; - struct ieee80211_p2p_noa_attr noa_attr; - u8 rates_len = 0; - const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; - const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; - int ret; - const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies); - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) - return NULL; - - param->beacon_period = cpu_to_le16(bss->beacon_interval); - param->cap_info = cpu_to_le16(bss->capability); - param->bss_type = WILC_FW_BSS_TYPE_INFRA; - param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq); - ether_addr_copy(param->bssid, bss->bssid); - - ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); - if (ssid_elm) { - if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN) - memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]); - } - - tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); - if (tim_elm && tim_elm[1] >= 2) - param->dtim_period = tim_elm[3]; - - memset(param->p_suites, 0xFF, 3); - memset(param->akm_suites, 0xFF, 3); - - rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len); - if (rates_ie) { - rates_len = rates_ie[1]; - param->supp_rates[0] = rates_len; - memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len); - } - - supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data, - ies->len); - if (supp_rates_ie) { - if (supp_rates_ie[1] > (WILC_MAX_RATES_SUPPORTED - rates_len)) - param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED; - else - param->supp_rates[0] += supp_rates_ie[1]; - - memcpy(¶m->supp_rates[rates_len + 1], supp_rates_ie + 2, - (param->supp_rates[0] - rates_len)); - } - - ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len); - if (ht_ie) - param->ht_capable = true; - - ret = cfg80211_get_p2p_attr(ies->data, ies->len, - IEEE80211_P2P_ATTR_ABSENCE_NOTICE, - (u8 *)&noa_attr, sizeof(noa_attr)); - if (ret > 0) { - param->tsf_lo = cpu_to_le32(ies->tsf); - param->noa_enabled = 1; - param->idx = noa_attr.index; - if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) { - param->opp_enabled = 1; - param->opp_en.ct_window = noa_attr.oppps_ctwindow; - param->opp_en.cnt = noa_attr.desc[0].count; - param->opp_en.duration = noa_attr.desc[0].duration; - param->opp_en.interval = noa_attr.desc[0].interval; - param->opp_en.start_time = noa_attr.desc[0].start_time; - } else { - param->opp_enabled = 0; - param->opp_dis.cnt = noa_attr.desc[0].count; - param->opp_dis.duration = noa_attr.desc[0].duration; - param->opp_dis.interval = noa_attr.desc[0].interval; - param->opp_dis.start_time = noa_attr.desc[0].start_time; - } - } - wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, - WLAN_OUI_TYPE_MICROSOFT_WMM, - ies->data, ies->len); - if (wmm_ie) { - struct ieee80211_wmm_param_ie *ie; - - ie = (struct ieee80211_wmm_param_ie *)wmm_ie; - if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) && - ie->version == 1) { - param->wmm_cap = true; - if (ie->qos_info & BIT(7)) - param->uapsd_cap = true; - } - } - - wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, - WLAN_OUI_TYPE_MICROSOFT_WPA, - ies->data, ies->len); - if (wpa_ie) { - param->mode_802_11i = 1; - param->rsn_found = true; - } - - rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len); - if (rsn_ie) { - int offset = 8; - - param->mode_802_11i = 2; - param->rsn_found = true; - //extract RSN capabilities - offset += (rsn_ie[offset] * 4) + 2; - offset += (rsn_ie[offset] * 4) + 2; - memcpy(param->rsn_cap, &rsn_ie[offset], 2); - } - - if (param->rsn_found) { - int i; - - param->rsn_grp_policy = crypto->cipher_group & 0xFF; - for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++) - param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF; - - for (i = 0; i < crypto->n_akm_suites && i < 3; i++) - param->akm_suites[i] = crypto->akm_suites[i] & 0xFF; - } - - return (void *)param; -} - -static void handle_rcvd_ntwrk_info(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - struct wilc_rcvd_net_info *rcvd_info = &msg->body.net_info; - struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req; - const u8 *ch_elm; - u8 *ies; - int ies_len; - size_t offset; - - PRINT_D(msg->vif->ndev, HOSTINF_DBG, - "Handling received network info\n"); - - if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control)) - offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); - else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control)) - offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); - else - goto done; - - ies = rcvd_info->mgmt->u.beacon.variable; - ies_len = rcvd_info->frame_len - offset; - if (ies_len <= 0) - goto done; - - PRINT_INFO(msg->vif->ndev, HOSTINF_DBG, "New network found\n"); - /* extract the channel from recevied mgmt frame */ - ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len); - if (ch_elm && ch_elm[1] > 0) - rcvd_info->ch = ch_elm[2]; - - if (scan_req->scan_result) - scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, - rcvd_info, scan_req->arg); - -done: - kfree(rcvd_info->mgmt); - kfree(msg); -} - -static void host_int_get_assoc_res_info(struct wilc_vif *vif, - u8 *assoc_resp_info, - u32 max_assoc_resp_info_len, - u32 *rcvd_assoc_resp_info_len) -{ - int result; - struct wid wid; - - wid.id = WID_ASSOC_RES_INFO; - wid.type = WID_STR; - wid.val = assoc_resp_info; - wid.size = max_assoc_resp_info_len; - - result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) { - *rcvd_assoc_resp_info_len = 0; - PRINT_ER(vif->ndev, "Failed to send association response\n"); - return; - } - - *rcvd_assoc_resp_info_len = wid.size; -} - -static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len, - struct wilc_conn_info *ret_conn_info) -{ - u8 *ies; - u16 ies_len; - struct assoc_resp *res = (struct assoc_resp *)buffer; - - ret_conn_info->status = le16_to_cpu(res->status_code); - if (ret_conn_info->status == WLAN_STATUS_SUCCESS) { - ies = &buffer[sizeof(*res)]; - ies_len = buffer_len - sizeof(*res); - - ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL); - if (!ret_conn_info->resp_ies) - return -ENOMEM; - - ret_conn_info->resp_ies_len = ies_len; - } - - return 0; -} - -static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, - u8 mac_status) -{ - struct host_if_drv *hif_drv = vif->hif_drv; - struct wilc_conn_info *conn_info = &hif_drv->conn_info; - - if (mac_status == WILC_MAC_STATUS_CONNECTED) { - u32 assoc_resp_info_len; - - memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE); - - host_int_get_assoc_res_info(vif, hif_drv->assoc_resp, - WILC_MAX_ASSOC_RESP_FRAME_SIZE, - &assoc_resp_info_len); - - PRINT_D(vif->ndev, HOSTINF_DBG, - "Received association response = %d\n", - assoc_resp_info_len); - if (assoc_resp_info_len != 0) { - s32 err = 0; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Parsing association response\n"); - err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp, - assoc_resp_info_len, - conn_info); - if (err) - PRINT_ER(vif->ndev, - "wilc_parse_assoc_resp_info() returned error %d\n", - err); - } - } - - del_timer(&hif_drv->connect_timer); - conn_info->conn_result(EVENT_CONN_RESP, mac_status, conn_info->arg); - - if (mac_status == WILC_MAC_STATUS_CONNECTED && - conn_info->status == WLAN_STATUS_SUCCESS) { - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "MAC status : CONNECTED and Connect Status : Successful\n"); - hif_drv->hif_state = HOST_IF_CONNECTED; - ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid); -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - handle_pwrsave_for_IP(vif, IP_STATE_OBTAINING); -#endif - } else { - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "MAC status : %d and Connect Status : %d\n", - mac_status, conn_info->status); - hif_drv->hif_state = HOST_IF_IDLE; - } - - kfree(conn_info->resp_ies); - conn_info->resp_ies = NULL; - conn_info->resp_ies_len = 0; - - kfree(conn_info->req_ies); - conn_info->req_ies = NULL; - conn_info->req_ies_len = 0; -} - -static inline void host_int_handle_disconnect(struct wilc_vif *vif) -{ - struct host_if_drv *hif_drv = vif->hif_drv; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Received WILC_MAC_STATUS_DISCONNECTED from the FW\n"); - if (hif_drv->usr_scan_req.scan_result) { - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "\n\n<< Abort the running OBSS Scan >>\n\n"); - del_timer(&hif_drv->scan_timer); - handle_scan_done(vif, SCAN_EVENT_ABORTED); - } - - if (hif_drv->conn_info.conn_result) { -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - handle_pwrsave_for_IP(vif, IP_STATE_DEFAULT); -#endif - - hif_drv->conn_info.conn_result(EVENT_DISCONN_NOTIF, - 0, hif_drv->conn_info.arg); - } else { - PRINT_ER(vif->ndev, "Connect result NULL\n"); - } - - eth_zero_addr(hif_drv->assoc_bssid); - - hif_drv->conn_info.req_ies_len = 0; - kfree(hif_drv->conn_info.req_ies); - hif_drv->conn_info.req_ies = NULL; - hif_drv->hif_state = HOST_IF_IDLE; -} - -static void handle_rcvd_gnrl_async_info(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - struct wilc_vif *vif = msg->vif; - struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info; - struct host_if_drv *hif_drv = vif->hif_drv; - - if (!hif_drv) { - netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__); - goto free_msg; - } - - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Current State = %d,Received state = %d\n", - hif_drv->hif_state, mac_info->status); - - if (!hif_drv->conn_info.conn_result) { - PRINT_ER(vif->ndev, "conn_result is NULL\n"); - goto free_msg; - } - if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { - host_int_parse_assoc_resp_info(vif, mac_info->status); - } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) { - if (hif_drv->hif_state == HOST_IF_CONNECTED) { - host_int_handle_disconnect(vif); - } else if (hif_drv->usr_scan_req.scan_result) { - PRINT_WRN(vif->ndev, HOSTINF_DBG, - "Received WILC_MAC_STATUS_DISCONNECTED. Abort the running Scan"); - del_timer(&hif_drv->scan_timer); - handle_scan_done(vif, SCAN_EVENT_ABORTED); - } - } - -free_msg: - kfree(msg); -} - -int wilc_disconnect(struct wilc_vif *vif) -{ - struct wid wid; - struct host_if_drv *hif_drv = vif->hif_drv; - struct wilc_user_scan_req *scan_req; - struct wilc_conn_info *conn_info; - int result; - u16 dummy_reason_code = 0; - struct host_if_drv *hif_drv_p2p = get_drv_hndl_by_ifc(vif->wilc, - WILC_P2P_IFC); - struct host_if_drv *hif_drv_wlan = get_drv_hndl_by_ifc(vif->wilc, - WILC_WLAN_IFC); - - if (hif_drv_wlan != NULL) { - if (hif_drv_wlan->hif_state == HOST_IF_SCANNING) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Abort Scan. WLAN_IFC is in state [%d]\n", - hif_drv_wlan->hif_state); - del_timer(&hif_drv_wlan->scan_timer); - handle_scan_done(vif, SCAN_EVENT_ABORTED); - } - } - if (hif_drv_p2p != NULL) { - if (hif_drv_p2p->hif_state == HOST_IF_SCANNING) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Abort Scan. P2P_IFC is in state [%d]\n", - hif_drv_p2p->hif_state); - del_timer(&hif_drv_p2p->scan_timer); - handle_scan_done(vif, SCAN_EVENT_ABORTED); - } - } - wid.id = WID_DISCONNECT; - wid.type = WID_CHAR; - wid.val = (s8 *)&dummy_reason_code; - wid.size = sizeof(char); - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Sending disconnect request\n"); - -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - handle_pwrsave_for_IP(vif, IP_STATE_DEFAULT); -#endif - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - - if (result) { - PRINT_ER(vif->ndev, "Failed to send disconnect\n"); - return -ENOMEM; - } - - scan_req = &hif_drv->usr_scan_req; - conn_info = &hif_drv->conn_info; - - if (scan_req->scan_result) { - del_timer(&hif_drv->scan_timer); - scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg); - scan_req->scan_result = NULL; - } - - if (conn_info->conn_result) { - if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "supplicant requested disconnection\n"); - del_timer(&hif_drv->connect_timer); - conn_info->conn_result(EVENT_CONN_RESP, - WILC_MAC_STATUS_DISCONNECTED, - conn_info->arg); - - } else if (hif_drv->hif_state == HOST_IF_CONNECTED) { - conn_info->conn_result(EVENT_DISCONN_NOTIF, - WILC_MAC_STATUS_DISCONNECTED, - conn_info->arg); - } - } else { - PRINT_ER(vif->ndev, "conn_result = NULL\n"); - } - - hif_drv->hif_state = HOST_IF_IDLE; - - eth_zero_addr(hif_drv->assoc_bssid); - - conn_info->req_ies_len = 0; - kfree(conn_info->req_ies); - conn_info->req_ies = NULL; - - return 0; -} - -void wilc_resolve_disconnect_aberration(struct wilc_vif *vif) -{ - if (!vif->hif_drv) - return; - if (vif->hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP || - vif->hif_drv->hif_state == HOST_IF_CONNECTING) { - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "\n\n<< correcting Supplicant state machine >>\n\n"); - wilc_disconnect(vif); - } -} - -int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats) -{ - struct wid wid_list[5]; - u32 wid_cnt = 0, result; - - wid_list[wid_cnt].id = WID_LINKSPEED; - wid_list[wid_cnt].type = WID_CHAR; - wid_list[wid_cnt].size = sizeof(char); - wid_list[wid_cnt].val = (s8 *)&stats->link_speed; - wid_cnt++; - - wid_list[wid_cnt].id = WID_RSSI; - wid_list[wid_cnt].type = WID_CHAR; - wid_list[wid_cnt].size = sizeof(char); - wid_list[wid_cnt].val = (s8 *)&stats->rssi; - wid_cnt++; - - wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT; - wid_list[wid_cnt].type = WID_INT; - wid_list[wid_cnt].size = sizeof(u32); - wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt; - wid_cnt++; - - wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT; - wid_list[wid_cnt].type = WID_INT; - wid_list[wid_cnt].size = sizeof(u32); - wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt; - wid_cnt++; - - wid_list[wid_cnt].id = WID_FAILED_COUNT; - wid_list[wid_cnt].type = WID_INT; - wid_list[wid_cnt].size = sizeof(u32); - wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt; - wid_cnt++; - - result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list, - wid_cnt, - wilc_get_vif_idx(vif)); - - if (result) { - PRINT_ER(vif->ndev, "Failed to send scan parameters\n"); - return result; - } - - if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH && - stats->link_speed != DEFAULT_LINK_SPEED) { - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Enable TCP filter\n"); - wilc_enable_tcp_ack_filter(vif, true); - } else if (stats->link_speed != DEFAULT_LINK_SPEED) { - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Disable TCP filter %d\n", - stats->link_speed); - wilc_enable_tcp_ack_filter(vif, false); - } - - return result; -} - -static void handle_get_statistics(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - struct wilc_vif *vif = msg->vif; - struct rf_info *stats = (struct rf_info *)msg->body.data; - - wilc_get_statistics(vif, stats); - kfree(msg); -} - -static void wilc_hif_pack_sta_param(struct wilc_vif *vif, u8 *cur_byte, - const u8 *mac, - struct station_parameters *params) -{ - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Packing STA params\n"); - ether_addr_copy(cur_byte, mac); - cur_byte += ETH_ALEN; - - put_unaligned_le16(params->aid, cur_byte); - cur_byte += 2; - - *cur_byte++ = params->supported_rates_len; - if (params->supported_rates_len > 0) - memcpy(cur_byte, params->supported_rates, - params->supported_rates_len); - cur_byte += params->supported_rates_len; - - if (params->ht_capa) { - *cur_byte++ = true; - memcpy(cur_byte, ¶ms->ht_capa, - sizeof(struct ieee80211_ht_cap)); - } else { - *cur_byte++ = false; - } - cur_byte += sizeof(struct ieee80211_ht_cap); - - put_unaligned_le16(params->sta_flags_mask, cur_byte); - cur_byte += 2; - put_unaligned_le16(params->sta_flags_set, cur_byte); -} - -static int handle_remain_on_chan(struct wilc_vif *vif, - struct wilc_remain_ch *hif_remain_ch) -{ - int result; - u8 remain_on_chan_flag; - struct wid wid; - struct host_if_drv *hif_drv = vif->hif_drv; - struct host_if_drv *hif_drv_p2p = get_drv_hndl_by_ifc(vif->wilc, - WILC_P2P_IFC); - struct host_if_drv *hif_drv_wlan = get_drv_hndl_by_ifc(vif->wilc, - WILC_WLAN_IFC); - - if (!hif_drv) { - PRINT_ER(vif->ndev, "Driver is null\n"); - return -EFAULT; - } - - if (hif_drv_p2p != NULL) { - if (hif_drv_p2p->hif_state == HOST_IF_SCANNING) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "IFC busy scanning P2P_IFC state %d\n", - hif_drv_p2p->hif_state); - return -EBUSY; - } else if ((hif_drv_p2p->hif_state != HOST_IF_IDLE) && - (hif_drv_p2p->hif_state != HOST_IF_CONNECTED)) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "IFC busy connecting. P2P_IFC state %d\n", - hif_drv_p2p->hif_state); - return -EBUSY; - } - } - if (hif_drv_wlan != NULL) { - if (hif_drv_wlan->hif_state == HOST_IF_SCANNING) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "IFC busy scanning. WLAN_IFC state %d\n", - hif_drv_wlan->hif_state); - return -EBUSY; - } else if ((hif_drv_wlan->hif_state != HOST_IF_IDLE) && - (hif_drv_wlan->hif_state != HOST_IF_CONNECTED)) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "IFC busy connecting. WLAN_IFC %d\n", - hif_drv_wlan->hif_state); - return -EBUSY; - } - } - - if (vif->connecting) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Don't do scan in (CONNECTING) state\n"); - return -EBUSY; - } -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - if (vif->obtaining_ip) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Don't obss scan until IP adresss is obtained\n"); - return -EBUSY; - } -#endif - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Setting channel [%d] duration[%d] [%llu]\n", - hif_remain_ch->ch, hif_remain_ch->duration, - hif_remain_ch->cookie); - remain_on_chan_flag = true; - wid.id = WID_REMAIN_ON_CHAN; - wid.type = WID_STR; - wid.size = 2; - wid.val = kmalloc(wid.size, GFP_KERNEL); - if (!wid.val) - return -ENOMEM; - - wid.val[0] = remain_on_chan_flag; - wid.val[1] = (s8)hif_remain_ch->ch; - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - kfree(wid.val); - if (result) { - PRINT_ER(vif->ndev, "Failed to set remain on channel\n"); - return -EBUSY; - } - - hif_drv->remain_on_ch.arg = hif_remain_ch->arg; - hif_drv->remain_on_ch.expired = hif_remain_ch->expired; - hif_drv->remain_on_ch.ch = hif_remain_ch->ch; - hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie; - hif_drv->hif_state = HOST_IF_P2P_LISTEN; - - hif_drv->remain_on_ch_timer_vif = vif; - - return result; -} - -static void handle_listen_state_expired(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - struct wilc_vif *vif = msg->vif; - struct wilc_remain_ch *hif_remain_ch = &msg->body.remain_on_ch; - u8 remain_on_chan_flag; - struct wid wid; - int result; - struct host_if_drv *hif_drv = vif->hif_drv; - u8 null_bssid[6] = {0}; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "CANCEL REMAIN ON CHAN\n"); - - if (hif_drv->hif_state == HOST_IF_P2P_LISTEN) { - remain_on_chan_flag = false; - wid.id = WID_REMAIN_ON_CHAN; - wid.type = WID_STR; - wid.size = 2; - wid.val = kmalloc(wid.size, GFP_KERNEL); - - if (!wid.val) { - PRINT_ER(vif->ndev, "Failed to allocate memory\n"); - goto free_msg; - } - - wid.val[0] = remain_on_chan_flag; - wid.val[1] = WILC_FALSE_FRMWR_CHANNEL; - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - kfree(wid.val); - if (result != 0) { - PRINT_ER(vif->ndev, "Failed to set remain channel\n"); - goto free_msg; - } - - if (hif_drv->remain_on_ch.expired) - hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg, - hif_remain_ch->cookie); - - if (memcmp(hif_drv->assoc_bssid, null_bssid, ETH_ALEN) == 0) - hif_drv->hif_state = HOST_IF_IDLE; - else - hif_drv->hif_state = HOST_IF_CONNECTED; - } else { - PRINT_D(vif->ndev, GENERIC_DBG, "Not in listen state\n"); - } - -free_msg: - kfree(msg); -} - -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE -static void listen_timer_cb(struct timer_list *t) -#else -static void listen_timer_cb(unsigned long arg) -#endif -{ -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE - struct host_if_drv *hif_drv = from_timer(hif_drv, t, - remain_on_ch_timer); -#else - struct host_if_drv *hif_drv = (struct host_if_drv *)arg; -#endif - struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif; - int result; - struct host_if_msg *msg; - - del_timer(&vif->hif_drv->remain_on_ch_timer); - - msg = wilc_alloc_work(vif, handle_listen_state_expired, false); - if (IS_ERR(msg)) - return; - - msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie; - - result = wilc_enqueue_work(msg); - if (result) { - PRINT_ER(vif->ndev, "wilc_mq_send fail\n"); - kfree(msg); - } -} - -static void handle_set_mcast_filter(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - struct wilc_vif *vif = msg->vif; - struct wilc_set_multicast *set_mc = &msg->body.mc_info; - int result; - struct wid wid; - u8 *cur_byte; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Setup Multicast Filter\n"); - - wid.id = WID_SETUP_MULTICAST_FILTER; - wid.type = WID_BIN; - wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN); - wid.val = kmalloc(wid.size, GFP_KERNEL); - if (!wid.val) - goto error; - - cur_byte = wid.val; - put_unaligned_le32(set_mc->enabled, cur_byte); - cur_byte += 4; - - put_unaligned_le32(set_mc->cnt, cur_byte); - cur_byte += 4; - - if (set_mc->cnt > 0 && set_mc->mc_list) - memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to send setup multicast\n"); - -error: - kfree(set_mc->mc_list); - kfree(wid.val); - kfree(msg); -} - -void wilc_set_wowlan_trigger(struct wilc_vif *vif, u8 wowlan_trigger) -{ - int ret; - struct wid wid; - - wid.id = WID_WOWLAN_TRIGGER; - wid.type = WID_CHAR; - wid.val = &wowlan_trigger; - wid.size = sizeof(s8); - - ret = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - - if (ret) - PRINT_ER(vif->ndev, - "Failed to send wowlan trigger config packet\n"); -} - -static void handle_scan_timer(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - int ret; - - PRINT_INFO(msg->vif->ndev, HOSTINF_DBG, "handling scan timer\n"); - ret = handle_scan_done(msg->vif, SCAN_EVENT_ABORTED); - if (ret) - PRINT_ER(msg->vif->ndev, "Failed to handle scan done\n"); - kfree(msg); -} - -static void handle_scan_complete(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - - del_timer(&msg->vif->hif_drv->scan_timer); - PRINT_INFO(msg->vif->ndev, HOSTINF_DBG, "scan completed\n"); - - handle_scan_done(msg->vif, SCAN_EVENT_DONE); - - kfree(msg); -} - -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE -static void timer_scan_cb(struct timer_list *t) -#else -static void timer_scan_cb(unsigned long arg) -#endif -{ -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE - struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer); -#else - struct host_if_drv *hif_drv = (struct host_if_drv *)arg; -#endif - struct wilc_vif *vif = hif_drv->scan_timer_vif; - struct host_if_msg *msg; - int result; - - msg = wilc_alloc_work(vif, handle_scan_timer, false); - if (IS_ERR(msg)) - return; - - result = wilc_enqueue_work(msg); - if (result) - kfree(msg); -} - -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE -static void timer_connect_cb(struct timer_list *t) -#else -static void timer_connect_cb(unsigned long arg) -#endif -{ -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE - struct host_if_drv *hif_drv = from_timer(hif_drv, t, connect_timer); -#else - struct host_if_drv *hif_drv = (struct host_if_drv *)arg; -#endif - struct wilc_vif *vif = hif_drv->connect_timer_vif; - struct host_if_msg *msg; - int result; - - msg = wilc_alloc_work(vif, handle_connect_timeout, false); - if (IS_ERR(msg)) - return; - - result = wilc_enqueue_work(msg); - if (result) - kfree(msg); -} - -signed int wilc_send_buffered_eap(struct wilc_vif *vif, - void (*deliver_to_stack)(struct wilc_vif *, - u8 *, u32, u32, u8), - void (*eap_buf_param)(void *), u8 *buff, - unsigned int size, unsigned int pkt_offset, - void *user_arg) -{ - int result; - struct host_if_msg *msg; - - if (!vif || !deliver_to_stack || !eap_buf_param) - return -EFAULT; - - msg = wilc_alloc_work(vif, handle_send_buffered_eap, false); - if (IS_ERR(msg)) - return PTR_ERR(msg); - msg->body.send_buff_eap.deliver_to_stack = deliver_to_stack; - msg->body.send_buff_eap.eap_buf_param = eap_buf_param; - msg->body.send_buff_eap.size = size; - msg->body.send_buff_eap.pkt_offset = pkt_offset; - msg->body.send_buff_eap.buff = kmalloc(size + pkt_offset, - GFP_ATOMIC); - memcpy(msg->body.send_buff_eap.buff, buff, size + pkt_offset); - msg->body.send_buff_eap.user_arg = user_arg; - - result = wilc_enqueue_work(msg); - if (result) { - PRINT_ER(vif->ndev, "enqueue work failed\n"); - kfree(msg->body.send_buff_eap.buff); - kfree(msg); - } - return result; -} - -int wilc_remove_wep_key(struct wilc_vif *vif, u8 index) -{ - struct wid wid; - int result; - - wid.id = WID_REMOVE_WEP_KEY; - wid.type = WID_STR; - wid.size = sizeof(char); - wid.val = &index; - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, - "Failed to send remove wep key config packet\n"); - return result; -} - -int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index) -{ - struct wid wid; - int result; - - wid.id = WID_KEY_ID; - wid.type = WID_CHAR; - wid.size = sizeof(char); - wid.val = &index; - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, - "Failed to send wep default key config packet\n"); - - return result; -} - -int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, - u8 index) -{ - struct wid wid; - int result; - struct wilc_wep_key *wep_key; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Handling WEP key\n"); - wid.id = WID_ADD_WEP_KEY; - wid.type = WID_STR; - wid.size = sizeof(*wep_key) + len; - wep_key = kzalloc(wid.size, GFP_KERNEL); - if (!wep_key) { - PRINT_ER(vif->ndev, "No buffer to send Key\n"); - return -ENOMEM; - } - wid.val = (u8 *)wep_key; - - wep_key->index = index; - wep_key->key_len = len; - memcpy(wep_key->key, key, len); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - netdev_err(vif->ndev, - "Failed to add wep key config packet\n"); - - kfree(wep_key); - return result; -} - -int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len, - u8 index, u8 mode, enum authtype auth_type) -{ - struct wid wid_list[3]; - int result; - struct wilc_wep_key *wep_key; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Handling WEP key index: %d\n", - index); - wid_list[0].id = WID_11I_MODE; - wid_list[0].type = WID_CHAR; - wid_list[0].size = sizeof(char); - wid_list[0].val = &mode; - - wid_list[1].id = WID_AUTH_TYPE; - wid_list[1].type = WID_CHAR; - wid_list[1].size = sizeof(char); - wid_list[1].val = (s8 *)&auth_type; - - wid_list[2].id = WID_WEP_KEY_VALUE; - wid_list[2].type = WID_STR; - wid_list[2].size = sizeof(*wep_key) + len; - wep_key = kzalloc(wid_list[2].size, GFP_KERNEL); - if (!wep_key) { - PRINT_ER(vif->ndev, "No buffer to send Key\n"); - return -ENOMEM; - } - - wid_list[2].val = (u8 *)wep_key; - - wep_key->index = index; - wep_key->key_len = len; - memcpy(wep_key->key, key, len); - result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, - ARRAY_SIZE(wid_list), - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, - "Failed to add wep ap key config packet\n"); - - kfree(wep_key); - return result; -} - -int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, - const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, - u8 mode, u8 cipher_mode, u8 index) -{ - int result = 0; - u8 t_key_len = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN; - - if (mode == WILC_AP_MODE) { - struct wid wid_list[2]; - struct wilc_ap_wpa_ptk *key_buf; - - wid_list[0].id = WID_11I_MODE; - wid_list[0].type = WID_CHAR; - wid_list[0].size = sizeof(char); - wid_list[0].val = (s8 *)&cipher_mode; - - key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL); - if (!key_buf) { - PRINT_ER(vif->ndev, - "NO buffer to keep Key buffer - AP\n"); - return -ENOMEM; - } - ether_addr_copy(key_buf->mac_addr, mac_addr); - key_buf->index = index; - key_buf->key_len = t_key_len; - memcpy(&key_buf->key[0], ptk, ptk_key_len); - - if (rx_mic) - memcpy(&key_buf->key[ptk_key_len], rx_mic, - WILC_RX_MIC_KEY_LEN); - - if (tx_mic) - memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN], - tx_mic, WILC_TX_MIC_KEY_LEN); - - wid_list[1].id = WID_ADD_PTK; - wid_list[1].type = WID_STR; - wid_list[1].size = sizeof(*key_buf) + t_key_len; - wid_list[1].val = (u8 *)key_buf; - result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, - ARRAY_SIZE(wid_list), - wilc_get_vif_idx(vif)); - kfree(key_buf); - } else if (mode == WILC_STATION_MODE) { - struct wid wid; - struct wilc_sta_wpa_ptk *key_buf; - - key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL); - if (!key_buf) { - PRINT_ER(vif->ndev, - "No buffer to keep Key buffer - Station\n"); - return -ENOMEM; - } - - ether_addr_copy(key_buf->mac_addr, mac_addr); - key_buf->key_len = t_key_len; - memcpy(&key_buf->key[0], ptk, ptk_key_len); - - if (rx_mic) - memcpy(&key_buf->key[ptk_key_len], rx_mic, - WILC_RX_MIC_KEY_LEN); - - if (tx_mic) - memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN], - tx_mic, WILC_TX_MIC_KEY_LEN); - - wid.id = WID_ADD_PTK; - wid.type = WID_STR; - wid.size = sizeof(*key_buf) + t_key_len; - wid.val = (s8 *)key_buf; - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - kfree(key_buf); - } - - return result; -} - -int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, - u8 index, u32 key_rsc_len, const u8 *key_rsc, - const u8 *rx_mic, const u8 *tx_mic, u8 mode, - u8 cipher_mode) -{ - int result = 0; - struct wilc_gtk_key *gtk_key; - int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN; - - gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL); - if (!gtk_key) { - PRINT_ER(vif->ndev, "No buffer to send GTK Key\n"); - return -ENOMEM; - } - - /* fill bssid value only in station mode */ - if (mode == WILC_STATION_MODE && - vif->hif_drv->hif_state == HOST_IF_CONNECTED) - memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN); - - if (key_rsc) - memcpy(gtk_key->rsc, key_rsc, 8); - gtk_key->index = index; - gtk_key->key_len = t_key_len; - memcpy(>k_key->key[0], rx_gtk, gtk_key_len); - - if (rx_mic) - memcpy(>k_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN); - - if (tx_mic) - memcpy(>k_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN], - tx_mic, WILC_TX_MIC_KEY_LEN); - - if (mode == WILC_AP_MODE) { - struct wid wid_list[2]; - - wid_list[0].id = WID_11I_MODE; - wid_list[0].type = WID_CHAR; - wid_list[0].size = sizeof(char); - wid_list[0].val = (s8 *)&cipher_mode; - - wid_list[1].id = WID_ADD_RX_GTK; - wid_list[1].type = WID_STR; - wid_list[1].size = sizeof(*gtk_key) + t_key_len; - wid_list[1].val = (u8 *)gtk_key; - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, - ARRAY_SIZE(wid_list), - wilc_get_vif_idx(vif)); - kfree(gtk_key); - } else if (mode == WILC_STATION_MODE) { - struct wid wid; - - wid.id = WID_ADD_RX_GTK; - wid.type = WID_STR; - wid.size = sizeof(*gtk_key) + t_key_len; - wid.val = (u8 *)gtk_key; - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - kfree(gtk_key); - } - - return result; -} - -int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid) -{ - struct wid wid; - - wid.id = WID_PMKID_INFO; - wid.type = WID_STR; - wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1; - wid.val = (u8 *)pmkid; - - return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); -} - -int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr) -{ - int result; - struct wid wid; - - wid.id = WID_MAC_ADDR; - wid.type = WID_STR; - wid.size = ETH_ALEN; - wid.val = mac_addr; - - result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - netdev_err(vif->ndev, "Failed to get mac address\n"); - - return result; -} - -int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr) -{ - struct wid wid; - int result; - - wid.id = WID_MAC_ADDR; - wid.type = WID_STR; - wid.size = ETH_ALEN; - wid.val = mac_addr; - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to set mac address\n"); - - return result; -} - -int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, - size_t ies_len) -{ - int result; - struct host_if_drv *hif_drv = vif->hif_drv; - struct wilc_conn_info *conn_info = &hif_drv->conn_info; - - if (bssid) - ether_addr_copy(conn_info->bssid, bssid); - - if (ies) { - conn_info->req_ies_len = ies_len; - conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL); - if (!conn_info->req_ies) - return -ENOMEM; - } - - result = wilc_send_connect_wid(vif); - if (result) { - PRINT_ER(vif->ndev, "Failed to send connect wid\n"); - goto free_ies; - } - -#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE - hif_drv->connect_timer.data = (unsigned long)hif_drv; -#endif - hif_drv->connect_timer_vif = vif; - mod_timer(&hif_drv->connect_timer, - jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS)); - - return 0; - -free_ies: - kfree(conn_info->req_ies); - - return result; -} - -int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel) -{ - struct wid wid; - int result; - - wid.id = WID_CURRENT_CHANNEL; - wid.type = WID_CHAR; - wid.size = sizeof(char); - wid.val = &channel; - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to set channel\n"); - - return result; -} - -int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode, - u8 ifc_id) -{ - struct wid wid; - struct host_if_drv *hif_drv = vif->hif_drv; - int result; - struct wilc_drv_handler drv; - - if (!hif_drv) - return -EFAULT; - - wid.id = WID_SET_DRV_HANDLER; - wid.type = WID_STR; - wid.size = sizeof(drv); - wid.val = (u8 *)&drv; - - drv.handler = cpu_to_le32(index); - drv.mode = (ifc_id | (mode << 1)); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - hif_drv->driver_handler_id); - if (result) - PRINT_ER(vif->ndev, "Failed to set driver handler\n"); - - return result; -} - -int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode) -{ - struct wid wid; - struct wilc_op_mode op_mode; - int result; - - wid.id = WID_SET_OPERATION_MODE; - wid.type = WID_INT; - wid.size = sizeof(op_mode); - wid.val = (u8 *)&op_mode; - - op_mode.mode = cpu_to_le32(mode); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to set operation mode\n"); - - return result; -} - -s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val) -{ - struct wid wid; - s32 result; - - wid.id = WID_SET_STA_MAC_INACTIVE_TIME; - wid.type = WID_STR; - wid.size = ETH_ALEN; - wid.val = kzalloc(wid.size, GFP_KERNEL); - if (!wid.val) { - PRINT_ER(vif->ndev, "Failed to allocate buffer\n"); - return -ENOMEM; - } - - ether_addr_copy(wid.val, mac); - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - kfree(wid.val); - if (result) { - PRINT_ER(vif->ndev, "Failed to set inactive mac\n"); - return result; - } - - wid.id = WID_GET_INACTIVE_TIME; - wid.type = WID_INT; - wid.val = (s8 *)out_val; - wid.size = sizeof(u32); - result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to get inactive time\n"); - - PRINT_INFO(vif->ndev, CFG80211_DBG, "Getting inactive time : %d\n", - *out_val); - - return result; -} - -int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level) -{ - struct wid wid; - int result; - - if (!rssi_level) { - PRINT_ER(vif->ndev, "RSS pointer value is null\n"); - return -EFAULT; - } - - wid.id = WID_RSSI; - wid.type = WID_CHAR; - wid.size = sizeof(char); - wid.val = rssi_level; - result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - netdev_err(vif->ndev, "Failed to get RSSI value\n"); - - return result; -} - -int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats) -{ - int result; - struct host_if_msg *msg; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, " getting async statistics\n"); - msg = wilc_alloc_work(vif, handle_get_statistics, false); - if (IS_ERR(msg)) - return PTR_ERR(msg); - - msg->body.data = (char *)stats; - - result = wilc_enqueue_work(msg); - if (result) { - PRINT_ER(vif->ndev, "enqueue work failed\n"); - kfree(msg); - return result; - } - - return result; -} - -int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param) -{ - struct wid wid_list[4]; - int i = 0; - - if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) { - wid_list[i].id = WID_SHORT_RETRY_LIMIT; - wid_list[i].val = (s8 *)¶m->short_retry_limit; - wid_list[i].type = WID_SHORT; - wid_list[i].size = sizeof(u16); - i++; - } - if (param->flag & WILC_CFG_PARAM_RETRY_LONG) { - wid_list[i].id = WID_LONG_RETRY_LIMIT; - wid_list[i].val = (s8 *)¶m->long_retry_limit; - wid_list[i].type = WID_SHORT; - wid_list[i].size = sizeof(u16); - i++; - } - if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) { - wid_list[i].id = WID_FRAG_THRESHOLD; - wid_list[i].val = (s8 *)¶m->frag_threshold; - wid_list[i].type = WID_SHORT; - wid_list[i].size = sizeof(u16); - i++; - } - if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) { - wid_list[i].id = WID_RTS_THRESHOLD; - wid_list[i].val = (s8 *)¶m->rts_threshold; - wid_list[i].type = WID_SHORT; - wid_list[i].size = sizeof(u16); - i++; - } - - return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, - i, wilc_get_vif_idx(vif)); -} - -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE -static void get_periodic_rssi(struct timer_list *t) -#else -static void get_periodic_rssi(unsigned long arg) -#endif -{ -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE - struct wilc_vif *vif = from_timer(vif, t, periodic_rssi); -#else - struct wilc_vif *vif = (struct wilc_vif *)arg; -#endif - - if (!vif->hif_drv) { - PRINT_ER(vif->ndev, "hif driver is NULL\n"); - return; - } - - if (vif->hif_drv->hif_state == HOST_IF_CONNECTED) - wilc_get_stats_async(vif, &vif->periodic_stats); - - mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000)); -} - -int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler) -{ - struct host_if_drv *hif_drv; - struct wilc_vif *vif = netdev_priv(dev); - struct wilc *wilc = vif->wilc; - int i; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Initializing host interface for client %d\n", - wilc->clients_count + 1); - - hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL); - if (!hif_drv) { - PRINT_ER(dev, "hif driver is NULL\n"); - return -ENOMEM; - } - *hif_drv_handler = hif_drv; - for (i = 0; i < wilc->vif_num; i++) - if (dev == wilc->vif[i]->ndev) { - wilc->vif[i]->hif_drv = hif_drv; - hif_drv->driver_handler_id = i + 1; - break; - } - -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - vif->obtaining_ip = false; -#endif - - if (wilc->clients_count == 0) - mutex_init(&wilc->deinit_lock); - - #if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE - timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0); - #else - setup_timer(&vif->periodic_rssi, get_periodic_rssi, - (unsigned long)vif); - #endif - mod_timer(&vif->periodic_rssi, - jiffies + msecs_to_jiffies(5000)); - -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE - timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0); - timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0); - timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0); -#else - setup_timer(&hif_drv->scan_timer, timer_scan_cb, 0); - setup_timer(&hif_drv->connect_timer, timer_connect_cb, 0); - setup_timer(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0); -#endif - - hif_drv->hif_state = HOST_IF_IDLE; - - hif_drv->p2p_timeout = 0; - - wilc->clients_count++; - - return 0; -} - -int wilc_deinit(struct wilc_vif *vif) -{ - int result = 0; - struct host_if_drv *hif_drv = vif->hif_drv; - - if (!hif_drv) { - PRINT_ER(vif->ndev, "hif driver is NULL\n"); - return -EFAULT; - } - - mutex_lock(&vif->wilc->deinit_lock); - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "De-initializing host interface for client %d\n", - vif->wilc->clients_count); - - del_timer_sync(&hif_drv->scan_timer); - del_timer_sync(&hif_drv->connect_timer); - del_timer_sync(&vif->periodic_rssi); - del_timer_sync(&hif_drv->remain_on_ch_timer); - - if (hif_drv->usr_scan_req.scan_result) { - hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL, - hif_drv->usr_scan_req.arg); - hif_drv->usr_scan_req.scan_result = NULL; - } - - hif_drv->hif_state = HOST_IF_IDLE; - - kfree(hif_drv); - vif->hif_drv = NULL; - - vif->wilc->clients_count--; - mutex_unlock(&vif->wilc->deinit_lock); - return result; -} - -void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) -{ - int result; - struct host_if_msg *msg; - int id; - struct host_if_drv *hif_drv; - struct wilc_vif *vif; - - id = get_unaligned_le32(&buffer[length - 4]); - vif = wilc_get_vif_from_idx(wilc, id); - if (!vif) - return; - hif_drv = vif->hif_drv; - - if (!hif_drv) { - PRINT_ER(vif->ndev, "driver not init[%p]\n", hif_drv); - return; - } - - msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false); - if (IS_ERR(msg)) - return; - - msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1; - msg->body.net_info.rssi = buffer[8]; - msg->body.net_info.mgmt = kmemdup(&buffer[9], - msg->body.net_info.frame_len, - GFP_KERNEL); - if (!msg->body.net_info.mgmt) { - kfree(msg); - return; - } - - result = wilc_enqueue_work(msg); - if (result) { - PRINT_ER(vif->ndev, "message parameters (%d)\n", result); - kfree(msg->body.net_info.mgmt); - kfree(msg); - } -} - -void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) -{ - int result; - struct host_if_msg *msg; - int id; - struct host_if_drv *hif_drv; - struct wilc_vif *vif; - - mutex_lock(&wilc->deinit_lock); - - id = get_unaligned_le32(&buffer[length - 4]); - vif = wilc_get_vif_from_idx(wilc, id); - if (!vif) { - mutex_unlock(&wilc->deinit_lock); - return; - } - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "General asynchronous info packet received\n"); - - hif_drv = vif->hif_drv; - - if (!hif_drv) { - PRINT_ER(vif->ndev, "hif driver is NULL\n"); - mutex_unlock(&wilc->deinit_lock); - return; - } - - if (!hif_drv->conn_info.conn_result) { - PRINT_ER(vif->ndev, "there is no current Connect Request\n"); - mutex_unlock(&wilc->deinit_lock); - return; - } - - msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false); - if (IS_ERR(msg)) { - mutex_unlock(&wilc->deinit_lock); - return; - } - - msg->body.mac_info.status = buffer[7]; - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Received MAC status= %d Reason= %d Info = %d\n", - buffer[7], buffer[8], buffer[9]); - result = wilc_enqueue_work(msg); - if (result) { - PRINT_ER(vif->ndev, "enqueue work failed\n"); - kfree(msg); - } - - mutex_unlock(&wilc->deinit_lock); -} - -void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) -{ - int result; - int id; - struct host_if_drv *hif_drv; - struct wilc_vif *vif; - - id = get_unaligned_le32(&buffer[length - 4]); - vif = wilc_get_vif_from_idx(wilc, id); - if (!vif) - return; - hif_drv = vif->hif_drv; - PRINT_INFO(vif->ndev, GENERIC_DBG, "Scan notification received\n"); - - if (!hif_drv) { - PRINT_ER(vif->ndev, "hif driver is NULL\n"); - return; - } - - if (hif_drv->usr_scan_req.scan_result) { - struct host_if_msg *msg; - - msg = wilc_alloc_work(vif, handle_scan_complete, false); - if (IS_ERR(msg)) - return; - - result = wilc_enqueue_work(msg); - if (result) { - PRINT_ER(vif->ndev, "enqueue work failed\n"); - kfree(msg); - } - } -} - -int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, - u32 duration, u16 chan, - void (*expired)(void *, u64), void *user_arg) -{ - struct wilc_remain_ch roc; - int result; - - PRINT_INFO(vif->ndev, CFG80211_DBG, "%s called\n", __func__); - roc.ch = chan; - roc.expired = expired; - roc.arg = user_arg; - roc.duration = duration; - roc.cookie = cookie; - result = handle_remain_on_chan(vif, &roc); - if (result) - PRINT_ER(vif->ndev, "%s: failed to set remain on channel\n", - __func__); - - return result; -} - -int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie) -{ - int result; - struct host_if_msg *msg; - struct host_if_drv *hif_drv = vif->hif_drv; - - if (!hif_drv) { - PRINT_ER(vif->ndev, "hif driver is NULL\n"); - return -EFAULT; - } - - del_timer(&hif_drv->remain_on_ch_timer); - - msg = wilc_alloc_work(vif, handle_listen_state_expired, false); - if (IS_ERR(msg)) - return PTR_ERR(msg); - - msg->body.remain_on_ch.cookie = cookie; - - result = wilc_enqueue_work(msg); - if (result) { - PRINT_ER(vif->ndev, "enqueue work failed\n"); - kfree(msg); - } - - return result; -} - -void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg) -{ - struct wid wid; - int result; - struct wilc_reg_frame reg_frame; - - wid.id = WID_REGISTER_FRAME; - wid.type = WID_STR; - wid.size = sizeof(reg_frame); - wid.val = (u8 *)®_frame; - - memset(®_frame, 0x0, sizeof(reg_frame)); - reg_frame.reg = reg; - - switch (frame_type) { - case IEEE80211_STYPE_ACTION: - PRINT_INFO(vif->ndev, HOSTINF_DBG, "ACTION\n"); - reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX; - break; - - case IEEE80211_STYPE_PROBE_REQ: - PRINT_INFO(vif->ndev, HOSTINF_DBG, "PROBE REQ\n"); - reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX; - break; - - default: - PRINT_INFO(vif->ndev, HOSTINF_DBG, "Not valid frame type\n"); - break; - } - reg_frame.frame_type = cpu_to_le16(frame_type); - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to frame register\n"); -} - -int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, - struct cfg80211_beacon_data *params) -{ - struct wid wid; - int result; - u8 *cur_byte; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Setting adding beacon\n"); - - wid.id = WID_ADD_BEACON; - wid.type = WID_BIN; - wid.size = params->head_len + params->tail_len + 16; - wid.val = kzalloc(wid.size, GFP_KERNEL); - if (!wid.val) { - PRINT_ER(vif->ndev, "Failed to allocate buffer\n"); - return -ENOMEM; - } - - cur_byte = wid.val; - put_unaligned_le32(interval, cur_byte); - cur_byte += 4; - put_unaligned_le32(dtim_period, cur_byte); - cur_byte += 4; - put_unaligned_le32(params->head_len, cur_byte); - cur_byte += 4; - - if (params->head_len > 0) - memcpy(cur_byte, params->head, params->head_len); - cur_byte += params->head_len; - - put_unaligned_le32(params->tail_len, cur_byte); - cur_byte += 4; - - if (params->tail_len > 0) - memcpy(cur_byte, params->tail, params->tail_len); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to send add beacon\n"); - - kfree(wid.val); - - return result; -} - -int wilc_del_beacon(struct wilc_vif *vif) -{ - int result; - struct wid wid; - u8 del_beacon = 0; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Setting deleting beacon message queue params\n"); - - wid.id = WID_DEL_BEACON; - wid.type = WID_CHAR; - wid.size = sizeof(char); - wid.val = &del_beacon; - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to send delete beacon\n"); - - return result; -} - -int wilc_add_station(struct wilc_vif *vif, const u8 *mac, - struct station_parameters *params) -{ - struct wid wid; - int result; - u8 *cur_byte; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Setting adding station message queue params\n"); - - wid.id = WID_ADD_STA; - wid.type = WID_BIN; - wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len; - wid.val = kmalloc(wid.size, GFP_KERNEL); - if (!wid.val) - return -ENOMEM; - - cur_byte = wid.val; - wilc_hif_pack_sta_param(vif, cur_byte, mac, params); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result != 0) - PRINT_ER(vif->ndev, "Failed to send add station\n"); - - kfree(wid.val); - - return result; -} - -int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr) -{ - struct wid wid; - int result; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Setting deleting station message queue params\n"); - - wid.id = WID_REMOVE_STA; - wid.type = WID_BIN; - wid.size = ETH_ALEN; - wid.val = kzalloc(wid.size, GFP_KERNEL); - if (!wid.val) { - PRINT_ER(vif->ndev, "Failed to allocate buffer\n"); - return -ENOMEM; - } - - if (!mac_addr) - eth_broadcast_addr(wid.val); - else - ether_addr_copy(wid.val, mac_addr); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to del station\n"); - - kfree(wid.val); - - return result; -} - -int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]) -{ - struct wid wid; - int result; - int i; - u8 assoc_sta = 0; - struct wilc_del_all_sta del_sta; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Setting deauthenticating station message queue params\n"); - memset(&del_sta, 0x0, sizeof(del_sta)); - for (i = 0; i < WILC_MAX_NUM_STA; i++) { - if (!is_zero_ether_addr(mac_addr[i])) { - PRINT_INFO(vif->ndev, - CFG80211_DBG, "BSSID = %x%x%x%x%x%x\n", - mac_addr[i][0], mac_addr[i][1], - mac_addr[i][2], mac_addr[i][3], - mac_addr[i][4], mac_addr[i][5]); - assoc_sta++; - ether_addr_copy(del_sta.mac[i], mac_addr[i]); - } - } - if (!assoc_sta) { - PRINT_INFO(vif->ndev, CFG80211_DBG, "NO ASSOCIATED STAS\n"); - return 0; - } - del_sta.assoc_sta = assoc_sta; - - wid.id = WID_DEL_ALL_STA; - wid.type = WID_STR; - wid.size = (assoc_sta * ETH_ALEN) + 1; - wid.val = (u8 *)&del_sta; - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to send delete all station\n"); - - return result; -} - -int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, - struct station_parameters *params) -{ - struct wid wid; - int result; - u8 *cur_byte; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Setting editing station message queue params\n"); - - wid.id = WID_EDIT_STA; - wid.type = WID_BIN; - wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len; - wid.val = kmalloc(wid.size, GFP_KERNEL); - if (!wid.val) - return -ENOMEM; - - cur_byte = wid.val; - wilc_hif_pack_sta_param(vif, cur_byte, mac, params); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to send edit station\n"); - - kfree(wid.val); - return result; -} - -int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout) -{ - struct wid wid; - int result; - s8 power_mode; - - if (wilc_wlan_get_num_conn_ifcs(vif->wilc) == 2 && enabled) - return 0; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, "\n\n>> Setting PS to %d <<\n\n", - enabled); - if (enabled) - power_mode = WILC_FW_MIN_FAST_PS; - else - power_mode = WILC_FW_NO_POWERSAVE; - - wid.id = WID_POWER_MANAGEMENT; - wid.val = &power_mode; - wid.size = sizeof(char); - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (result) - PRINT_ER(vif->ndev, "Failed to send power management\n"); -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - else - store_power_save_current_state(vif, power_mode); -#endif - - return result; -} - -int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, - u8 *mc_list) -{ - int result; - struct host_if_msg *msg; - - PRINT_INFO(vif->ndev, HOSTINF_DBG, - "Setting Multicast Filter params\n"); - msg = wilc_alloc_work(vif, handle_set_mcast_filter, false); - if (IS_ERR(msg)) - return PTR_ERR(msg); - - msg->body.mc_info.enabled = enabled; - msg->body.mc_info.cnt = count; - msg->body.mc_info.mc_list = mc_list; - - result = wilc_enqueue_work(msg); - if (result) { - PRINT_ER(vif->ndev, "enqueue work failed\n"); - kfree(msg); - } - return result; -} - -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP -void handle_powersave_state_changes(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - struct wilc_vif *vif = msg->vif; - - PRINT_INFO(vif->ndev, GENERIC_DBG, "Recover PS = %d\n", - vif->pwrsave_current_state); - - /* Recover PS previous state */ - wilc_set_power_mgmt(vif, vif->pwrsave_current_state, 0); -} - -void wilc_powersave_state_changes(struct wilc_vif *vif) -{ - int result; - struct host_if_msg *msg; - - msg = wilc_alloc_work(vif, handle_powersave_state_changes, false); - if (IS_ERR(msg)) - return; - - result = wilc_enqueue_work(msg); - if (result) { - PRINT_ER(vif->ndev, "enqueue work failed\n"); - kfree(msg); - } -} -#endif - -int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power) -{ - struct wid wid; - - wid.id = WID_TX_POWER; - wid.type = WID_CHAR; - wid.val = &tx_power; - wid.size = sizeof(char); - - return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); -} - -int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power) -{ - struct wid wid; - - wid.id = WID_TX_POWER; - wid.type = WID_CHAR; - wid.val = tx_power; - wid.size = sizeof(char); - - return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); -} - -bool is_valid_gpio(struct wilc_vif *vif, u8 gpio) -{ - switch (vif->wilc->chip) { - case WILC_1000: - if (gpio == 0 || gpio == 1 || gpio == 4 || gpio == 6) - return true; - else - return false; - case WILC_3000: - if (gpio == 0 || gpio == 3 || gpio == 4 || - (gpio >= 17 && gpio <= 20)) - return true; - else - return false; - default: - return false; - } -} - -int wilc_set_antenna(struct wilc_vif *vif, u8 mode) -{ - struct wid wid; - int ret; - struct sysfs_attr_group *attr_syfs_p = &vif->attr_sysfs; - struct host_if_set_ant set_ant; - - set_ant.mode = mode; - - if (attr_syfs_p->ant_swtch_mode == ANT_SWTCH_INVALID_GPIO_CTRL) { - PRINT_ER(vif->ndev, "Ant switch GPIO mode is invalid.\n"); - PRINT_ER(vif->ndev, "Set it using /sys/wilc/ant_swtch_mode\n"); - return WILC_FAIL; - } - - if (is_valid_gpio(vif, attr_syfs_p->antenna1)) { - set_ant.antenna1 = attr_syfs_p->antenna1; - } else { - PRINT_ER(vif->ndev, "Invalid GPIO%d\n", attr_syfs_p->antenna1); - return WILC_FAIL; - } - - if (attr_syfs_p->ant_swtch_mode == ANT_SWTCH_DUAL_GPIO_CTRL) { - if ((attr_syfs_p->antenna2 != attr_syfs_p->antenna1) && - is_valid_gpio(vif, attr_syfs_p->antenna2)) { - set_ant.antenna2 = attr_syfs_p->antenna2; - } else { - PRINT_ER(vif->ndev, "Invalid GPIO %d\n", - attr_syfs_p->antenna2); - return WILC_FAIL; - } - } - - set_ant.gpio_mode = attr_syfs_p->ant_swtch_mode; - - wid.id = WID_ANTENNA_SELECTION; - wid.type = WID_BIN; - wid.val = (u8 *)&set_ant; - wid.size = sizeof(struct host_if_set_ant); - if (attr_syfs_p->ant_swtch_mode == ANT_SWTCH_SNGL_GPIO_CTRL) - PRINT_INFO(vif->ndev, CFG80211_DBG, - "set antenna %d on GPIO %d\n", set_ant.mode, - set_ant.antenna1); - else if (attr_syfs_p->ant_swtch_mode == ANT_SWTCH_DUAL_GPIO_CTRL) - PRINT_INFO(vif->ndev, CFG80211_DBG, - "set antenna %d on GPIOs %d and %d\n", - set_ant.mode, set_ant.antenna1, - set_ant.antenna2); - - ret = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1, - wilc_get_vif_idx(vif)); - if (ret) - PRINT_ER(vif->ndev, "Failed to set antenna mode\n"); - - return ret; -} diff --git a/drivers/net/wireless/mchp/host_interface.h b/drivers/net/wireless/mchp/host_interface.h deleted file mode 100644 index 92c1c179e1bd..000000000000 --- a/drivers/net/wireless/mchp/host_interface.h +++ /dev/null @@ -1,269 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. - * All rights reserved. - */ - -#ifndef HOST_INT_H -#define HOST_INT_H -#include -#include "wilc_wlan_if.h" - -enum { - WILC_IDLE_MODE = 0x0, - WILC_AP_MODE = 0x1, - WILC_STATION_MODE = 0x2, - WILC_GO_MODE = 0x3, - WILC_CLIENT_MODE = 0x4, - WILC_MONITOR_MODE = 0x5 -}; - -enum { - WILC_P2P_IFC = 0x00, - WILC_WLAN_IFC = 0x01, -}; - -#define IFC_0 "wlan0" -#define IFC_1 "p2p0" - -#define WILC_MAX_NUM_STA 9 -#define WILC_MAX_NUM_SCANNED_CH 14 -#define WILC_MAX_NUM_PROBED_SSID 10 - -#define WILC_TX_MIC_KEY_LEN 8 -#define WILC_RX_MIC_KEY_LEN 8 - -#define WILC_MAX_NUM_PMKIDS 16 -#define WILC_ADD_STA_LENGTH 40 -#define WILC_NUM_CONCURRENT_IFC 2 - -enum { - WILC_SET_CFG = 0, - WILC_GET_CFG -}; - -#define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256 -extern uint32_t cfg_packet_timeout; - -struct assoc_resp { - __le16 capab_info; - __le16 status_code; - __le16 aid; -} __packed; - -struct rf_info { - u8 link_speed; - s8 rssi; - u32 tx_cnt; - u32 rx_cnt; - u32 tx_fail_cnt; -}; - -enum host_if_state { - HOST_IF_IDLE = 0, - HOST_IF_SCANNING = 1, - HOST_IF_CONNECTING = 2, - HOST_IF_WAITING_CONN_RESP = 3, - HOST_IF_CONNECTED = 4, - HOST_IF_P2P_LISTEN = 5, - HOST_IF_FORCE_32BIT = 0xFFFFFFFF -}; - -struct wilc_pmkid { - u8 bssid[ETH_ALEN]; - u8 pmkid[WLAN_PMKID_LEN]; -} __packed; - -struct wilc_pmkid_attr { - u8 numpmkid; - struct wilc_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS]; -} __packed; - -struct cfg_param_attr { - u32 flag; - u16 short_retry_limit; - u16 long_retry_limit; - u16 frag_threshold; - u16 rts_threshold; -}; - -enum cfg_param { - WILC_CFG_PARAM_RETRY_SHORT = BIT(0), - WILC_CFG_PARAM_RETRY_LONG = BIT(1), - WILC_CFG_PARAM_FRAG_THRESHOLD = BIT(2), - WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3) -}; - -enum scan_event { - SCAN_EVENT_NETWORK_FOUND = 0, - SCAN_EVENT_DONE = 1, - SCAN_EVENT_ABORTED = 2, - SCAN_EVENT_FORCE_32BIT = 0xFFFFFFFF -}; - -enum conn_event { - EVENT_CONN_RESP = 0, - EVENT_DISCONN_NOTIF = 1, - EVENT_FORCE_32BIT = 0xFFFFFFFF -}; - -enum { - WILC_HIF_SDIO = 0, - WILC_HIF_SPI = BIT(0), - WILC_HIF_SDIO_GPIO_IRQ = BIT(1) -}; - -enum { - WILC_MAC_STATUS_INIT = -1, - WILC_MAC_STATUS_DISCONNECTED = 0, - WILC_MAC_STATUS_CONNECTED = 1 -}; - -struct wilc_rcvd_net_info { - s8 rssi; - u8 ch; - u16 frame_len; - struct ieee80211_mgmt *mgmt; -}; - -typedef void (*wilc_remain_on_chan_ready)(void *); - -struct wilc_user_scan_req { - void (*scan_result)(enum scan_event evt, - struct wilc_rcvd_net_info *info, void *priv); - void *arg; - u32 ch_cnt; -}; - -struct wilc_conn_info { - u8 bssid[ETH_ALEN]; - u8 security; - enum authtype auth_type; - u8 ch; - u8 *req_ies; - size_t req_ies_len; - u8 *resp_ies; - u16 resp_ies_len; - u16 status; - void (*conn_result)(enum conn_event evt, u8 status, void *priv); - void *arg; - void *param; -}; - -struct wilc_remain_ch { - u16 ch; - u32 duration; - void (*expired)(void *priv, u64 cookie); - void *arg; - u64 cookie; -}; - -struct host_if_drv { - struct wilc_user_scan_req usr_scan_req; - struct wilc_conn_info conn_info; - struct wilc_remain_ch remain_on_ch; - u64 p2p_timeout; - - enum host_if_state hif_state; - - u8 assoc_bssid[ETH_ALEN]; - struct completion comp_test_key_block; - struct completion comp_test_disconn_block; - struct completion comp_get_rssi; - struct completion comp_inactive_time; - - struct timer_list scan_timer; - struct wilc_vif *scan_timer_vif; - - struct timer_list connect_timer; - struct wilc_vif *connect_timer_vif; - - struct timer_list remain_on_ch_timer; - struct wilc_vif *remain_on_ch_timer_vif; - - bool ifc_up; - int driver_handler_id; - u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; -}; - -struct wilc_vif; - -signed int wilc_send_buffered_eap(struct wilc_vif *vif, - void (*deliver_to_stack)(struct wilc_vif *, - u8 *, u32, u32, u8), - void (*eap_buf_param)(void *), u8 *buff, - unsigned int size, unsigned int pkt_offset, - void *user_arg); -int wilc_remove_wep_key(struct wilc_vif *vif, u8 index); -int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index); -int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, - u8 index); -int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len, - u8 index, u8 mode, enum authtype auth_type); -int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, - const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, - u8 mode, u8 cipher_mode, u8 index); -s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, - u32 *out_val); -int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, - u8 index, u32 key_rsc_len, const u8 *key_rsc, - const u8 *rx_mic, const u8 *tx_mic, u8 mode, - u8 cipher_mode); -int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid); -int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr); -int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr); -int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, - size_t ies_len); -int wilc_disconnect(struct wilc_vif *vif); -int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel); -int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level); -int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, - u8 *ch_freq_list, u8 ch_list_len, - void (*scan_result_fn)(enum scan_event, - struct wilc_rcvd_net_info *, void *), - void *user_arg, struct cfg80211_scan_request *request); -int wilc_hif_set_cfg(struct wilc_vif *vif, - struct cfg_param_attr *cfg_param); -int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler); -int wilc_deinit(struct wilc_vif *vif); -int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, - struct cfg80211_beacon_data *params); -int wilc_del_beacon(struct wilc_vif *vif); -int wilc_add_station(struct wilc_vif *vif, const u8 *mac, - struct station_parameters *params); -int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]); -int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr); -int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, - struct station_parameters *params); -int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout); -int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, - u8 *mc_list); -int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, - u32 duration, u16 chan, - void (*expired)(void *, u64), void *user_arg); -int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie); -void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg); -int wilc_set_wfi_drv_handler(struct wilc_vif *vif, int index, u8 mode, - u8 ifc_id); -int wilc_set_operation_mode(struct wilc_vif *vif, u32 mode); -int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats); -void wilc_resolve_disconnect_aberration(struct wilc_vif *vif); -int wilc_get_vif_idx(struct wilc_vif *vif); -int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power); -int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power); -/*0 select antenna 1 , 2 select antenna mode , 2 allow the firmware to choose - * the best antenna - */ -int wilc_set_antenna(struct wilc_vif *vif, u8 mode); - -void wilc_set_wowlan_trigger(struct wilc_vif *vif, u8 wowlan_trigger); - -extern u8 wilc_initialized; -s32 handle_scan_done(struct wilc_vif *vif, enum scan_event evt); -void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length); -void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length); -void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length); -void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, - struct cfg80211_crypto_settings *crypto); -void wilc_powersave_state_changes(struct wilc_vif *vif); -#endif diff --git a/drivers/net/wireless/mchp/microchip,wilc,sdio.txt b/drivers/net/wireless/mchp/microchip,wilc,sdio.txt deleted file mode 100644 index 028c64017c9b..000000000000 --- a/drivers/net/wireless/mchp/microchip,wilc,sdio.txt +++ /dev/null @@ -1,36 +0,0 @@ -* Microchip WILC wireless SDIO device - -The wilc1000 chips can be connected via SDIO. The node is used to specifiy -child node to the SDIO controller that connects the device to the system. - -Required properties: -- compatible : Should be "microchip,wilc1000-sdio" -- irq-gpios : Connect to a host IRQ -- reset-gpios : Reset module GPIO -- chip_en-gpios : Chip enable GPIO -- reg : Slot ID used in the controller - -Optional: -- bus-width : Number of data lines wired up the slot. Default 1 bit. - - -Examples: -mmc1: mmc@fc000000 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3>; - non-removable; - vmmc-supply = <&vcc_mmc1_reg>; - vqmmc-supply = <&vcc_3v3_reg>; - status = "okay"; - - wilc_sdio@0 { - compatible = "microchip,wilc1000", "microchip,wilc3000"; - irq-gpios = <&pioC 27 0>; - reset-gpios = <&pioB 28 0>; - chip_en-gpios = <&pioC 30 0>; - status = "okay"; - reg = <0>; - bus-width = <4>; - } - }; -} diff --git a/drivers/net/wireless/mchp/microchip,wilc,spi.txt b/drivers/net/wireless/mchp/microchip,wilc,spi.txt deleted file mode 100644 index 2e2a9306c1e8..000000000000 --- a/drivers/net/wireless/mchp/microchip,wilc,spi.txt +++ /dev/null @@ -1,30 +0,0 @@ -* Microchip WILC wireless SPI device - -The wilc1000 chips can be connected via SPI. This document describes -the binding for the SPI connected module. - -Required properties: -- compatible : Should be "microchip,wilc1000-spi" -- spi-max-frequency : Maximum SPI clocking speed of device in Hz -- reg : Chip select address of device -- irq-gpios : Connect to a host IRQ -- reset-gpios : Reset module GPIO -- chip_en-gpios: : Chip enable GPIO - - -Examples: - -spi1: spi@fc018000 { - cs-gpios = <&pioB 21 0>; - status = "okay"; - - wilc_spi@0 { - compatible = "microchip,wilc1000", "microchip,wilc3000"; - spi-max-frequency = <48000000>; - reg = <0>; - irq-gpios = <&pioC 27 0>; - reset-gpios = <&pioB 28 0>; - chip_en-gpios = <&pioC 30 0>; - status = "okay"; - }; -}; diff --git a/drivers/net/wireless/mchp/microchip,wilc1000,sdio.txt b/drivers/net/wireless/mchp/microchip,wilc1000,sdio.txt new file mode 100644 index 000000000000..8dc88bca2a83 --- /dev/null +++ b/drivers/net/wireless/mchp/microchip,wilc1000,sdio.txt @@ -0,0 +1,42 @@ +* Microchip WILC wireless SDIO device + +The wilc1000 chips can be connected via SDIO. The node is used to specifiy +child node to the SDIO controller that connects the device to the system. + +Required properties: +- compatible : Should be "microchip,wilc1000-sdio" +- irq-gpios : Connect to a host IRQ +- reset-gpios : Reset module GPIO +- chip_en-gpios : Chip enable GPIO +- reg : Slot ID used in the controller + +Optional: +- bus-width : Number of data lines wired up the slot. Default 1 bit. +- rtc_clk : Clock connected on the rtc clock line. Must be assigned + a frequency with assigned-clocks property, and must be + connected to a clock provider. + +Examples: +mmc1: mmc@fc000000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3>; + non-removable; + vmmc-supply = <&vcc_mmc1_reg>; + vqmmc-supply = <&vcc_3v3_reg>; + status = "okay"; + + wilc_sdio@0 { + compatible = "microchip,wilc1000", "microchip,wilc3000"; + irq-gpios = <&pioC 27 0>; + reset-gpios = <&pioB 28 0>; + chip_en-gpios = <&pioC 30 0>; + clocks = <&pck1>; + clock-names = "rtc_clk"; + assigned-clocks = <&pck1>; + assigned-clock-rates = <32768>; + status = "okay"; + reg = <0>; + bus-width = <4>; + } + }; +} diff --git a/drivers/net/wireless/mchp/microchip,wilc1000,spi.txt b/drivers/net/wireless/mchp/microchip,wilc1000,spi.txt new file mode 100644 index 000000000000..dfc01f4aaaa2 --- /dev/null +++ b/drivers/net/wireless/mchp/microchip,wilc1000,spi.txt @@ -0,0 +1,38 @@ +* Microchip WILC wireless SPI device + +The wilc1000 chips can be connected via SPI. This document describes +the binding for the SPI connected module. + +Required properties: +- compatible : Should be "microchip,wilc1000-spi" +- spi-max-frequency : Maximum SPI clocking speed of device in Hz +- reg : Chip select address of device +- irq-gpios : Connect to a host IRQ +- reset-gpios : Reset module GPIO +- chip_en-gpios: : Chip enable GPIO + +Optional: +- rtc_clk : Clock connected on the rtc clock line. Must be assigned + a frequency with assigned-clocks property, and must be + connected to a clock provider. + +Examples: + +spi1: spi@fc018000 { + cs-gpios = <&pioB 21 0>; + status = "okay"; + + wilc_spi@0 { + compatible = "microchip,wilc1000", "microchip,wilc3000"; + spi-max-frequency = <48000000>; + reg = <0>; + irq-gpios = <&pioC 27 0>; + reset-gpios = <&pioB 28 0>; + chip_en-gpios = <&pioC 30 0>; + clocks = <&pck1>; + clock-names = "rtc_clk"; + assigned-clocks = <&pck1>; + assigned-clock-rates = <32768>; + status = "okay"; + }; +}; diff --git a/drivers/net/wireless/mchp/sysfs.c b/drivers/net/wireless/mchp/sysfs.c index 8d32e53aa091..3c4a87190e28 100644 --- a/drivers/net/wireless/mchp/sysfs.c +++ b/drivers/net/wireless/mchp/sysfs.c @@ -9,7 +9,7 @@ static struct kobject *wilc_kobj; static int device_created; -static struct wilc_vif *vif[WILC_NUM_CONCURRENT_IFC]; +static struct wilc *wl; static ssize_t wilc_sysfs_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -17,13 +17,13 @@ static ssize_t wilc_sysfs_show(struct kobject *kobj, int attr_val = -1; if (strcmp(attr->attr.name, "p2p_mode") == 0) - attr_val = vif[0]->attr_sysfs.p2p_mode; + attr_val = wl->attr_sysfs.p2p_mode; if (strcmp(attr->attr.name, "ant_swtch_mode") == 0) - attr_val = vif[0]->attr_sysfs.ant_swtch_mode; + attr_val = wl->attr_sysfs.ant_swtch_mode; else if (strcmp(attr->attr.name, "antenna1") == 0) - attr_val = vif[0]->attr_sysfs.antenna1; + attr_val = wl->attr_sysfs.antenna1; else if (strcmp(attr->attr.name, "antenna2") == 0) - attr_val = vif[0]->attr_sysfs.antenna2; + attr_val = wl->attr_sysfs.antenna2; return sprintf(buf, "%d\n", attr_val); } @@ -33,25 +33,20 @@ static ssize_t wilc_sysfs_store(struct kobject *kobj, size_t count) { int attr_val; - int i; - - for (i = 0; i < WILC_NUM_CONCURRENT_IFC; i++) { - if (kstrtoint(buf, 10, &attr_val)) - PRINT_ER(vif[i]->ndev, - "Failed to convert p2p_mode string"); - if (strcmp(attr->attr.name, "p2p_mode") == 0) { - vif[i]->attr_sysfs.p2p_mode = (attr_val?1:0); - } else if (strcmp(attr->attr.name, "ant_swtch_mode") == 0) { - if (attr_val > ANT_SWTCH_DUAL_GPIO_CTRL) - PRINT_ER(vif[i]->ndev, - "Valid antenna switch modes:\n1-Single Antenna, 2-Dual Antenna\n"); - else - vif[i]->attr_sysfs.ant_swtch_mode = attr_val; - } else if (strcmp(attr->attr.name, "antenna1") == 0) { - vif[i]->attr_sysfs.antenna1 = attr_val; - } else if (strcmp(attr->attr.name, "antenna2") == 0) { - vif[i]->attr_sysfs.antenna2 = attr_val; - } + + if (kstrtoint(buf, 10, &attr_val)) + pr_err("Failed to convert p2p_mode string"); + if (strcmp(attr->attr.name, "p2p_mode") == 0) { + wl->attr_sysfs.p2p_mode = (attr_val?1:0); + } else if (strcmp(attr->attr.name, "ant_swtch_mode") == 0) { + if (attr_val > ANT_SWTCH_DUAL_GPIO_CTRL) + pr_err("Valid antenna switch modes:\n1-Single Antenna, 2-Dual Antenna\n"); + else + wl->attr_sysfs.ant_swtch_mode = attr_val; + } else if (strcmp(attr->attr.name, "antenna1") == 0) { + wl->attr_sysfs.antenna1 = attr_val; + } else if (strcmp(attr->attr.name, "antenna2") == 0) { + wl->attr_sysfs.antenna2 = attr_val; } return count; @@ -82,13 +77,9 @@ static struct attribute_group attr_group = { .attrs = wilc_attrs, }; -void wilc_sysfs_init(struct wilc_vif *vif1, struct wilc_vif *vif2) +void wilc_sysfs_init(struct wilc *wilc) { int retval; - int i; - - vif[0] = vif1; - vif[1] = vif2; if (device_created) return; @@ -99,15 +90,14 @@ void wilc_sysfs_init(struct wilc_vif *vif1, struct wilc_vif *vif2) return; } - for (i = 0; i < WILC_NUM_CONCURRENT_IFC; i++) { - /* By default p2p mode is Group Owner */ - vif[i]->attr_sysfs.p2p_mode = 1; - vif[i]->attr_sysfs.ant_swtch_mode = ANT_SWTCH_INVALID_GPIO_CTRL; - vif[i]->attr_sysfs.antenna1 = 0xFF; - vif[i]->attr_sysfs.antenna2 = 0xFF; - } retval = sysfs_create_group(wilc_kobj, &attr_group); device_created = 1; + wl = wilc; + /* By default p2p mode is Group Owner */ + wl->attr_sysfs.p2p_mode = 1; + wl->attr_sysfs.ant_swtch_mode = ANT_SWTCH_INVALID_GPIO_CTRL; + wl->attr_sysfs.antenna1 = 0xFF; + wl->attr_sysfs.antenna2 = 0xFF; } void wilc_sysfs_exit(void) @@ -116,4 +106,3 @@ void wilc_sysfs_exit(void) sysfs_remove_group(wilc_kobj, &attr_group); kobject_put(wilc_kobj); } - diff --git a/drivers/net/wireless/mchp/wilc_bt.c b/drivers/net/wireless/mchp/wilc_bt.c index a92a34b2b9f9..63643312363f 100644 --- a/drivers/net/wireless/mchp/wilc_bt.c +++ b/drivers/net/wireless/mchp/wilc_bt.c @@ -74,7 +74,7 @@ static const struct cmd_entry cmd_table[] = { static int wilc_bt_dev_open(struct inode *i, struct file *f) { - pr_err("at_pwr_dev: open()\n"); + pr_info("at_pwr_dev: open()\n"); return 0; } @@ -210,9 +210,9 @@ static void handle_cmd_cca_thrshld(char *param) int wilc_bt_power_down(struct wilc *wilc, int source) { const struct wilc_hif_func *hif_func = wilc->hif_func; + int ret; if (source == DEV_BT) { - int ret; u32 reg; pr_info("AT PWR: bt_power_down\n"); @@ -322,7 +322,11 @@ int wilc_bt_power_down(struct wilc *wilc, int source) pr_warn("Another device is preventing power down. request source is %s\n", (source == DEV_WIFI ? "Wifi" : "BT")); } else { - wilc_wlan_power_off_sequence(wilc); + ret = wilc_wlan_power_off_sequence(wilc); + if (ret) { + mutex_unlock(&wilc->cs); + return ret; + } } wilc->power_status[source] = false; diff --git a/drivers/net/wireless/mchp/wilc_hif.c b/drivers/net/wireless/mchp/wilc_hif.c new file mode 100644 index 000000000000..bd36d4087036 --- /dev/null +++ b/drivers/net/wireless/mchp/wilc_hif.c @@ -0,0 +1,2612 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#include + +#include "wilc_wfi_netdevice.h" +#include "wilc_netdev.h" +#include "wilc_wfi_cfgoperations.h" + +#define WILC_HIF_SCAN_TIMEOUT_MS 5000 +#define WILC_HIF_CONNECT_TIMEOUT_MS 9500 + +#define WILC_FALSE_FRMWR_CHANNEL 100 +#define WILC_MAX_RATES_SUPPORTED 12 + +/* Generic success will return 0 */ +#define WILC_SUCCESS 0 /* Generic success */ + +/* Negative numbers to indicate failures */ +/* Generic Fail */ +#define WILC_FAIL -100 +/* Busy with another operation*/ +#define WILC_BUSY -101 +/* A given argument is invalid*/ +#define WILC_INVALID_ARGUMENT -102 +/* An API request would violate the Driver state machine + * (i.e. to start PID while not camped) + */ +#define WILC_INVALID_STATE -103 +/* In copy operations if the copied data is larger than the allocated buffer*/ +#define WILC_BUFFER_OVERFLOW -104 +/* null pointer is passed or used */ +#define WILC_NULL_PTR -105 +#define WILC_EMPTY -107 +#define WILC_FULL -108 +#define WILC_TIMEOUT -109 +/* The required operation have been canceled by the user*/ +#define WILC_CANCELED -110 +/* The Loaded file is corruped or having an invalid format */ +#define WILC_INVALID_FILE -112 +/* Cant find the file to load */ +#define WILC_NOT_FOUND -113 +#define WILC_NO_MEM -114 +#define WILC_UNSUPPORTED_VERSION -115 +#define WILC_FILE_EOF -116 + +#if KERNEL_VERSION(3, 17, 0) > LINUX_VERSION_CODE +struct ieee80211_wmm_ac_param { + u8 aci_aifsn; /* AIFSN, ACM, ACI */ + u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */ + __le16 txop_limit; +} __packed; + +struct ieee80211_wmm_param_ie { + u8 element_id; /* Element ID: 221 (0xdd); */ + u8 len; /* Length: 24 */ + u8 oui[3]; /* 00:50:f2 */ + u8 oui_type; /* 2 */ + u8 oui_subtype; /* 1 */ + u8 version; /* 1 for WMM version 1.0 */ + u8 qos_info; /* AP/STA specific QoS info */ + u8 reserved; /* 0 */ + /* AC_BE, AC_BK, AC_VI, AC_VO */ + struct ieee80211_wmm_ac_param ac[4]; +} __packed; +#endif + +struct send_buffered_eap { + void (*deliver_to_stack)(struct wilc_vif *vif, u8 *buff, u32 size, + u32 pkt_offset, u8 status); + void (*eap_buf_param)(void *priv); + u8 *buff; + unsigned int size; + unsigned int pkt_offset; + void *user_arg; +}; + +struct wilc_rcvd_mac_info { + u8 status; +}; + +struct wilc_set_multicast { + u32 enabled; + u32 cnt; + u8 *mc_list; +}; + +struct host_if_wowlan_trigger { + u8 wowlan_trigger; +}; + +struct bt_coex_mode { + u8 bt_coex; +}; + +struct host_if_set_ant { + u8 mode; + u8 antenna1; + u8 antenna2; + u8 gpio_mode; +}; + +struct wilc_del_all_sta { + u8 assoc_sta; + u8 mac[WILC_MAX_NUM_STA][ETH_ALEN]; +}; + +struct wilc_op_mode { + __le32 mode; +}; + +struct wilc_reg_frame { + bool reg; + u8 reg_id; + __le16 frame_type; +} __packed; + +struct wilc_drv_handler { + __le32 handler; + u8 mode; +} __packed; + +struct wilc_wep_key { + u8 index; + u8 key_len; + u8 key[0]; +} __packed; + +struct wilc_sta_wpa_ptk { + u8 mac_addr[ETH_ALEN]; + u8 key_len; + u8 key[0]; +} __packed; + +struct wilc_ap_wpa_ptk { + u8 mac_addr[ETH_ALEN]; + u8 index; + u8 key_len; + u8 key[0]; +} __packed; + +struct wilc_gtk_key { + u8 mac_addr[ETH_ALEN]; + u8 rsc[8]; + u8 index; + u8 key_len; + u8 key[0]; +} __packed; + +union wilc_message_body { + struct wilc_rcvd_net_info net_info; + struct wilc_rcvd_mac_info mac_info; + struct wilc_set_multicast mc_info; + struct wilc_remain_ch remain_on_ch; + char *data; + struct send_buffered_eap send_buff_eap; + struct host_if_set_ant set_ant; + struct host_if_wowlan_trigger wow_trigger; + struct bt_coex_mode bt_coex_mode; +}; + +struct host_if_msg { + union wilc_message_body body; + struct wilc_vif *vif; + struct work_struct work; + void (*fn)(struct work_struct *ws); + struct completion work_comp; + bool is_sync; +}; + +struct wilc_noa_opp_enable { + u8 ct_window; + u8 cnt; + __le32 duration; + __le32 interval; + __le32 start_time; +} __packed; + +struct wilc_noa_opp_disable { + u8 cnt; + __le32 duration; + __le32 interval; + __le32 start_time; +} __packed; + +struct wilc_join_bss_param { + char ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_terminator; + u8 bss_type; + u8 ch; + __le16 cap_info; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 beacon_period; + u8 dtim_period; + u8 supp_rates[WILC_MAX_RATES_SUPPORTED + 1]; + u8 wmm_cap; + u8 uapsd_cap; + u8 ht_capable; + u8 rsn_found; + u8 rsn_grp_policy; + u8 mode_802_11i; + u8 p_suites[3]; + u8 akm_suites[3]; + u8 rsn_cap[2]; + u8 noa_enabled; + __le32 tsf_lo; + u8 idx; + u8 opp_enabled; + union { + struct wilc_noa_opp_disable opp_dis; + struct wilc_noa_opp_enable opp_en; + }; +} __packed; + +/* 'msg' should be free by the caller for syc */ +static struct host_if_msg* +wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *), + bool is_sync) +{ + struct host_if_msg *msg; + + if (!work_fun) + return ERR_PTR(-EINVAL); + + msg = kzalloc(sizeof(*msg), GFP_ATOMIC); + if (!msg) + return ERR_PTR(-ENOMEM); + msg->fn = work_fun; + msg->vif = vif; + msg->is_sync = is_sync; + if (is_sync) + init_completion(&msg->work_comp); + + return msg; +} + +static int wilc_enqueue_work(struct host_if_msg *msg) +{ + INIT_WORK(&msg->work, msg->fn); + + if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue) + return -EINVAL; + + if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work)) + return -EINVAL; + + return 0; +} + +/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as + * special purpose in wilc device, so we add 1 to the index to starts from 1. + * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC. + */ +int wilc_get_vif_idx(struct wilc_vif *vif) +{ + return vif->idx + 1; +} + +/* We need to minus 1 from idx which is from wilc device to get real index + * of wilc->vif[], because we add 1 when pass to wilc device in the function + * wilc_get_vif_idx. + * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1). + */ +static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx) +{ + int index = idx - 1; + struct wilc_vif *vif; + + if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC) + return NULL; + + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->idx == index) + return vif; + } + + return NULL; +} + +static void handle_send_buffered_eap(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + struct send_buffered_eap *hif_buff_eap = &msg->body.send_buff_eap; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Sending bufferd eapol to WPAS\n"); + if (!hif_buff_eap->buff) + goto out; + + if (hif_buff_eap->deliver_to_stack) + hif_buff_eap->deliver_to_stack(vif, hif_buff_eap->buff, + hif_buff_eap->size, + hif_buff_eap->pkt_offset, + PKT_STATUS_BUFFERED); + if (hif_buff_eap->eap_buf_param) + hif_buff_eap->eap_buf_param(hif_buff_eap->user_arg); + + if (hif_buff_eap->buff != NULL) { + kfree(hif_buff_eap->buff); + hif_buff_eap->buff = NULL; + } + +out: + kfree(msg); +} + +int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, + u8 *ch_freq_list, u8 ch_list_len, + void (*scan_result_fn)(enum scan_event, + struct wilc_rcvd_net_info *, void *), + void *user_arg, struct cfg80211_scan_request *request) +{ + int result = 0; + struct wid wid_list[5]; + u32 index = 0; + u32 i, scan_timeout; + u8 *buffer; + u8 valuesize = 0; + u8 *search_ssid_vals = NULL; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_vif *vif_tmp; + int srcu_idx; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Setting SCAN params\n"); + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Scanning: In [%d] state\n", + hif_drv->hif_state); + + srcu_idx = srcu_read_lock(&vif->wilc->srcu); + list_for_each_entry_rcu(vif_tmp, &vif->wilc->vif_list, list) { + struct host_if_drv *hif_drv_tmp; + + if (vif_tmp == NULL || vif_tmp->hif_drv == NULL) + continue; + + hif_drv_tmp = vif_tmp->hif_drv; + + if (hif_drv_tmp->hif_state != HOST_IF_IDLE && + hif_drv_tmp->hif_state != HOST_IF_CONNECTED) { + PRINT_INFO(vif_tmp->ndev, GENERIC_DBG, + "Abort scan. In state [%d]\n", + hif_drv_tmp->hif_state); + result = -EBUSY; + srcu_read_unlock(&vif->wilc->srcu, srcu_idx); + goto error; + } + } + srcu_read_unlock(&vif->wilc->srcu, srcu_idx); + + if (vif->connecting) { + PRINT_INFO(vif->ndev, GENERIC_DBG, + "Don't do scan in (CONNECTING) state\n"); + result = -EBUSY; + goto error; + } + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Setting SCAN params\n"); + hif_drv->usr_scan_req.ch_cnt = 0; + + if (request->n_ssids) { + for (i = 0; i < request->n_ssids; i++) + valuesize += ((request->ssids[i].ssid_len) + 1); + search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL); + if (search_ssid_vals) { + wid_list[index].id = WID_SSID_PROBE_REQ; + wid_list[index].type = WID_STR; + wid_list[index].val = search_ssid_vals; + buffer = wid_list[index].val; + + *buffer++ = request->n_ssids; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "In Handle_ProbeRequest number of ssid %d\n", + request->n_ssids); + for (i = 0; i < request->n_ssids; i++) { + *buffer++ = request->ssids[i].ssid_len; + memcpy(buffer, request->ssids[i].ssid, + request->ssids[i].ssid_len); + buffer += request->ssids[i].ssid_len; + } + wid_list[index].size = (s32)(valuesize + 1); + index++; + } + } + + wid_list[index].id = WID_INFO_ELEMENT_PROBE; + wid_list[index].type = WID_BIN_DATA; + wid_list[index].val = (s8 *)request->ie; + wid_list[index].size = request->ie_len; + index++; + + wid_list[index].id = WID_SCAN_TYPE; + wid_list[index].type = WID_CHAR; + wid_list[index].size = sizeof(char); + wid_list[index].val = (s8 *)&scan_type; + index++; + +#if KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE + scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS; +#else + if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) { + wid_list[index].id = WID_PASSIVE_SCAN_TIME; + wid_list[index].type = WID_SHORT; + wid_list[index].size = sizeof(u16); + wid_list[index].val = (s8 *)&request->duration; + index++; + + scan_timeout = (request->duration * ch_list_len) + 500; + } else { + scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS; + } +#endif + wid_list[index].id = WID_SCAN_CHANNEL_LIST; + wid_list[index].type = WID_BIN_DATA; + + if (ch_freq_list && ch_list_len > 0) { + for (i = 0; i < ch_list_len; i++) { + if (ch_freq_list[i] > 0) + ch_freq_list[i] -= 1; + } + } + + wid_list[index].val = ch_freq_list; + wid_list[index].size = ch_list_len; + index++; + + wid_list[index].id = WID_START_SCAN_REQ; + wid_list[index].type = WID_CHAR; + wid_list[index].size = sizeof(char); + wid_list[index].val = (s8 *)&scan_source; + index++; + + hif_drv->usr_scan_req.scan_result = scan_result_fn; + hif_drv->usr_scan_req.arg = user_arg; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index); + if (result) { + PRINT_ER(vif->ndev, "Failed to send scan parameters\n"); + goto error; + } else { + hif_drv->scan_timer_vif = vif; + PRINT_INFO(vif->ndev, HOSTINF_DBG, + ">> Starting the SCAN timer\n"); +#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE + hif_drv->scan_timer.data = (unsigned long)hif_drv; +#endif + mod_timer(&hif_drv->scan_timer, + jiffies + msecs_to_jiffies(scan_timeout)); + } + +error: + + kfree(search_ssid_vals); + + return result; +} + +s32 handle_scan_done(struct wilc_vif *vif, enum scan_event evt) +{ + s32 result = 0; + u8 abort_running_scan; + struct wid wid; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_user_scan_req *scan_req; + u8 null_bssid[6] = {0}; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "handling scan done\n"); + + if (!hif_drv) { + PRINT_ER(vif->ndev, "hif driver is NULL\n"); + return result; + } + + if (evt == SCAN_EVENT_DONE) { + if (memcmp(hif_drv->assoc_bssid, null_bssid, ETH_ALEN) == 0) + hif_drv->hif_state = HOST_IF_IDLE; + else + hif_drv->hif_state = HOST_IF_CONNECTED; + } else if (evt == SCAN_EVENT_ABORTED) { + PRINT_INFO(vif->ndev, GENERIC_DBG, "Abort running scan\n"); + abort_running_scan = 1; + wid.id = WID_ABORT_RUNNING_SCAN; + wid.type = WID_CHAR; + wid.val = (s8 *)&abort_running_scan; + wid.size = sizeof(char); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) { + PRINT_ER(vif->ndev, "Failed to set abort running\n"); + result = -EFAULT; + } + } + + scan_req = &hif_drv->usr_scan_req; + if (scan_req->scan_result) { + scan_req->scan_result(evt, NULL, scan_req->arg); + scan_req->scan_result = NULL; + } + + return result; +} + +static int wilc_send_connect_wid(struct wilc_vif *vif) +{ + int result = 0; + struct wid wid_list[4]; + u32 wid_cnt = 0; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_conn_info *conn_attr = &hif_drv->conn_info; + struct wilc_join_bss_param *bss_param = hif_drv->conn_info.param; + struct wilc_vif *vif_tmp; + int srcu_idx; + + srcu_idx = srcu_read_lock(&vif->wilc->srcu); + list_for_each_entry_rcu(vif_tmp, &vif->wilc->vif_list, list) { + struct host_if_drv *hif_drv_tmp; + + if (vif_tmp == NULL || vif_tmp->hif_drv == NULL) + continue; + + hif_drv_tmp = vif_tmp->hif_drv; + + if (hif_drv_tmp->hif_state == HOST_IF_SCANNING) { + PRINT_INFO(vif_tmp->ndev, GENERIC_DBG, + "Abort connect in state [%d]\n", + hif_drv_tmp->hif_state); + result = -EBUSY; + srcu_read_unlock(&vif->wilc->srcu, srcu_idx); + goto error; + } + } + srcu_read_unlock(&vif->wilc->srcu, srcu_idx); + + wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE; + wid_list[wid_cnt].type = WID_BIN_DATA; + wid_list[wid_cnt].val = conn_attr->req_ies; + wid_list[wid_cnt].size = conn_attr->req_ies_len; + wid_cnt++; + + wid_list[wid_cnt].id = WID_11I_MODE; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&conn_attr->security; + wid_cnt++; + + PRINT_D(vif->ndev, HOSTINF_DBG, "Encrypt Mode = %x\n", + conn_attr->security); + wid_list[wid_cnt].id = WID_AUTH_TYPE; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&conn_attr->auth_type; + wid_cnt++; + + PRINT_D(vif->ndev, HOSTINF_DBG, "Authentication Type = %x\n", + conn_attr->auth_type); + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Connecting to network on channel %d\n", conn_attr->ch); + + wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED; + wid_list[wid_cnt].type = WID_STR; + wid_list[wid_cnt].size = sizeof(*bss_param); + wid_list[wid_cnt].val = (u8 *)bss_param; + wid_cnt++; + + PRINT_INFO(vif->ndev, GENERIC_DBG, "send HOST_IF_WAITING_CONN_RESP\n"); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt); + if (result) { + PRINT_ER(vif->ndev, "failed to send config packet\n"); + goto error; + } else { + PRINT_INFO(vif->ndev, GENERIC_DBG, + "set HOST_IF_WAITING_CONN_RESP\n"); + hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP; + } + + return 0; + +error: + + kfree(conn_attr->req_ies); + conn_attr->req_ies = NULL; + + return result; +} + +void handle_connect_cancel(struct wilc_vif *vif) +{ + struct host_if_drv *hif_drv = vif->hif_drv; + + if (hif_drv->conn_info.conn_result) { + hif_drv->conn_info.conn_result(EVENT_DISCONN_NOTIF, + 0, hif_drv->conn_info.arg); + } + + eth_zero_addr(hif_drv->assoc_bssid); + + hif_drv->conn_info.req_ies_len = 0; + kfree(hif_drv->conn_info.req_ies); + hif_drv->conn_info.req_ies = NULL; + hif_drv->hif_state = HOST_IF_IDLE; +} + +static void handle_connect_timeout(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + int result; + struct wid wid; + u16 dummy_reason_code = 0; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (!hif_drv) { + PRINT_ER(vif->ndev, "hif driver is NULL\n"); + goto out; + } + + hif_drv->hif_state = HOST_IF_IDLE; + + if (hif_drv->conn_info.conn_result) { + hif_drv->conn_info.conn_result(EVENT_CONN_RESP, + WILC_MAC_STATUS_DISCONNECTED, + hif_drv->conn_info.arg); + + } else { + PRINT_ER(vif->ndev, "conn_result is NULL\n"); + } + + wid.id = WID_DISCONNECT; + wid.type = WID_CHAR; + wid.val = (s8 *)&dummy_reason_code; + wid.size = sizeof(char); + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Sending disconnect request\n"); + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to send disconect\n"); + + hif_drv->conn_info.req_ies_len = 0; + kfree(hif_drv->conn_info.req_ies); + hif_drv->conn_info.req_ies = NULL; + +out: + kfree(msg); +} + +void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto) +{ + struct wilc_join_bss_param *param; + struct ieee80211_p2p_noa_attr noa_attr; + u8 rates_len = 0; + const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; + const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; + int ret; + const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) + return NULL; + + param->beacon_period = cpu_to_le16(bss->beacon_interval); + param->cap_info = cpu_to_le16(bss->capability); + param->bss_type = WILC_FW_BSS_TYPE_INFRA; + param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq); + ether_addr_copy(param->bssid, bss->bssid); + + ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); + if (ssid_elm) { + if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN) + memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]); + } + + tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); + if (tim_elm && tim_elm[1] >= 2) + param->dtim_period = tim_elm[3]; + + memset(param->p_suites, 0xFF, 3); + memset(param->akm_suites, 0xFF, 3); + + rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len); + if (rates_ie) { + rates_len = rates_ie[1]; + if (rates_len > WILC_MAX_RATES_SUPPORTED) + rates_len = WILC_MAX_RATES_SUPPORTED; + param->supp_rates[0] = rates_len; + memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len); + } + + supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, ies->data, + ies->len); + if (supp_rates_ie) { + if (supp_rates_ie[1] > (WILC_MAX_RATES_SUPPORTED - rates_len)) + param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED; + else + param->supp_rates[0] += supp_rates_ie[1]; + + memcpy(¶m->supp_rates[rates_len + 1], supp_rates_ie + 2, + (param->supp_rates[0] - rates_len)); + } + + ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len); + if (ht_ie) + param->ht_capable = true; + + ret = cfg80211_get_p2p_attr(ies->data, ies->len, + IEEE80211_P2P_ATTR_ABSENCE_NOTICE, + (u8 *)&noa_attr, sizeof(noa_attr)); + if (ret > 0) { + param->tsf_lo = cpu_to_le32(ies->tsf); + param->noa_enabled = 1; + param->idx = noa_attr.index; + if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) { + param->opp_enabled = 1; + param->opp_en.ct_window = noa_attr.oppps_ctwindow; + param->opp_en.cnt = noa_attr.desc[0].count; + param->opp_en.duration = noa_attr.desc[0].duration; + param->opp_en.interval = noa_attr.desc[0].interval; + param->opp_en.start_time = noa_attr.desc[0].start_time; + } else { + param->opp_enabled = 0; + param->opp_dis.cnt = noa_attr.desc[0].count; + param->opp_dis.duration = noa_attr.desc[0].duration; + param->opp_dis.interval = noa_attr.desc[0].interval; + param->opp_dis.start_time = noa_attr.desc[0].start_time; + } + } + wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WMM, + ies->data, ies->len); + if (wmm_ie) { + struct ieee80211_wmm_param_ie *ie; + + ie = (struct ieee80211_wmm_param_ie *)wmm_ie; + if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) && + ie->version == 1) { + param->wmm_cap = true; + if (ie->qos_info & BIT(7)) + param->uapsd_cap = true; + } + } + + wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + ies->data, ies->len); + if (wpa_ie) { + param->mode_802_11i = 1; + param->rsn_found = true; + } + + rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len); + if (rsn_ie) { + int offset = 8; + + param->mode_802_11i = 2; + param->rsn_found = true; + //extract RSN capabilities + offset += (rsn_ie[offset] * 4) + 2; + offset += (rsn_ie[offset] * 4) + 2; + memcpy(param->rsn_cap, &rsn_ie[offset], 2); + } + + if (param->rsn_found) { + int i; + + param->rsn_grp_policy = crypto->cipher_group & 0xFF; + for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++) + param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF; + + for (i = 0; i < crypto->n_akm_suites && i < 3; i++) + param->akm_suites[i] = crypto->akm_suites[i] & 0xFF; + } + + return (void *)param; +} + +static void handle_rcvd_ntwrk_info(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_rcvd_net_info *rcvd_info = &msg->body.net_info; + struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req; + const u8 *ch_elm; + u8 *ies; + int ies_len; + size_t offset; + + PRINT_D(msg->vif->ndev, HOSTINF_DBG, + "Handling received network info\n"); + + if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control)) + offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control)) + offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + else + goto done; + + ies = rcvd_info->mgmt->u.beacon.variable; + ies_len = rcvd_info->frame_len - offset; + if (ies_len <= 0) + goto done; + + PRINT_INFO(msg->vif->ndev, HOSTINF_DBG, "New network found\n"); + /* extract the channel from recevied mgmt frame */ + ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len); + if (ch_elm && ch_elm[1] > 0) + rcvd_info->ch = ch_elm[2]; + + if (scan_req->scan_result) + scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, + rcvd_info, scan_req->arg); + +done: + kfree(rcvd_info->mgmt); + kfree(msg); +} + +static void host_int_get_assoc_res_info(struct wilc_vif *vif, + u8 *assoc_resp_info, + u32 max_assoc_resp_info_len, + u32 *rcvd_assoc_resp_info_len) +{ + int result; + struct wid wid; + + wid.id = WID_ASSOC_RES_INFO; + wid.type = WID_STR; + wid.val = assoc_resp_info; + wid.size = max_assoc_resp_info_len; + + result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); + if (result) { + *rcvd_assoc_resp_info_len = 0; + PRINT_ER(vif->ndev, "Failed to send association response\n"); + return; + } + + *rcvd_assoc_resp_info_len = wid.size; +} + +static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len, + struct wilc_conn_info *ret_conn_info) +{ + u8 *ies; + u16 ies_len; + struct assoc_resp *res = (struct assoc_resp *)buffer; + + ret_conn_info->status = le16_to_cpu(res->status_code); + if (ret_conn_info->status == WLAN_STATUS_SUCCESS) { + ies = &buffer[sizeof(*res)]; + ies_len = buffer_len - sizeof(*res); + + ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL); + if (!ret_conn_info->resp_ies) + return -ENOMEM; + + ret_conn_info->resp_ies_len = ies_len; + } + + return 0; +} + +static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, + u8 mac_status) +{ + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_conn_info *conn_info = &hif_drv->conn_info; + + if (mac_status == WILC_MAC_STATUS_CONNECTED) { + u32 assoc_resp_info_len; + + memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE); + + host_int_get_assoc_res_info(vif, hif_drv->assoc_resp, + WILC_MAX_ASSOC_RESP_FRAME_SIZE, + &assoc_resp_info_len); + + PRINT_D(vif->ndev, HOSTINF_DBG, + "Received association response = %d\n", + assoc_resp_info_len); + if (assoc_resp_info_len != 0) { + s32 err = 0; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Parsing association response\n"); + err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp, + assoc_resp_info_len, + conn_info); + if (err) + PRINT_ER(vif->ndev, + "wilc_parse_assoc_resp_info() returned error %d\n", + err); + } + } + + del_timer(&hif_drv->connect_timer); + conn_info->conn_result(EVENT_CONN_RESP, mac_status, conn_info->arg); + + if (mac_status == WILC_MAC_STATUS_CONNECTED && + conn_info->status == WLAN_STATUS_SUCCESS) { + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "MAC status : CONNECTED and Connect Status : Successful\n"); + hif_drv->hif_state = HOST_IF_CONNECTED; + ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid); + } else { + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "MAC status : %d and Connect Status : %d\n", + mac_status, conn_info->status); + hif_drv->hif_state = HOST_IF_IDLE; + } + + kfree(conn_info->resp_ies); + conn_info->resp_ies = NULL; + conn_info->resp_ies_len = 0; + + kfree(conn_info->req_ies); + conn_info->req_ies = NULL; + conn_info->req_ies_len = 0; +} + +static inline void host_int_handle_disconnect(struct wilc_vif *vif) +{ + struct host_if_drv *hif_drv = vif->hif_drv; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Received WILC_MAC_STATUS_DISCONNECTED from the FW\n"); + if (hif_drv->usr_scan_req.scan_result) { + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "\n\n<< Abort the running OBSS Scan >>\n\n"); + del_timer(&hif_drv->scan_timer); + handle_scan_done(vif, SCAN_EVENT_ABORTED); + } + + if (hif_drv->conn_info.conn_result) { + hif_drv->conn_info.conn_result(EVENT_DISCONN_NOTIF, + 0, hif_drv->conn_info.arg); + } else { + PRINT_ER(vif->ndev, "Connect result NULL\n"); + } + + eth_zero_addr(hif_drv->assoc_bssid); + + hif_drv->conn_info.req_ies_len = 0; + kfree(hif_drv->conn_info.req_ies); + hif_drv->conn_info.req_ies = NULL; + hif_drv->hif_state = HOST_IF_IDLE; +} + +static void handle_rcvd_gnrl_async_info(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (!hif_drv) { + netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__); + goto free_msg; + } + + PRINT_INFO(vif->ndev, GENERIC_DBG, + "Current State = %d,Received state = %d\n", + hif_drv->hif_state, mac_info->status); + + if (!hif_drv->conn_info.conn_result) { + PRINT_ER(vif->ndev, "conn_result is NULL\n"); + goto free_msg; + } + if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { + host_int_parse_assoc_resp_info(vif, mac_info->status); + } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) { + if (hif_drv->hif_state == HOST_IF_CONNECTED) { + host_int_handle_disconnect(vif); + } else if (hif_drv->usr_scan_req.scan_result) { + PRINT_WRN(vif->ndev, HOSTINF_DBG, + "Received WILC_MAC_STATUS_DISCONNECTED. Abort the running Scan"); + del_timer(&hif_drv->scan_timer); + handle_scan_done(vif, SCAN_EVENT_ABORTED); + } + } + +free_msg: + kfree(msg); +} + +int wilc_disconnect(struct wilc_vif *vif) +{ + struct wid wid; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_user_scan_req *scan_req; + struct wilc_conn_info *conn_info; + int result; + u16 dummy_reason_code = 0; + struct wilc_vif *vif_tmp; + int srcu_idx; + + srcu_idx = srcu_read_lock(&vif->wilc->srcu); + list_for_each_entry_rcu(vif_tmp, &vif->wilc->vif_list, list) { + struct host_if_drv *hif_drv_tmp; + + if (vif_tmp == NULL || vif_tmp->hif_drv == NULL) + continue; + + hif_drv_tmp = vif_tmp->hif_drv; + + if (hif_drv_tmp->hif_state == HOST_IF_SCANNING) { + PRINT_INFO(vif_tmp->ndev, GENERIC_DBG, + "Abort scan from disconnect. state [%d]\n", + hif_drv_tmp->hif_state); + del_timer(&hif_drv_tmp->scan_timer); + handle_scan_done(vif_tmp, SCAN_EVENT_ABORTED); + } + } + srcu_read_unlock(&vif->wilc->srcu, srcu_idx); + + wid.id = WID_DISCONNECT; + wid.type = WID_CHAR; + wid.val = (s8 *)&dummy_reason_code; + wid.size = sizeof(char); + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Sending disconnect request\n"); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) { + PRINT_ER(vif->ndev, "Failed to send disconnect\n"); + return -ENOMEM; + } + + scan_req = &hif_drv->usr_scan_req; + conn_info = &hif_drv->conn_info; + + if (scan_req->scan_result) { + del_timer(&hif_drv->scan_timer); + scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg); + scan_req->scan_result = NULL; + } + + if (conn_info->conn_result) { + if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "supplicant requested disconnection\n"); + del_timer(&hif_drv->connect_timer); + conn_info->conn_result(EVENT_CONN_RESP, + WILC_MAC_STATUS_DISCONNECTED, + conn_info->arg); + + } else if (hif_drv->hif_state == HOST_IF_CONNECTED) { + conn_info->conn_result(EVENT_DISCONN_NOTIF, + WILC_MAC_STATUS_DISCONNECTED, + conn_info->arg); + } + } else { + PRINT_ER(vif->ndev, "conn_result = NULL\n"); + } + + hif_drv->hif_state = HOST_IF_IDLE; + + eth_zero_addr(hif_drv->assoc_bssid); + + conn_info->req_ies_len = 0; + kfree(conn_info->req_ies); + conn_info->req_ies = NULL; + conn_info->conn_result = NULL; + + return 0; +} + +int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats) +{ + struct wid wid_list[5]; + u32 wid_cnt = 0, result; + + wid_list[wid_cnt].id = WID_LINKSPEED; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&stats->link_speed; + wid_cnt++; + + wid_list[wid_cnt].id = WID_RSSI; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&stats->rssi; + wid_cnt++; + + wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt; + wid_cnt++; + + wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt; + wid_cnt++; + + wid_list[wid_cnt].id = WID_FAILED_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt; + wid_cnt++; + + result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list, wid_cnt); + if (result) { + PRINT_ER(vif->ndev, "Failed to send scan parameters\n"); + return result; + } + + if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH && + stats->link_speed != DEFAULT_LINK_SPEED) { + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Enable TCP filter\n"); + wilc_enable_tcp_ack_filter(vif, true); + } else if (stats->link_speed != DEFAULT_LINK_SPEED) { + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Disable TCP filter %d\n", + stats->link_speed); + wilc_enable_tcp_ack_filter(vif, false); + } + + return result; +} + +static void handle_get_statistics(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + struct rf_info *stats = (struct rf_info *)msg->body.data; + + wilc_get_statistics(vif, stats); + kfree(msg); +} + +static void wilc_hif_pack_sta_param(struct wilc_vif *vif, u8 *cur_byte, + const u8 *mac, + struct station_parameters *params) +{ + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Packing STA params\n"); + ether_addr_copy(cur_byte, mac); + cur_byte += ETH_ALEN; + + put_unaligned_le16(params->aid, cur_byte); + cur_byte += 2; + + *cur_byte++ = params->supported_rates_len; + if (params->supported_rates_len > 0) + memcpy(cur_byte, params->supported_rates, + params->supported_rates_len); + cur_byte += params->supported_rates_len; + + if (params->ht_capa) { + *cur_byte++ = true; + memcpy(cur_byte, ¶ms->ht_capa, + sizeof(struct ieee80211_ht_cap)); + } else { + *cur_byte++ = false; + } + cur_byte += sizeof(struct ieee80211_ht_cap); + + put_unaligned_le16(params->sta_flags_mask, cur_byte); + cur_byte += 2; + put_unaligned_le16(params->sta_flags_set, cur_byte); +} + +static int handle_remain_on_chan(struct wilc_vif *vif, + struct wilc_remain_ch *hif_remain_ch) +{ + int result; + u8 remain_on_chan_flag; + struct wid wid; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_vif *vif_tmp; + int srcu_idx; + + if (!hif_drv) { + PRINT_ER(vif->ndev, "Driver is null\n"); + return -EFAULT; + } + + srcu_idx = srcu_read_lock(&vif->wilc->srcu); + list_for_each_entry_rcu(vif_tmp, &vif->wilc->vif_list, list) { + struct host_if_drv *hif_drv_tmp; + + if (vif_tmp == NULL || vif_tmp->hif_drv == NULL) + continue; + + hif_drv_tmp = vif_tmp->hif_drv; + + if (hif_drv_tmp->hif_state == HOST_IF_SCANNING) { + PRINT_INFO(vif_tmp->ndev, GENERIC_DBG, + "IFC busy scanning. WLAN_IFC state %d\n", + hif_drv_tmp->hif_state); + srcu_read_unlock(&vif->wilc->srcu, srcu_idx); + return -EBUSY; + } else if (hif_drv_tmp->hif_state != HOST_IF_IDLE && + hif_drv_tmp->hif_state != HOST_IF_CONNECTED) { + PRINT_INFO(vif_tmp->ndev, GENERIC_DBG, + "IFC busy connecting. WLAN_IFC %d\n", + hif_drv_tmp->hif_state); + srcu_read_unlock(&vif->wilc->srcu, srcu_idx); + return -EBUSY; + } + } + srcu_read_unlock(&vif->wilc->srcu, srcu_idx); + + if (vif->connecting) { + PRINT_INFO(vif->ndev, GENERIC_DBG, + "Don't do scan in (CONNECTING) state\n"); + return -EBUSY; + } + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Setting channel [%d] duration[%d] [%llu]\n", + hif_remain_ch->ch, hif_remain_ch->duration, + hif_remain_ch->cookie); + remain_on_chan_flag = true; + wid.id = WID_REMAIN_ON_CHAN; + wid.type = WID_STR; + wid.size = 2; + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + wid.val[0] = remain_on_chan_flag; + wid.val[1] = (s8)hif_remain_ch->ch; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + kfree(wid.val); + if (result) { + PRINT_ER(vif->ndev, "Failed to set remain on channel\n"); + return -EBUSY; + } + + hif_drv->remain_on_ch.arg = hif_remain_ch->arg; + hif_drv->remain_on_ch.expired = hif_remain_ch->expired; + hif_drv->remain_on_ch.ch = hif_remain_ch->ch; + hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie; + hif_drv->hif_state = HOST_IF_P2P_LISTEN; + + hif_drv->remain_on_ch_timer_vif = vif; + + return result; +} + +static int handle_roc_expired(struct wilc_vif *vif, u64 cookie) +{ + u8 remain_on_chan_flag; + struct wid wid; + int result; + struct host_if_drv *hif_drv = vif->hif_drv; + u8 null_bssid[6] = {0}; + + if (hif_drv->hif_state == HOST_IF_P2P_LISTEN) { + remain_on_chan_flag = false; + wid.id = WID_REMAIN_ON_CHAN; + wid.type = WID_STR; + wid.size = 2; + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) { + PRINT_ER(vif->ndev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + wid.val[0] = remain_on_chan_flag; + wid.val[1] = WILC_FALSE_FRMWR_CHANNEL; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + kfree(wid.val); + if (result != 0) { + PRINT_ER(vif->ndev, "Failed to set remain channel\n"); + return -ENOMEM; + } + + if (hif_drv->remain_on_ch.expired) + hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg, + cookie); + + if (memcmp(hif_drv->assoc_bssid, null_bssid, ETH_ALEN) == 0) + hif_drv->hif_state = HOST_IF_IDLE; + else + hif_drv->hif_state = HOST_IF_CONNECTED; + } else { + PRINT_D(vif->ndev, GENERIC_DBG, "Not in listen state\n"); + } + + return 0; +} + +static void handle_listen_state_expired(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + struct wilc_remain_ch *hif_remain_ch = &msg->body.remain_on_ch; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "CANCEL REMAIN ON CHAN\n"); + + handle_roc_expired(vif, hif_remain_ch->cookie); + + kfree(msg); +} + +#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE +static void listen_timer_cb(struct timer_list *t) +#else +static void listen_timer_cb(unsigned long arg) +#endif +{ +#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE + struct host_if_drv *hif_drv = from_timer(hif_drv, t, + remain_on_ch_timer); +#else + struct host_if_drv *hif_drv = (struct host_if_drv *)arg; +#endif + struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif; + int result; + struct host_if_msg *msg; + + del_timer(&vif->hif_drv->remain_on_ch_timer); + + msg = wilc_alloc_work(vif, handle_listen_state_expired, false); + if (IS_ERR(msg)) + return; + + msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie; + + result = wilc_enqueue_work(msg); + if (result) { + PRINT_ER(vif->ndev, "wilc_mq_send fail\n"); + kfree(msg); + } +} + +static void handle_set_mcast_filter(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + struct wilc_set_multicast *set_mc = &msg->body.mc_info; + int result; + struct wid wid; + u8 *cur_byte; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Setup Multicast Filter\n"); + + wid.id = WID_SETUP_MULTICAST_FILTER; + wid.type = WID_BIN; + wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN); + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + goto error; + + cur_byte = wid.val; + put_unaligned_le32(set_mc->enabled, cur_byte); + cur_byte += 4; + + put_unaligned_le32(set_mc->cnt, cur_byte); + cur_byte += 4; + + if (set_mc->cnt > 0 && set_mc->mc_list) + memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to send setup multicast\n"); + +error: + kfree(set_mc->mc_list); + kfree(wid.val); + kfree(msg); +} + +void wilc_set_wowlan_trigger(struct wilc_vif *vif, u8 wowlan_trigger) +{ + int ret; + struct wid wid; + + wid.id = WID_WOWLAN_TRIGGER; + wid.type = WID_CHAR; + wid.val = &wowlan_trigger; + wid.size = sizeof(s8); + + ret = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (ret) + PRINT_ER(vif->ndev, + "Failed to send wowlan trigger config packet\n"); +} + +static void handle_scan_timer(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + int ret; + + PRINT_INFO(msg->vif->ndev, HOSTINF_DBG, "handling scan timer\n"); + ret = handle_scan_done(msg->vif, SCAN_EVENT_ABORTED); + if (ret) + PRINT_ER(msg->vif->ndev, "Failed to handle scan done\n"); + kfree(msg); +} + +static void handle_scan_complete(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + + del_timer(&msg->vif->hif_drv->scan_timer); + PRINT_INFO(msg->vif->ndev, HOSTINF_DBG, "scan completed\n"); + + handle_scan_done(msg->vif, SCAN_EVENT_DONE); + + kfree(msg); +} + +#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE +static void timer_scan_cb(struct timer_list *t) +#else +static void timer_scan_cb(unsigned long arg) +#endif +{ +#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE + struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer); +#else + struct host_if_drv *hif_drv = (struct host_if_drv *)arg; +#endif + struct wilc_vif *vif = hif_drv->scan_timer_vif; + struct host_if_msg *msg; + int result; + + msg = wilc_alloc_work(vif, handle_scan_timer, false); + if (IS_ERR(msg)) + return; + + result = wilc_enqueue_work(msg); + if (result) + kfree(msg); +} + +#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE +static void timer_connect_cb(struct timer_list *t) +#else +static void timer_connect_cb(unsigned long arg) +#endif +{ +#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE + struct host_if_drv *hif_drv = from_timer(hif_drv, t, connect_timer); +#else + struct host_if_drv *hif_drv = (struct host_if_drv *)arg; +#endif + struct wilc_vif *vif = hif_drv->connect_timer_vif; + struct host_if_msg *msg; + int result; + + msg = wilc_alloc_work(vif, handle_connect_timeout, false); + if (IS_ERR(msg)) + return; + + result = wilc_enqueue_work(msg); + if (result) + kfree(msg); +} + +signed int wilc_send_buffered_eap(struct wilc_vif *vif, + void (*deliver_to_stack)(struct wilc_vif *, + u8 *, u32, u32, u8), + void (*eap_buf_param)(void *), u8 *buff, + unsigned int size, unsigned int pkt_offset, + void *user_arg) +{ + int result; + struct host_if_msg *msg; + + if (!vif || !deliver_to_stack || !eap_buf_param) + return -EFAULT; + + msg = wilc_alloc_work(vif, handle_send_buffered_eap, false); + if (IS_ERR(msg)) + return PTR_ERR(msg); + msg->body.send_buff_eap.deliver_to_stack = deliver_to_stack; + msg->body.send_buff_eap.eap_buf_param = eap_buf_param; + msg->body.send_buff_eap.size = size; + msg->body.send_buff_eap.pkt_offset = pkt_offset; + msg->body.send_buff_eap.buff = kmalloc(size + pkt_offset, + GFP_ATOMIC); + memcpy(msg->body.send_buff_eap.buff, buff, size + pkt_offset); + msg->body.send_buff_eap.user_arg = user_arg; + + result = wilc_enqueue_work(msg); + if (result) { + PRINT_ER(vif->ndev, "enqueue work failed\n"); + kfree(msg->body.send_buff_eap.buff); + kfree(msg); + } + return result; +} + +int wilc_remove_wep_key(struct wilc_vif *vif, u8 index) +{ + struct wid wid; + int result; + + wid.id = WID_REMOVE_WEP_KEY; + wid.type = WID_STR; + wid.size = sizeof(char); + wid.val = &index; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, + "Failed to send remove wep key config packet\n"); + return result; +} + +int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index) +{ + struct wid wid; + int result; + + wid.id = WID_KEY_ID; + wid.type = WID_CHAR; + wid.size = sizeof(char); + wid.val = &index; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, + "Failed to send wep default key config packet\n"); + + return result; +} + +int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, + u8 index) +{ + struct wid wid; + int result; + struct wilc_wep_key *wep_key; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Handling WEP key\n"); + wid.id = WID_ADD_WEP_KEY; + wid.type = WID_STR; + wid.size = sizeof(*wep_key) + len; + wep_key = kzalloc(wid.size, GFP_KERNEL); + if (!wep_key) { + PRINT_ER(vif->ndev, "No buffer to send Key\n"); + return -ENOMEM; + } + wid.val = (u8 *)wep_key; + + wep_key->index = index; + wep_key->key_len = len; + memcpy(wep_key->key, key, len); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, + "Failed to add wep key config packet\n"); + + kfree(wep_key); + return result; +} + +int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len, + u8 index, u8 mode, enum authtype auth_type) +{ + struct wid wid_list[3]; + int result; + struct wilc_wep_key *wep_key; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Handling WEP key index: %d\n", + index); + wid_list[0].id = WID_11I_MODE; + wid_list[0].type = WID_CHAR; + wid_list[0].size = sizeof(char); + wid_list[0].val = &mode; + + wid_list[1].id = WID_AUTH_TYPE; + wid_list[1].type = WID_CHAR; + wid_list[1].size = sizeof(char); + wid_list[1].val = (s8 *)&auth_type; + + wid_list[2].id = WID_WEP_KEY_VALUE; + wid_list[2].type = WID_STR; + wid_list[2].size = sizeof(*wep_key) + len; + wep_key = kzalloc(wid_list[2].size, GFP_KERNEL); + if (!wep_key) { + PRINT_ER(vif->ndev, "No buffer to send Key\n"); + return -ENOMEM; + } + + wid_list[2].val = (u8 *)wep_key; + + wep_key->index = index; + wep_key->key_len = len; + memcpy(wep_key->key, key, len); + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, + ARRAY_SIZE(wid_list)); + if (result) + PRINT_ER(vif->ndev, + "Failed to add wep ap key config packet\n"); + + kfree(wep_key); + return result; +} + +int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, + const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, + u8 mode, u8 cipher_mode, u8 index) +{ + int result = 0; + u8 t_key_len = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN; + + if (mode == WILC_AP_MODE) { + struct wid wid_list[2]; + struct wilc_ap_wpa_ptk *key_buf; + + wid_list[0].id = WID_11I_MODE; + wid_list[0].type = WID_CHAR; + wid_list[0].size = sizeof(char); + wid_list[0].val = (s8 *)&cipher_mode; + + key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL); + if (!key_buf) { + PRINT_ER(vif->ndev, + "NO buffer to keep Key buffer - AP\n"); + return -ENOMEM; + } + ether_addr_copy(key_buf->mac_addr, mac_addr); + key_buf->index = index; + key_buf->key_len = t_key_len; + memcpy(&key_buf->key[0], ptk, ptk_key_len); + + if (rx_mic) + memcpy(&key_buf->key[ptk_key_len], rx_mic, + WILC_RX_MIC_KEY_LEN); + + if (tx_mic) + memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN], + tx_mic, WILC_TX_MIC_KEY_LEN); + + wid_list[1].id = WID_ADD_PTK; + wid_list[1].type = WID_STR; + wid_list[1].size = sizeof(*key_buf) + t_key_len; + wid_list[1].val = (u8 *)key_buf; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, + ARRAY_SIZE(wid_list)); + kfree(key_buf); + } else if (mode == WILC_STATION_MODE) { + struct wid wid; + struct wilc_sta_wpa_ptk *key_buf; + + key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL); + if (!key_buf) { + PRINT_ER(vif->ndev, + "No buffer to keep Key buffer - Station\n"); + return -ENOMEM; + } + + ether_addr_copy(key_buf->mac_addr, mac_addr); + key_buf->key_len = t_key_len; + memcpy(&key_buf->key[0], ptk, ptk_key_len); + + if (rx_mic) + memcpy(&key_buf->key[ptk_key_len], rx_mic, + WILC_RX_MIC_KEY_LEN); + + if (tx_mic) + memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN], + tx_mic, WILC_TX_MIC_KEY_LEN); + + wid.id = WID_ADD_PTK; + wid.type = WID_STR; + wid.size = sizeof(*key_buf) + t_key_len; + wid.val = (s8 *)key_buf; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + kfree(key_buf); + } + + return result; +} + +int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, + u8 index, u32 key_rsc_len, const u8 *key_rsc, + const u8 *rx_mic, const u8 *tx_mic, u8 mode, + u8 cipher_mode) +{ + int result = 0; + struct wilc_gtk_key *gtk_key; + int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN; + + gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL); + if (!gtk_key) { + PRINT_ER(vif->ndev, "No buffer to send GTK Key\n"); + return -ENOMEM; + } + + /* fill bssid value only in station mode */ + if (mode == WILC_STATION_MODE && + vif->hif_drv->hif_state == HOST_IF_CONNECTED) + memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN); + + if (key_rsc) + memcpy(gtk_key->rsc, key_rsc, 8); + gtk_key->index = index; + gtk_key->key_len = t_key_len; + memcpy(>k_key->key[0], rx_gtk, gtk_key_len); + + if (rx_mic) + memcpy(>k_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN); + + if (tx_mic) + memcpy(>k_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN], + tx_mic, WILC_TX_MIC_KEY_LEN); + + if (mode == WILC_AP_MODE) { + struct wid wid_list[2]; + + wid_list[0].id = WID_11I_MODE; + wid_list[0].type = WID_CHAR; + wid_list[0].size = sizeof(char); + wid_list[0].val = (s8 *)&cipher_mode; + + wid_list[1].id = WID_ADD_RX_GTK; + wid_list[1].type = WID_STR; + wid_list[1].size = sizeof(*gtk_key) + t_key_len; + wid_list[1].val = (u8 *)gtk_key; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, + ARRAY_SIZE(wid_list)); + kfree(gtk_key); + } else if (mode == WILC_STATION_MODE) { + struct wid wid; + + wid.id = WID_ADD_RX_GTK; + wid.type = WID_STR; + wid.size = sizeof(*gtk_key) + t_key_len; + wid.val = (u8 *)gtk_key; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + kfree(gtk_key); + } + + return result; +} + +int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid) +{ + struct wid wid; + + wid.id = WID_PMKID_INFO; + wid.type = WID_STR; + wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1; + wid.val = (u8 *)pmkid; + + return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); +} + +int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr) +{ + int result; + struct wid wid; + + wid.id = WID_MAC_ADDR; + wid.type = WID_STR; + wid.size = ETH_ALEN; + wid.val = mac_addr; + + result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to get mac address\n"); + + return result; +} + +int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr) +{ + struct wid wid; + int result; + + wid.id = WID_MAC_ADDR; + wid.type = WID_STR; + wid.size = ETH_ALEN; + wid.val = mac_addr; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to set mac address\n"); + + return result; +} + +int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, + size_t ies_len) +{ + int result; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_conn_info *conn_info = &hif_drv->conn_info; + + if (bssid) + ether_addr_copy(conn_info->bssid, bssid); + + if (ies) { + conn_info->req_ies_len = ies_len; + conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL); + if (!conn_info->req_ies) + return -ENOMEM; + } + + result = wilc_send_connect_wid(vif); + if (result) { + PRINT_ER(vif->ndev, "Failed to send connect wid\n"); + goto free_ies; + } + +#if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE + hif_drv->connect_timer.data = (unsigned long)hif_drv; +#endif + hif_drv->connect_timer_vif = vif; + mod_timer(&hif_drv->connect_timer, + jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS)); + + return 0; + +free_ies: + kfree(conn_info->req_ies); + + return result; +} + +int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel) +{ + struct wid wid; + int result; + + wid.id = WID_CURRENT_CHANNEL; + wid.type = WID_CHAR; + wid.size = sizeof(char); + wid.val = &channel; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to set channel\n"); + + return result; +} + +int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode, + u8 ifc_id) +{ + struct wid wid; + int result; + struct wilc_drv_handler drv; + + + wid.id = WID_SET_OPERATION_MODE; + wid.type = WID_STR; + wid.size = sizeof(drv); + wid.val = (u8 *)&drv; + + drv.handler = cpu_to_le32(index); + drv.mode = (ifc_id | (mode << 1)); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to set driver handler\n"); + + return result; +} + +s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val) +{ + struct wid wid; + s32 result; + + wid.id = WID_SET_STA_MAC_INACTIVE_TIME; + wid.type = WID_STR; + wid.size = ETH_ALEN; + wid.val = kzalloc(wid.size, GFP_KERNEL); + if (!wid.val) { + PRINT_ER(vif->ndev, "Failed to allocate buffer\n"); + return -ENOMEM; + } + + ether_addr_copy(wid.val, mac); + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + kfree(wid.val); + if (result) { + PRINT_ER(vif->ndev, "Failed to set inactive mac\n"); + return result; + } + + wid.id = WID_GET_INACTIVE_TIME; + wid.type = WID_INT; + wid.val = (s8 *)out_val; + wid.size = sizeof(u32); + result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to get inactive time\n"); + + PRINT_INFO(vif->ndev, CFG80211_DBG, "Getting inactive time : %d\n", + *out_val); + + return result; +} + +int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level) +{ + struct wid wid; + int result; + + if (!rssi_level) { + PRINT_ER(vif->ndev, "RSS pointer value is null\n"); + return -EFAULT; + } + + wid.id = WID_RSSI; + wid.type = WID_CHAR; + wid.size = sizeof(char); + wid.val = rssi_level; + result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to get RSSI value\n"); + + return result; +} + +int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats) +{ + int result; + struct host_if_msg *msg; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, " getting async statistics\n"); + msg = wilc_alloc_work(vif, handle_get_statistics, false); + if (IS_ERR(msg)) + return PTR_ERR(msg); + + msg->body.data = (char *)stats; + + result = wilc_enqueue_work(msg); + if (result) { + PRINT_ER(vif->ndev, "enqueue work failed\n"); + kfree(msg); + return result; + } + + return result; +} + +int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param) +{ + struct wid wid_list[4]; + int i = 0; + + if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) { + wid_list[i].id = WID_SHORT_RETRY_LIMIT; + wid_list[i].val = (s8 *)¶m->short_retry_limit; + wid_list[i].type = WID_SHORT; + wid_list[i].size = sizeof(u16); + i++; + } + if (param->flag & WILC_CFG_PARAM_RETRY_LONG) { + wid_list[i].id = WID_LONG_RETRY_LIMIT; + wid_list[i].val = (s8 *)¶m->long_retry_limit; + wid_list[i].type = WID_SHORT; + wid_list[i].size = sizeof(u16); + i++; + } + if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) { + wid_list[i].id = WID_FRAG_THRESHOLD; + wid_list[i].val = (s8 *)¶m->frag_threshold; + wid_list[i].type = WID_SHORT; + wid_list[i].size = sizeof(u16); + i++; + } + if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) { + wid_list[i].id = WID_RTS_THRESHOLD; + wid_list[i].val = (s8 *)¶m->rts_threshold; + wid_list[i].type = WID_SHORT; + wid_list[i].size = sizeof(u16); + i++; + } + + return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, i); +} + +#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE +static void get_periodic_rssi(struct timer_list *t) +#else +static void get_periodic_rssi(unsigned long arg) +#endif +{ +#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE + struct wilc_vif *vif = from_timer(vif, t, periodic_rssi); +#else + struct wilc_vif *vif = (struct wilc_vif *)arg; +#endif + + if (!vif->hif_drv) { + PRINT_ER(vif->ndev, "hif driver is NULL\n"); + return; + } + + if (vif->hif_drv->hif_state == HOST_IF_CONNECTED) + wilc_get_stats_async(vif, &vif->periodic_stats); + + mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000)); +} + +int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler) +{ + struct host_if_drv *hif_drv; + struct wilc_vif *vif = netdev_priv(dev); + + hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL); + if (!hif_drv) { + PRINT_ER(dev, "hif driver is NULL\n"); + return -ENOMEM; + } + *hif_drv_handler = hif_drv; + vif->hif_drv = hif_drv; + +#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE + timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0); + timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0); + timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0); + timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0); +#else + setup_timer(&hif_drv->scan_timer, timer_scan_cb, 0); + setup_timer(&hif_drv->connect_timer, timer_connect_cb, 0); + setup_timer(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0); + setup_timer(&vif->periodic_rssi, get_periodic_rssi, + (unsigned long)vif); +#endif + mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000)); + + hif_drv->hif_state = HOST_IF_IDLE; + + hif_drv->p2p_timeout = 0; + + return 0; +} + +int wilc_deinit(struct wilc_vif *vif) +{ + int result = 0; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (!hif_drv) { + PRINT_ER(vif->ndev, "hif driver is NULL\n"); + return -EFAULT; + } + + mutex_lock(&vif->wilc->deinit_lock); + + del_timer_sync(&hif_drv->scan_timer); + del_timer_sync(&hif_drv->connect_timer); + del_timer_sync(&vif->periodic_rssi); + del_timer_sync(&hif_drv->remain_on_ch_timer); + + if (hif_drv->usr_scan_req.scan_result) { + hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL, + hif_drv->usr_scan_req.arg); + hif_drv->usr_scan_req.scan_result = NULL; + } + + hif_drv->hif_state = HOST_IF_IDLE; + + kfree(hif_drv); + vif->hif_drv = NULL; + + mutex_unlock(&vif->wilc->deinit_lock); + return result; +} + +void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) +{ + int result; + struct host_if_msg *msg; + int id; + struct host_if_drv *hif_drv; + struct wilc_vif *vif; + int srcu_idx; + + id = get_unaligned_le32(&buffer[length - 4]); + srcu_idx = srcu_read_lock(&wilc->srcu); + vif = wilc_get_vif_from_idx(wilc, id); + if (!vif) + goto out; + + hif_drv = vif->hif_drv; + if (!hif_drv) { + PRINT_ER(vif->ndev, "driver not init[%p]\n", hif_drv); + goto out; + } + + msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false); + if (IS_ERR(msg)) + goto out; + + msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1; + msg->body.net_info.rssi = buffer[8]; + msg->body.net_info.mgmt = kmemdup(&buffer[9], + msg->body.net_info.frame_len, + GFP_KERNEL); + if (!msg->body.net_info.mgmt) { + kfree(msg); + goto out; + } + + result = wilc_enqueue_work(msg); + if (result) { + PRINT_ER(vif->ndev, "message parameters (%d)\n", result); + kfree(msg->body.net_info.mgmt); + kfree(msg); + } +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); +} + +void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) +{ + int result; + struct host_if_msg *msg; + int id; + struct host_if_drv *hif_drv; + struct wilc_vif *vif; + int srcu_idx; + + mutex_lock(&wilc->deinit_lock); + + id = get_unaligned_le32(&buffer[length - 4]); + srcu_idx = srcu_read_lock(&wilc->srcu); + vif = wilc_get_vif_from_idx(wilc, id); + if (!vif) + goto out; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "General asynchronous info packet received\n"); + + hif_drv = vif->hif_drv; + + if (!hif_drv) { + PRINT_ER(vif->ndev, "hif driver is NULL\n"); + goto out; + } + + if (!hif_drv->conn_info.conn_result) { + PRINT_ER(vif->ndev, "there is no current Connect Request\n"); + goto out; + } + + msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false); + if (IS_ERR(msg)) + goto out; + + msg->body.mac_info.status = buffer[7]; + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Received MAC status= %d Reason= %d Info = %d\n", + buffer[7], buffer[8], buffer[9]); + result = wilc_enqueue_work(msg); + if (result) { + PRINT_ER(vif->ndev, "enqueue work failed\n"); + kfree(msg); + } +out: + mutex_unlock(&wilc->deinit_lock); + srcu_read_unlock(&wilc->srcu, srcu_idx); +} + +void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) +{ + int result; + int id; + struct host_if_drv *hif_drv; + struct wilc_vif *vif; + int srcu_idx; + + id = get_unaligned_le32(&buffer[length - 4]); + srcu_idx = srcu_read_lock(&wilc->srcu); + vif = wilc_get_vif_from_idx(wilc, id); + if (!vif) + goto out; + + PRINT_INFO(vif->ndev, GENERIC_DBG, "Scan notification received\n"); + + hif_drv = vif->hif_drv; + if (!hif_drv) { + PRINT_ER(vif->ndev, "hif driver is NULL\n"); + goto out; + } + + if (hif_drv->usr_scan_req.scan_result) { + struct host_if_msg *msg; + + msg = wilc_alloc_work(vif, handle_scan_complete, false); + if (IS_ERR(msg)) + goto out; + + result = wilc_enqueue_work(msg); + if (result) { + PRINT_ER(vif->ndev, "enqueue work failed\n"); + kfree(msg); + } + } +out: + srcu_read_unlock(&wilc->srcu, srcu_idx); +} + +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, + u32 duration, u16 chan, + void (*expired)(void *, u64), void *user_arg) +{ + struct wilc_remain_ch roc; + int result; + + PRINT_INFO(vif->ndev, CFG80211_DBG, "called\n"); + roc.ch = chan; + roc.expired = expired; + roc.arg = user_arg; + roc.duration = duration; + roc.cookie = cookie; + result = handle_remain_on_chan(vif, &roc); + if (result) + PRINT_ER(vif->ndev, "failed to set remain on channel\n"); + + return result; +} + +int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie) +{ + int result; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (!hif_drv) { + PRINT_ER(vif->ndev, "hif driver is NULL\n"); + return -EFAULT; + } + + del_timer(&hif_drv->remain_on_ch_timer); + + result = handle_roc_expired(vif, cookie); + + return result; +} + +void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg) +{ + struct wid wid; + int result; + struct wilc_reg_frame reg_frame; + + wid.id = WID_REGISTER_FRAME; + wid.type = WID_STR; + wid.size = sizeof(reg_frame); + wid.val = (u8 *)®_frame; + + memset(®_frame, 0x0, sizeof(reg_frame)); + reg_frame.reg = reg; + + switch (frame_type) { + case IEEE80211_STYPE_ACTION: + PRINT_INFO(vif->ndev, HOSTINF_DBG, "ACTION\n"); + reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX; + break; + + case IEEE80211_STYPE_PROBE_REQ: + PRINT_INFO(vif->ndev, HOSTINF_DBG, "PROBE REQ\n"); + reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX; + break; + + default: + PRINT_INFO(vif->ndev, HOSTINF_DBG, "Not valid frame type\n"); + break; + } + reg_frame.frame_type = cpu_to_le16(frame_type); + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to frame register\n"); +} + +int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, + struct cfg80211_beacon_data *params) +{ + struct wid wid; + int result; + u8 *cur_byte; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Setting adding beacon\n"); + + wid.id = WID_ADD_BEACON; + wid.type = WID_BIN; + wid.size = params->head_len + params->tail_len + 16; + wid.val = kzalloc(wid.size, GFP_KERNEL); + if (!wid.val) { + PRINT_ER(vif->ndev, "Failed to allocate buffer\n"); + return -ENOMEM; + } + + cur_byte = wid.val; + put_unaligned_le32(interval, cur_byte); + cur_byte += 4; + put_unaligned_le32(dtim_period, cur_byte); + cur_byte += 4; + put_unaligned_le32(params->head_len, cur_byte); + cur_byte += 4; + + if (params->head_len > 0) + memcpy(cur_byte, params->head, params->head_len); + cur_byte += params->head_len; + + put_unaligned_le32(params->tail_len, cur_byte); + cur_byte += 4; + + if (params->tail_len > 0) + memcpy(cur_byte, params->tail, params->tail_len); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to send add beacon\n"); + + kfree(wid.val); + + return result; +} + +int wilc_del_beacon(struct wilc_vif *vif) +{ + int result; + struct wid wid; + u8 del_beacon = 0; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Setting deleting beacon message queue params\n"); + + wid.id = WID_DEL_BEACON; + wid.type = WID_CHAR; + wid.size = sizeof(char); + wid.val = &del_beacon; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to send delete beacon\n"); + + return result; +} + +int wilc_add_station(struct wilc_vif *vif, const u8 *mac, + struct station_parameters *params) +{ + struct wid wid; + int result; + u8 *cur_byte; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Setting adding station message queue params\n"); + + wid.id = WID_ADD_STA; + wid.type = WID_BIN; + wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len; + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + cur_byte = wid.val; + wilc_hif_pack_sta_param(vif, cur_byte, mac, params); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result != 0) + PRINT_ER(vif->ndev, "Failed to send add station\n"); + + kfree(wid.val); + + return result; +} + +int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr) +{ + struct wid wid; + int result; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Setting deleting station message queue params\n"); + + wid.id = WID_REMOVE_STA; + wid.type = WID_BIN; + wid.size = ETH_ALEN; + wid.val = kzalloc(wid.size, GFP_KERNEL); + if (!wid.val) { + PRINT_ER(vif->ndev, "Failed to allocate buffer\n"); + return -ENOMEM; + } + + if (!mac_addr) + eth_broadcast_addr(wid.val); + else + ether_addr_copy(wid.val, mac_addr); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to del station\n"); + + kfree(wid.val); + + return result; +} + +int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]) +{ + struct wid wid; + int result; + int i; + u8 assoc_sta = 0; + struct wilc_del_all_sta del_sta; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Setting deauthenticating station message queue params\n"); + memset(&del_sta, 0x0, sizeof(del_sta)); + for (i = 0; i < WILC_MAX_NUM_STA; i++) { + if (!is_zero_ether_addr(mac_addr[i])) { + PRINT_INFO(vif->ndev, + CFG80211_DBG, "BSSID = %x%x%x%x%x%x\n", + mac_addr[i][0], mac_addr[i][1], + mac_addr[i][2], mac_addr[i][3], + mac_addr[i][4], mac_addr[i][5]); + assoc_sta++; + ether_addr_copy(del_sta.mac[i], mac_addr[i]); + } + } + if (!assoc_sta) { + PRINT_INFO(vif->ndev, CFG80211_DBG, "NO ASSOCIATED STAS\n"); + return 0; + } + del_sta.assoc_sta = assoc_sta; + + wid.id = WID_DEL_ALL_STA; + wid.type = WID_STR; + wid.size = (assoc_sta * ETH_ALEN) + 1; + wid.val = (u8 *)&del_sta; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to send delete all station\n"); + + return result; +} + +int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, + struct station_parameters *params) +{ + struct wid wid; + int result; + u8 *cur_byte; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Setting editing station message queue params\n"); + + wid.id = WID_EDIT_STA; + wid.type = WID_BIN; + wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len; + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + cur_byte = wid.val; + wilc_hif_pack_sta_param(vif, cur_byte, mac, params); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to send edit station\n"); + + kfree(wid.val); + return result; +} + +int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout) +{ + struct wid wid; + int result; + s8 power_mode; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, "\n\n>> Setting PS to %d <<\n\n", + enabled); + if (enabled) + power_mode = WILC_FW_MIN_FAST_PS; + else + power_mode = WILC_FW_NO_POWERSAVE; + + wid.id = WID_POWER_MANAGEMENT; + wid.val = &power_mode; + wid.size = sizeof(char); + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + PRINT_ER(vif->ndev, "Failed to send power management\n"); + + return result; +} + +int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, + u8 *mc_list) +{ + int result; + struct host_if_msg *msg; + + PRINT_INFO(vif->ndev, HOSTINF_DBG, + "Setting Multicast Filter params\n"); + msg = wilc_alloc_work(vif, handle_set_mcast_filter, false); + if (IS_ERR(msg)) + return PTR_ERR(msg); + + msg->body.mc_info.enabled = enabled; + msg->body.mc_info.cnt = count; + msg->body.mc_info.mc_list = mc_list; + + result = wilc_enqueue_work(msg); + if (result) { + PRINT_ER(vif->ndev, "enqueue work failed\n"); + kfree(msg); + } + return result; +} + +int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power) +{ + struct wid wid; + + wid.id = WID_TX_POWER; + wid.type = WID_CHAR; + wid.val = &tx_power; + wid.size = sizeof(char); + + return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); +} + +int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power) +{ + struct wid wid; + + wid.id = WID_TX_POWER; + wid.type = WID_CHAR; + wid.val = tx_power; + wid.size = sizeof(char); + + return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); +} + +bool is_valid_gpio(struct wilc_vif *vif, u8 gpio) +{ + switch (vif->wilc->chip) { + case WILC_1000: + if (gpio == 0 || gpio == 1 || gpio == 4 || gpio == 6) + return true; + else + return false; + case WILC_3000: + if (gpio == 0 || gpio == 3 || gpio == 4 || + (gpio >= 17 && gpio <= 20)) + return true; + else + return false; + default: + return false; + } +} + +int wilc_set_antenna(struct wilc_vif *vif, u8 mode) +{ + struct wid wid; + int ret; + struct sysfs_attr_group *attr_syfs_p = &vif->wilc->attr_sysfs; + struct host_if_set_ant set_ant; + + set_ant.mode = mode; + + if (attr_syfs_p->ant_swtch_mode == ANT_SWTCH_INVALID_GPIO_CTRL) { + PRINT_ER(vif->ndev, "Ant switch GPIO mode is invalid.\n"); + PRINT_ER(vif->ndev, "Set it using /sys/wilc/ant_swtch_mode\n"); + return WILC_FAIL; + } + + if (is_valid_gpio(vif, attr_syfs_p->antenna1)) { + set_ant.antenna1 = attr_syfs_p->antenna1; + } else { + PRINT_ER(vif->ndev, "Invalid GPIO %d\n", attr_syfs_p->antenna1); + return WILC_FAIL; + } + + if (attr_syfs_p->ant_swtch_mode == ANT_SWTCH_DUAL_GPIO_CTRL) { + if ((attr_syfs_p->antenna2 != attr_syfs_p->antenna1) && + is_valid_gpio(vif, attr_syfs_p->antenna2)) { + set_ant.antenna2 = attr_syfs_p->antenna2; + } else { + PRINT_ER(vif->ndev, "Invalid GPIO %d\n", + attr_syfs_p->antenna2); + return WILC_FAIL; + } + } + + set_ant.gpio_mode = attr_syfs_p->ant_swtch_mode; + + wid.id = WID_ANTENNA_SELECTION; + wid.type = WID_BIN; + wid.val = (u8 *)&set_ant; + wid.size = sizeof(struct host_if_set_ant); + if (attr_syfs_p->ant_swtch_mode == ANT_SWTCH_SNGL_GPIO_CTRL) + PRINT_INFO(vif->ndev, CFG80211_DBG, + "set antenna %d on GPIO %d\n", set_ant.mode, + set_ant.antenna1); + else if (attr_syfs_p->ant_swtch_mode == ANT_SWTCH_DUAL_GPIO_CTRL) + PRINT_INFO(vif->ndev, CFG80211_DBG, + "set antenna %d on GPIOs %d and %d\n", + set_ant.mode, set_ant.antenna1, + set_ant.antenna2); + + ret = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (ret) + PRINT_ER(vif->ndev, "Failed to set antenna mode\n"); + + return ret; +} diff --git a/drivers/net/wireless/mchp/wilc_hif.h b/drivers/net/wireless/mchp/wilc_hif.h new file mode 100644 index 000000000000..5210975b402f --- /dev/null +++ b/drivers/net/wireless/mchp/wilc_hif.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#ifndef HOST_INT_H +#define HOST_INT_H +#include +#include "wilc_wlan_if.h" + +enum { + WILC_IDLE_MODE = 0x0, + WILC_AP_MODE = 0x1, + WILC_STATION_MODE = 0x2, + WILC_GO_MODE = 0x3, + WILC_CLIENT_MODE = 0x4, + WILC_MONITOR_MODE = 0x5 +}; + +#define WILC_MAX_NUM_STA 9 +#define WILC_MAX_NUM_SCANNED_CH 14 +#define WILC_MAX_NUM_PROBED_SSID 10 + +#define WILC_TX_MIC_KEY_LEN 8 +#define WILC_RX_MIC_KEY_LEN 8 + +#define WILC_MAX_NUM_PMKIDS 16 +#define WILC_ADD_STA_LENGTH 40 +#define WILC_NUM_CONCURRENT_IFC 2 + +enum { + WILC_SET_CFG = 0, + WILC_GET_CFG +}; + +#define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256 +extern uint32_t cfg_packet_timeout; + +struct assoc_resp { + __le16 capab_info; + __le16 status_code; + __le16 aid; +} __packed; + +struct rf_info { + u8 link_speed; + s8 rssi; + u32 tx_cnt; + u32 rx_cnt; + u32 tx_fail_cnt; +}; + +enum host_if_state { + HOST_IF_IDLE = 0, + HOST_IF_SCANNING = 1, + HOST_IF_CONNECTING = 2, + HOST_IF_WAITING_CONN_RESP = 3, + HOST_IF_CONNECTED = 4, + HOST_IF_P2P_LISTEN = 5, + HOST_IF_FORCE_32BIT = 0xFFFFFFFF +}; + +struct wilc_pmkid { + u8 bssid[ETH_ALEN]; + u8 pmkid[WLAN_PMKID_LEN]; +} __packed; + +struct wilc_pmkid_attr { + u8 numpmkid; + struct wilc_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS]; +} __packed; + +struct cfg_param_attr { + u32 flag; + u16 short_retry_limit; + u16 long_retry_limit; + u16 frag_threshold; + u16 rts_threshold; +}; + +enum cfg_param { + WILC_CFG_PARAM_RETRY_SHORT = BIT(0), + WILC_CFG_PARAM_RETRY_LONG = BIT(1), + WILC_CFG_PARAM_FRAG_THRESHOLD = BIT(2), + WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3) +}; + +enum scan_event { + SCAN_EVENT_NETWORK_FOUND = 0, + SCAN_EVENT_DONE = 1, + SCAN_EVENT_ABORTED = 2, + SCAN_EVENT_FORCE_32BIT = 0xFFFFFFFF +}; + +enum conn_event { + EVENT_CONN_RESP = 0, + EVENT_DISCONN_NOTIF = 1, + EVENT_FORCE_32BIT = 0xFFFFFFFF +}; + +enum { + WILC_HIF_SDIO = 0, + WILC_HIF_SPI = BIT(0), + WILC_HIF_SDIO_GPIO_IRQ = BIT(1) +}; + +enum { + WILC_MAC_STATUS_INIT = -1, + WILC_MAC_STATUS_DISCONNECTED = 0, + WILC_MAC_STATUS_CONNECTED = 1 +}; + +struct wilc_rcvd_net_info { + s8 rssi; + u8 ch; + u16 frame_len; + struct ieee80211_mgmt *mgmt; +}; + +typedef void (*wilc_remain_on_chan_ready)(void *); + +struct wilc_user_scan_req { + void (*scan_result)(enum scan_event evt, + struct wilc_rcvd_net_info *info, void *priv); + void *arg; + u32 ch_cnt; +}; + +struct wilc_conn_info { + u8 bssid[ETH_ALEN]; + u8 security; + enum authtype auth_type; + u8 ch; + u8 *req_ies; + size_t req_ies_len; + u8 *resp_ies; + u16 resp_ies_len; + u16 status; + void (*conn_result)(enum conn_event evt, u8 status, void *priv); + void *arg; + void *param; +}; + +struct wilc_remain_ch { + u16 ch; + u32 duration; + void (*expired)(void *priv, u64 cookie); + void *arg; + u64 cookie; +}; + +struct host_if_drv { + struct wilc_user_scan_req usr_scan_req; + struct wilc_conn_info conn_info; + struct wilc_remain_ch remain_on_ch; + u64 p2p_timeout; + + enum host_if_state hif_state; + + u8 assoc_bssid[ETH_ALEN]; + struct completion comp_test_key_block; + struct completion comp_test_disconn_block; + struct completion comp_get_rssi; + struct completion comp_inactive_time; + + struct timer_list scan_timer; + struct wilc_vif *scan_timer_vif; + + struct timer_list connect_timer; + struct wilc_vif *connect_timer_vif; + + struct timer_list remain_on_ch_timer; + struct wilc_vif *remain_on_ch_timer_vif; + + bool ifc_up; + u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; +}; + +struct wilc_vif; + +signed int wilc_send_buffered_eap(struct wilc_vif *vif, + void (*deliver_to_stack)(struct wilc_vif *, + u8 *, u32, u32, u8), + void (*eap_buf_param)(void *), u8 *buff, + unsigned int size, unsigned int pkt_offset, + void *user_arg); +int wilc_remove_wep_key(struct wilc_vif *vif, u8 index); +int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index); +int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, + u8 index); +int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len, + u8 index, u8 mode, enum authtype auth_type); +int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, + const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, + u8 mode, u8 cipher_mode, u8 index); +s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, + u32 *out_val); +int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, + u8 index, u32 key_rsc_len, const u8 *key_rsc, + const u8 *rx_mic, const u8 *tx_mic, u8 mode, + u8 cipher_mode); +int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid); +int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr); +int wilc_set_mac_address(struct wilc_vif *vif, u8 *mac_addr); +int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, + size_t ies_len); +int wilc_disconnect(struct wilc_vif *vif); +int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel); +int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level); +int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, + u8 *ch_freq_list, u8 ch_list_len, + void (*scan_result_fn)(enum scan_event, + struct wilc_rcvd_net_info *, void *), + void *user_arg, struct cfg80211_scan_request *request); +int wilc_hif_set_cfg(struct wilc_vif *vif, + struct cfg_param_attr *cfg_param); +int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler); +int wilc_deinit(struct wilc_vif *vif); +int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, + struct cfg80211_beacon_data *params); +int wilc_del_beacon(struct wilc_vif *vif); +int wilc_add_station(struct wilc_vif *vif, const u8 *mac, + struct station_parameters *params); +int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]); +int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr); +int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, + struct station_parameters *params); +int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout); +int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, + u8 *mc_list); +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, + u32 duration, u16 chan, + void (*expired)(void *, u64), void *user_arg); +int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie); +void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg); +int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode, + u8 ifc_id); +int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats); +int wilc_get_vif_idx(struct wilc_vif *vif); +int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power); +int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power); +/*0 select antenna 1 , 2 select antenna mode , 2 allow the firmware to choose + * the best antenna + */ +int wilc_set_antenna(struct wilc_vif *vif, u8 mode); + +void wilc_set_wowlan_trigger(struct wilc_vif *vif, u8 wowlan_trigger); + +extern u8 wilc_initialized; +s32 handle_scan_done(struct wilc_vif *vif, enum scan_event evt); +void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length); +void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length); +void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length); +void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto); +void handle_connect_cancel(struct wilc_vif *vif); +#endif diff --git a/drivers/net/wireless/mchp/wilc_mon.c b/drivers/net/wireless/mchp/wilc_mon.c index 8a2a0b7b2319..98c975038a40 100644 --- a/drivers/net/wireless/mchp/wilc_mon.c +++ b/drivers/net/wireless/mchp/wilc_mon.c @@ -29,22 +29,14 @@ void wilc_wfi_handle_monitor_rx(struct wilc *wilc, u8 *buff, u32 size) struct wilc_vif *vif = 0; struct sk_buff *skb = NULL; struct wfi_rtap_hdr *hdr; - int i; - - for (i = 0; i < wilc->vif_num; i++) { - if (wilc->vif[i]->iftype == WILC_MONITOR_MODE) { - vif = wilc->vif[i]; - break; - } - } + vif = wilc_get_vif_from_type(wilc, WILC_MONITOR_MODE); if (!vif) { PRINT_D(vif->ndev, HOSTAPD_DBG, "Monitor interface not up\n"); return; } skb = dev_alloc_skb(size + sizeof(*hdr)); - if (!skb) { PRINT_D(vif->ndev, HOSTAPD_DBG, "Monitor if: No memory to allocate skb"); @@ -93,8 +85,7 @@ void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size) } /* Get WILC header */ - memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET); - le32_to_cpus(&header); + header = get_unaligned_le32(buff - HOST_HDR_OFFSET); /* * The packet offset field contain info about what type of management * the frame we are dealing with and ack status @@ -302,7 +293,11 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl, strncpy(wl->monitor_dev->name, name, IFNAMSIZ); wl->monitor_dev->name[IFNAMSIZ - 1] = 0; wl->monitor_dev->netdev_ops = &wilc_wfi_netdev_ops; - +#if KERNEL_VERSION(4, 11, 9) <= LINUX_VERSION_CODE + wl->monitor_dev->needs_free_netdev = true; +#else + wl->monitor_dev->destructor = free_netdev; +#endif if (register_netdevice(wl->monitor_dev)) { PRINT_ER(real_dev, "register_netdevice failed\n"); return NULL; @@ -318,7 +313,7 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl, return wl->monitor_dev; } -void wilc_wfi_deinit_mon_interface(struct wilc *wl) +void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked) { if (!wl->monitor_dev) return; @@ -326,8 +321,10 @@ void wilc_wfi_deinit_mon_interface(struct wilc *wl) PRINT_INFO(wl->monitor_dev, HOSTAPD_DBG, "In Deinit monitor interface\n"); PRINT_INFO(wl->monitor_dev, HOSTAPD_DBG, "Unregister monitor netdev\n"); - unregister_netdev(wl->monitor_dev); - free_netdev(wl->monitor_dev); + if (rtnl_locked) + unregister_netdevice(wl->monitor_dev); + else + unregister_netdev(wl->monitor_dev); PRINT_INFO(wl->monitor_dev, HOSTAPD_DBG, "Deinit monitor interface done\n"); wl->monitor_dev = NULL; diff --git a/drivers/net/wireless/mchp/wilc_netdev.c b/drivers/net/wireless/mchp/wilc_netdev.c index 5f769faae4f4..9c95f2c2a16b 100644 --- a/drivers/net/wireless/mchp/wilc_netdev.c +++ b/drivers/net/wireless/mchp/wilc_netdev.c @@ -13,121 +13,12 @@ #include #include #include -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP -#include -#endif /* DISABLE_PWRSAVE_AND_SCAN_DURING_IP */ #include "wilc_netdev.h" #include "wilc_wfi_cfgoperations.h" #define WILC_MULTICAST_TABLE_SIZE 8 -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP -bool g_ignore_PS_state; -#define WILC_IP_TIMEOUT_MS 15000 - -void handle_pwrsave_for_IP(struct wilc_vif *vif, uint8_t state) -{ - struct wilc_priv *priv; - - priv = wdev_priv(vif->ndev->ieee80211_ptr); - - switch (state) { - case IP_STATE_OBTAINING: - - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Obtaining IP, Disable (Scan-Set PowerSave)\n"); - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Save the Current state of the PS = %d\n", - vif->pwrsave_current_state); - - vif->obtaining_ip = true; - - /* Set this flag to avoid storing the disabled case of PS which - * occurs duringIP - */ - g_ignore_PS_state = true; - - wilc_set_power_mgmt(vif, 0, 0); - - /* Start the DuringIPTimer */ - #if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE - vif->during_ip_timer.data = (uint32_t)vif; - #endif - mod_timer(&vif->during_ip_timer, - (jiffies + msecs_to_jiffies(20000))); - - break; - - case IP_STATE_OBTAINED: - - PRINT_INFO(vif->ndev, GENERIC_DBG, - "IP obtained , Enable (Scan-Set PowerSave)\n"); - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Recover the state of the PS = %d\n", - vif->pwrsave_current_state); - - vif->obtaining_ip = false; - - wilc_set_power_mgmt(vif, vif->pwrsave_current_state, 0); - - del_timer(&vif->during_ip_timer); - - break; - - case IP_STATE_GO_ASSIGNING: - - vif->obtaining_ip = true; - - /* Start the DuringIPTimer */ - #if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE - vif->during_ip_timer.data = (uint32_t)vif; - #endif - mod_timer(&vif->during_ip_timer, - (jiffies + msecs_to_jiffies(WILC_IP_TIMEOUT_MS))); - - break; - - default: //IP_STATE_DEFAULT - - vif->obtaining_ip = false; - - /* Stop the DuringIPTimer */ - del_timer(&vif->during_ip_timer); - - break; - } -} - -void store_power_save_current_state(struct wilc_vif *vif, bool val) -{ - if (g_ignore_PS_state) { - g_ignore_PS_state = false; - return; - } - vif->pwrsave_current_state = val; -} - -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE -void clear_during_ip(struct timer_list *t) -#else -void clear_during_ip(unsigned long arg) -#endif -{ -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE - struct wilc_vif *vif = from_timer(vif, t, during_ip_timer); -#else - struct wilc_vif *vif = (struct wilc_vif *)arg; -#endif - - PRINT_ER(vif->ndev, "Unable to Obtain IP\n"); - - vif->obtaining_ip = false; - - wilc_powersave_state_changes(vif); -} -#endif /* DISABLE_PWRSAVE_AND_SCAN_DURING_IP */ - static int wilc_mac_open(struct net_device *ndev); static int wilc_mac_close(struct net_device *ndev); @@ -136,24 +27,17 @@ int recovery_on; int wait_for_recovery; static int debug_thread(void *arg) { - struct net_device *dev = arg; - struct wilc_vif *vif = netdev_priv(dev); - struct wilc *wl; - struct wilc_priv *priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy); + struct wilc *wl = arg; + struct wilc_vif *vif; signed long timeout; - struct host_if_drv *hif_drv = (struct host_if_drv *)priv->hif_drv; + struct host_if_drv *hif_drv; int i = 0; - if (!vif) - return -1; - - wl = vif->wilc; - if (!wl) - return -1; - complete(&wl->debug_thread_started); while (1) { + int srcu_idx; + if (!wl->initialized && !kthread_should_stop()) { msleep(1000); continue; @@ -165,64 +49,76 @@ static int debug_thread(void *arg) msecs_to_jiffies(6000))) { while (!kthread_should_stop()) schedule(); - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Exit debug thread\n"); + pr_info("Exit debug thread\n"); return 0; } - if (!debug_running) continue; - PRINT_INFO(dev, GENERIC_DBG, - "*** Debug Thread Running ***\n"); + + pr_debug("%s *** Debug Thread Running ***cnt[%d]\n", __func__, + cfg_packet_timeout); + if (cfg_packet_timeout < 5) continue; - PRINT_INFO(dev, GENERIC_DBG, - "\n"); + pr_info("%s \n", __func__); cfg_packet_timeout = 0; timeout = 10; recovery_on = 1; wait_for_recovery = 1; - for (i = 0; i < WILC_NUM_CONCURRENT_IFC; i++) - wilc_mac_close(wl->vif[i]->ndev); - for (i = WILC_NUM_CONCURRENT_IFC; i > 0; i--) { - while (wilc_mac_open(wl->vif[i-1]->ndev) && --timeout) + + srcu_idx = srcu_read_lock(&wl->srcu); + list_for_each_entry_rcu(vif, &wl->vif_list, list) { + //close the interface only if it was open + if (vif->mac_opened) { + wilc_mac_close(vif->ndev); + vif->restart = 1; + } + } + //TODO://Need to find way to call them in reverse + i = 0; + list_for_each_entry_rcu(vif, &wl->vif_list, list) { + struct wilc_conn_info *info; + + // Only open the interface manually closed earlier + if (!vif->restart) + continue; + i++; + hif_drv = vif->priv.hif_drv; + while (wilc_mac_open(vif->ndev) && --timeout) msleep(100); if (timeout == 0) PRINT_WRN(vif->ndev, GENERIC_DBG, "Couldn't restart ifc %d\n", i); - } - if (hif_drv->hif_state == HOST_IF_CONNECTED) { - struct wilc_conn_info *conn_info = &hif_drv->conn_info; - PRINT_INFO(vif->ndev, GENERIC_DBG, - "notify the user with the Disconnection\n"); - if (hif_drv->usr_scan_req.scan_result) { + if (hif_drv->hif_state == HOST_IF_CONNECTED) { + info = &hif_drv->conn_info; PRINT_INFO(vif->ndev, GENERIC_DBG, - "Abort the running OBSS Scan\n"); - del_timer(&hif_drv->scan_timer); - handle_scan_done(vif, SCAN_EVENT_ABORTED); - } - if (conn_info->conn_result) { -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - - handle_pwrsave_for_IP(vif, IP_STATE_DEFAULT); -#endif - - conn_info->conn_result(EVENT_DISCONN_NOTIF, - 0, conn_info->arg); - } else { - PRINT_ER(vif->ndev, "Connect result NULL\n"); + "notify the user with the Disconnection\n"); + if (hif_drv->usr_scan_req.scan_result) { + PRINT_INFO(vif->ndev, GENERIC_DBG, + "Abort the running OBSS Scan\n"); + del_timer(&hif_drv->scan_timer); + handle_scan_done(vif, + SCAN_EVENT_ABORTED); + } + if (info->conn_result) { + info->conn_result(EVENT_DISCONN_NOTIF, + 0, info->arg); + } else { + PRINT_ER(vif->ndev, + "Connect result NULL\n"); + } + eth_zero_addr(hif_drv->assoc_bssid); + info->req_ies_len = 0; + kfree(info->req_ies); + info->req_ies = NULL; + hif_drv->hif_state = HOST_IF_IDLE; } - eth_zero_addr(hif_drv->assoc_bssid); - - conn_info->req_ies_len = 0; - kfree(conn_info->req_ies); - conn_info->req_ies = NULL; - - hif_drv->hif_state = HOST_IF_IDLE; + vif->restart = 0; } + srcu_read_unlock(&wl->srcu, srcu_idx); recovery_on = 0; } return 0; @@ -231,10 +127,10 @@ static int debug_thread(void *arg) void wilc_disable_irq(struct wilc *wilc, int wait) { if (wait) { - PRINT_INFO(wilc->vif[0]->ndev, INT_DBG, "Disabling IRQ ...\n"); + pr_info("%s Disabling IRQ ...\n", __func__); disable_irq(wilc->dev_irq_num); } else { - PRINT_INFO(wilc->vif[0]->ndev, INT_DBG, "Disabling IRQ ...\n"); + pr_info("%s Disabling IRQ ...\n", __func__); disable_irq_nosync(wilc->dev_irq_num); } } @@ -247,13 +143,9 @@ static irqreturn_t host_wakeup_isr(int irq, void *user_data) static irqreturn_t isr_uh_routine(int irq, void *user_data) { struct wilc *wilc = (struct wilc *)user_data; - struct net_device *dev = wilc->vif[0]->ndev; - - - PRINT_INFO(dev, INT_DBG, "Interrupt received UH\n"); if (wilc->close) { - PRINT_ER(dev, "Can't handle UH interrupt\n"); + pr_err("%s: Can't handle UH interrupt\n", __func__); return IRQ_HANDLED; } return IRQ_WAKE_THREAD; @@ -262,15 +154,12 @@ static irqreturn_t isr_uh_routine(int irq, void *user_data) static irqreturn_t isr_bh_routine(int irq, void *userdata) { struct wilc *wilc = (struct wilc *)userdata; - struct net_device *dev = wilc->vif[0]->ndev; - if (wilc->close) { - PRINT_ER(dev, "Can't handle BH interrupt\n"); + pr_err("%s: Can't handle BH interrupt\n", __func__); return IRQ_HANDLED; } - PRINT_INFO(dev, INT_DBG, "Interrupt received BH\n"); wilc_handle_isr(wilc); return IRQ_HANDLED; @@ -329,7 +218,7 @@ static int init_irq(struct net_device *dev) if (wl->io_type == WILC_HIF_SPI || wl->io_type == WILC_HIF_SDIO_GPIO_IRQ) { if (request_threaded_irq(wl->dev_irq_num, isr_uh_routine, - isr_bh_routine, IRQF_TRIGGER_LOW | + isr_bh_routine, IRQF_TRIGGER_FALLING | IRQF_ONESHOT | IRQF_NO_SUSPEND, "WILC_IRQ", wl) < 0) { @@ -412,7 +301,7 @@ void wilc_frmw_to_host(struct wilc_vif *vif, u8 *buff, u32 size, u8 null_bssid[ETH_ALEN] = {0}; buff += pkt_offset; - priv = wiphy_priv(vif->ndev->ieee80211_ptr->wiphy); + priv = &vif->priv; if (size == 0) { PRINT_ER(vif->ndev, @@ -533,42 +422,21 @@ void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode) { struct wilc_vif *vif = netdev_priv(wilc_netdev); struct wilc *wilc = vif->wilc; - u8 i = 0; + int srcu_idx; - PRINT_INFO(vif->ndev, GENERIC_DBG, "set bssid on[%p]\n", wilc_netdev); - for (i = 0; i < wilc->vif_num; i++) { - if (wilc_netdev == wilc->vif[i]->ndev) { + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (wilc_netdev == vif->ndev) { if (bssid) - ether_addr_copy(wilc->vif[i]->bssid, bssid); + ether_addr_copy(vif->bssid, bssid); else - eth_zero_addr(wilc->vif[i]->bssid); + eth_zero_addr(vif->bssid); PRINT_INFO(vif->ndev, GENERIC_DBG, - "set bssid [%pM]\n", wilc->vif[i]->bssid); - wilc->vif[i]->iftype = mode; + "set bssid [%pM]\n", vif->bssid); + vif->iftype = mode; } } -} - -int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) -{ - u8 i = 0; - u8 ret_val = 0; - - for (i = 0; i < wilc->vif_num; i++) - if (!is_zero_ether_addr(wilc->vif[i]->bssid)) - ret_val++; - - return ret_val; -} - -struct net_device *wilc_get_if_netdev(struct wilc *wilc, uint8_t ifc) -{ - return wilc->vif[ifc]->ndev; -} - -struct host_if_drv *get_drv_hndl_by_ifc(struct wilc *wilc, uint8_t ifc) -{ - return wilc->vif[ifc]->hif_drv; + srcu_read_unlock(&wilc->srcu, srcu_idx); } #define TX_BACKOFF_WEIGHT_INCR_STEP (1) @@ -577,19 +445,19 @@ struct host_if_drv *get_drv_hndl_by_ifc(struct wilc *wilc, uint8_t ifc) #define TX_BACKOFF_WEIGHT_MIN (0) #define TX_BCKOFF_WGHT_MS (1) - static int wilc_txq_task(void *vp) { int ret; u32 txq_count; - struct net_device *ndev = vp; int backoff_weight = TX_BACKOFF_WEIGHT_MIN; signed long timeout; - struct wilc_vif *vif = netdev_priv(ndev); - struct wilc *wl = vif->wilc; + struct wilc *wl = vp; complete(&wl->txq_thread_started); while (1) { + struct wilc_vif *vif = wilc_get_wl_to_vif(wl); + struct net_device *ndev = vif->ndev; + PRINT_INFO(ndev, TX_DBG, "txq_task Taking a nap\n"); wait_for_completion(&wl->txq_event); PRINT_INFO(ndev, TX_DBG, "txq_task Who waked me up\n"); @@ -603,16 +471,21 @@ static int wilc_txq_task(void *vp) } PRINT_INFO(ndev, TX_DBG, "handle the tx packet\n"); do { - ret = wilc_wlan_handle_txq(ndev, &txq_count); + ret = wilc_wlan_handle_txq(wl, &txq_count); if (txq_count < FLOW_CTRL_LOW_THRESHLD) { + struct wilc_vif *ifc; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); PRINT_INFO(ndev, TX_DBG, "Waking up queue\n"); - if (wl->vif[0]->mac_opened && - netif_queue_stopped(wl->vif[0]->ndev)) - netif_wake_queue(wl->vif[0]->ndev); + list_for_each_entry_rcu(ifc, &wl->vif_list, + list) { + if (ifc->mac_opened && + netif_queue_stopped(ifc->ndev)) + netif_wake_queue(ifc->ndev); + } + srcu_read_unlock(&wl->srcu, srcu_idx); - if (wl->vif[1]->mac_opened && - netif_queue_stopped(wl->vif[1]->ndev)) - netif_wake_queue(wl->vif[1]->ndev); } if (ret == -ENOBUFS) { @@ -650,7 +523,6 @@ static int wilc_wlan_get_firmware(struct net_device *dev) const struct firmware *wilc_firmware; char *firmware; - if (wilc->chip == WILC_3000) { PRINT_INFO(dev, INIT_DBG, "Detect chip WILC3000\n"); firmware = FW_WILC3000_WIFI; @@ -733,14 +605,13 @@ fail: static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif) { - struct wilc_priv *priv; + struct wilc_priv *priv = &vif->priv; struct host_if_drv *hif_drv; u8 b; u16 hw; u32 w; PRINT_INFO(vif->ndev, INIT_DBG, "Start configuring Firmware\n"); - priv = wiphy_priv(dev->ieee80211_ptr->wiphy); hif_drv = (struct host_if_drv *)priv->hif_drv; PRINT_D(vif->ndev, INIT_DBG, "Host = %p\n", hif_drv); @@ -908,17 +779,6 @@ fail: return -1; } -static void wlan_deinit_locks(struct wilc *wilc) -{ - pr_info("De-Initializing Locks\n"); - - mutex_destroy(&wilc->hif_cs); - mutex_destroy(&wilc->rxq_cs); - mutex_destroy(&wilc->cfg_cmd_lock); - mutex_destroy(&wilc->txq_add_to_head_cs); - mutex_destroy(&wilc->cs); -} - static void wlan_deinitialize_threads(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); @@ -982,7 +842,7 @@ static void wilc_wlan_deinitialize(struct net_device *dev) deinit_irq(dev); ret = wilc_wlan_stop(wl, vif); - if (ret == 0) + if (ret != 0) PRINT_ER(dev, "failed in wlan_stop\n"); PRINT_INFO(vif->ndev, INIT_DBG, "Deinitializing WILC Wlan\n"); @@ -996,26 +856,6 @@ static void wilc_wlan_deinitialize(struct net_device *dev) } } -static void wlan_init_locks(struct wilc *wl) -{ - pr_info("Initializing Locks ...\n"); - - mutex_init(&wl->rxq_cs); - mutex_init(&wl->cfg_cmd_lock); - - spin_lock_init(&wl->txq_spinlock); - mutex_init(&wl->txq_add_to_head_cs); - mutex_init(&wl->hif_cs); - mutex_init(&wl->cs); - - init_completion(&wl->txq_event); - - init_completion(&wl->cfg_event); - init_completion(&wl->sync_event); - init_completion(&wl->txq_thread_started); - init_completion(&wl->debug_thread_started); -} - static int wlan_initialize_threads(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); @@ -1023,7 +863,7 @@ static int wlan_initialize_threads(struct net_device *dev) PRINT_INFO(vif->ndev, INIT_DBG, "Initializing Threads ...\n"); PRINT_INFO(vif->ndev, INIT_DBG, "Creating kthread for transmission\n"); - wilc->txq_thread = kthread_run(wilc_txq_task, (void *)dev, + wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc, "K_TXQ_TASK"); if (IS_ERR(wilc->txq_thread)) { PRINT_ER(dev, "couldn't create TXQ thread\n"); @@ -1035,7 +875,7 @@ static int wlan_initialize_threads(struct net_device *dev) if (!debug_running) { PRINT_INFO(vif->ndev, INIT_DBG, "Creating kthread for Debugging\n"); - wilc->debug_thread = kthread_run(debug_thread, (void *)dev, + wilc->debug_thread = kthread_run(debug_thread, (void *)wilc, "WILC_DEBUG"); if (IS_ERR(wilc->debug_thread)) { PRINT_ER(dev, "couldn't create debug thread\n"); @@ -1063,15 +903,10 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif) ret = wilc_wlan_init(dev); if (ret < 0) { PRINT_ER(dev, "Initializing WILC_Wlan FAILED\n"); - ret = -EIO; - goto fail; + return -EIO; } PRINT_INFO(vif->ndev, GENERIC_DBG, "WILC Initialization done\n"); - if (init_irq(dev)) { - ret = -EIO; - goto fail; - } ret = wlan_initialize_threads(dev); if (ret < 0) { @@ -1080,6 +915,11 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif) goto fail_wilc_wlan; } + if (init_irq(dev)) { + ret = -EIO; + goto fail_threads; + } + if (wl->io_type == WILC_HIF_SDIO && wl->hif_func->enable_interrupt(wl)) { PRINT_ER(dev, "couldn't initialize IRQ\n"); @@ -1138,10 +978,10 @@ fail_irq_enable: fail_irq_init: deinit_irq(dev); +fail_threads: wlan_deinitialize_threads(dev); fail_wilc_wlan: wilc_wlan_cleanup(dev); -fail: PRINT_ER(dev, "WLAN initialization FAILED\n"); } else { PRINT_WRN(vif->ndev, INIT_DBG, "wilc already initialized\n"); @@ -1161,7 +1001,7 @@ static int wilc_mac_open(struct net_device *ndev) { struct wilc_vif *vif = netdev_priv(ndev); struct wilc *wl = vif->wilc; - struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr); + struct wilc_priv *priv = &vif->priv; unsigned char mac_add[ETH_ALEN] = {0}; int ret = 0; @@ -1193,19 +1033,8 @@ static int wilc_mac_open(struct net_device *ndev) } wait_for_recovery = 0; - if (!(memcmp(ndev->name, IFC_0, 5))) { - vif->ifc_id = WILC_WLAN_IFC; - } else if (!(memcmp(ndev->name, IFC_1, 4))) { - vif->ifc_id = WILC_P2P_IFC; - } else { - PRINT_ER(vif->ndev, "Unknown interface name\n"); - wilc_deinit_host_int(ndev); - wilc_wlan_deinitialize(ndev); - return -ENODEV; - } - wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), - vif->iftype, vif->ifc_id); - wilc_set_operation_mode(vif, vif->iftype); + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + vif->iftype, vif->idx); wilc_get_mac_address(vif, mac_add); PRINT_INFO(vif->ndev, INIT_DBG, "Mac address: %pM\n", mac_add); @@ -1246,25 +1075,29 @@ static int wilc_set_mac_addr(struct net_device *dev, void *p) struct sockaddr *addr = (struct sockaddr *)p; struct wilc *wilc = vif->wilc; unsigned char mac_addr[6] = {0}; - int i; + struct wilc_vif *tmp_vif; + int srcu_idx; if (!is_valid_ether_addr(addr->sa_data)) { PRINT_INFO(vif->ndev, INIT_DBG, "Invalid MAC address\n"); return -EINVAL; } - for (i = 0; i < wilc->vif_num; i++) { - wilc_get_mac_address(wilc->vif[i], mac_addr); + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(tmp_vif, &wilc->vif_list, list) { + wilc_get_mac_address(tmp_vif, mac_addr); if (ether_addr_equal(addr->sa_data, mac_addr)) { - if (vif != wilc->vif[i]) { + if (vif != tmp_vif) { PRINT_INFO(vif->ndev, INIT_DBG, "MAC address is alredy in use\n"); + srcu_read_unlock(&wilc->srcu, srcu_idx); return -EINVAL; - } else { - return 0; } + srcu_read_unlock(&wilc->srcu, srcu_idx); + return 0; } } + srcu_read_unlock(&wilc->srcu, srcu_idx); /* configure new MAC address */ result = wilc_set_mac_address(vif, (u8 *)addr->sa_data); @@ -1369,17 +1202,21 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) PRINT_D(vif->ndev, TX_DBG, "Adding tx pkt to TX Queue\n"); vif->netstats.tx_packets++; vif->netstats.tx_bytes += tx_data->size; - tx_data->bssid = wilc->vif[vif->idx]->bssid; tx_data->vif = vif; queue_count = txq_add_net_pkt(ndev, (void *)tx_data, tx_data->buff, tx_data->size, wilc_tx_complete); if (queue_count > FLOW_CTRL_UP_THRESHLD) { - if (wilc->vif[0]->mac_opened) - netif_stop_queue(wilc->vif[0]->ndev); - if (wilc->vif[1]->mac_opened) - netif_stop_queue(wilc->vif[1]->ndev); + struct wilc_vif *vif; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->mac_opened) + netif_stop_queue(vif->ndev); + } + srcu_read_unlock(&wilc->srcu, srcu_idx); } return NETDEV_TX_OK; @@ -1402,6 +1239,8 @@ static int wilc_mac_close(struct net_device *ndev) if (vif->ndev) { netif_stop_queue(vif->ndev); + handle_connect_cancel(vif); + if (!recovery_on) wilc_deinit_host_int(vif->ndev); } @@ -1409,6 +1248,7 @@ static int wilc_mac_close(struct net_device *ndev) if (wl->open_ifcs == 0) { PRINT_INFO(ndev, GENERIC_DBG, "Deinitializing wilc\n"); wl->close = 1; + wilc_wlan_deinitialize(ndev); } @@ -1419,22 +1259,24 @@ static int wilc_mac_close(struct net_device *ndev) void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) { - int i = 0; struct wilc_vif *vif; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + u16 tp = le16_to_cpup((__le16 *)buff); + struct wilc_priv *priv; - for (i = 0; i < wilc->vif_num; i++) { - u16 type; + priv = &vif->priv; + if (((tp == vif->frame_reg[0].type && vif->frame_reg[0].reg) || + (tp == vif->frame_reg[1].type && vif->frame_reg[1].reg)) && + vif->p2p_listen_state) + wilc_wfi_p2p_rx(vif, buff, size); - vif = netdev_priv(wilc->vif[i]->ndev); - if (vif->monitor_flag) { + if (vif->monitor_flag) wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size); - return; - } - type = le16_to_cpup((__le16 *)buff); - if ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) || - (type == vif->frame_reg[1].type && vif->frame_reg[1].reg)) - wilc_wfi_p2p_rx(vif->ndev, buff, size); } + srcu_read_unlock(&wilc->srcu, srcu_idx); } static const struct net_device_ops wilc_netdev_ops = { @@ -1447,84 +1289,10 @@ static const struct net_device_ops wilc_netdev_ops = { .ndo_set_rx_mode = wilc_set_multicast_list, }; -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP -static int dev_state_ev_handler(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct in_ifaddr *dev_iface = ptr; - struct wilc_priv *priv; - struct host_if_drv *hif_drv; - struct net_device *dev; - struct wilc_vif *vif; - - if (!dev_iface || !dev_iface->ifa_dev || !dev_iface->ifa_dev->dev) { - pr_err("dev_iface = NULL\n"); - return NOTIFY_DONE; - } - - dev = (struct net_device *)dev_iface->ifa_dev->dev; - if (dev->netdev_ops != &wilc_netdev_ops) { - pr_info("interface is not ours\n"); - return NOTIFY_DONE; - } - - if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) { - pr_err("No Wireless registerd\n"); - return NOTIFY_DONE; - } - - priv = wiphy_priv(dev->ieee80211_ptr->wiphy); - if (!priv) { - pr_err("No Wireless Priv\n"); - return NOTIFY_DONE; - } - vif = netdev_priv(dev); - hif_drv = (struct host_if_drv *)priv->hif_drv; - if (!vif || !hif_drv) { - PRINT_WRN(vif->ndev, GENERIC_DBG, "No Wireless Priv\n"); - return NOTIFY_DONE; - } - - switch (event) { - case NETDEV_UP: - PRINT_INFO(vif->ndev, GENERIC_DBG, "event NETDEV_UP%p\n", dev); - PRINT_D(vif->ndev, GENERIC_DBG, - "\n =========== IP Address Obtained ============\n\n"); - if (vif->iftype == WILC_STATION_MODE || - vif->iftype == WILC_CLIENT_MODE) { - hif_drv->ifc_up = 1; - - handle_pwrsave_for_IP(vif, IP_STATE_OBTAINED); - } - break; - - case NETDEV_DOWN: - PRINT_INFO(vif->ndev, GENERIC_DBG, "event=NETDEV_DOWN %p\n", - dev); - if (vif->iftype == WILC_STATION_MODE || - vif->iftype == WILC_CLIENT_MODE) { - hif_drv->ifc_up = 0; - handle_pwrsave_for_IP(vif, IP_STATE_DEFAULT); - } - break; - - default: - PRINT_INFO(vif->ndev, GENERIC_DBG, - "[%s] unknown dev event %lu\n", - dev_iface->ifa_label, event); - break; - } - - return NOTIFY_DONE; -} -static struct notifier_block g_dev_notifier = { - .notifier_call = dev_state_ev_handler -}; -#endif - void wilc_netdev_cleanup(struct wilc *wilc) { - int i; + struct wilc_vif *vif; + int srcu_idx; if (!wilc) return; @@ -1534,28 +1302,39 @@ void wilc_netdev_cleanup(struct wilc *wilc) wilc->firmware = NULL; } - for (i = WILC_NUM_CONCURRENT_IFC - 1 ; i >= 0; i--) - if (wilc->vif[i] && wilc->vif[i]->ndev) { - PRINT_INFO(wilc->vif[i]->ndev, INIT_DBG, + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + /* clear the mode */ + wilc_set_operation_mode(vif, 0, 0, 0); + if (vif->ndev) { + PRINT_INFO(vif->ndev, INIT_DBG, "Unregistering netdev %p\n", - wilc->vif[i]->ndev); - unregister_netdev(wilc->vif[i]->ndev); - PRINT_INFO(wilc->vif[i]->ndev, INIT_DBG, - "Freeing Wiphy...\n"); - wilc_free_wiphy(wilc->vif[i]->ndev); - PRINT_INFO(wilc->vif[i]->ndev, INIT_DBG, - "Freeing netdev...\n"); - free_netdev(wilc->vif[i]->ndev); + vif->ndev); + unregister_netdev(vif->ndev); } + } + srcu_read_unlock(&wilc->srcu, srcu_idx); - wilc_wfi_deinit_mon_interface(wilc); - #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - unregister_inetaddr_notifier(&g_dev_notifier); - #endif + wilc_wfi_deinit_mon_interface(wilc, false); flush_workqueue(wilc->hif_workqueue); destroy_workqueue(wilc->hif_workqueue); wilc->hif_workqueue = NULL; + /* update the list */ + do { + mutex_lock(&wilc->vif_mutex); + if (wilc->vif_num <= 0) { + mutex_unlock(&wilc->vif_mutex); + break; + } + vif = wilc_get_wl_to_vif(wilc); + if (!IS_ERR(vif)) + list_del_rcu(&vif->list); + wilc->vif_num--; + mutex_unlock(&wilc->vif_mutex); + synchronize_srcu(&wilc->srcu); + } while (1); + cfg_deinit(wilc); #ifdef WILC_DEBUGFS wilc_debugfs_remove(); @@ -1563,141 +1342,94 @@ void wilc_netdev_cleanup(struct wilc *wilc) wilc_sysfs_exit(); wlan_deinit_locks(wilc); kfree(wilc->bus_data); - kfree(wilc); + wiphy_unregister(wilc->wiphy); + pr_info("Freeing wiphy\n"); + wiphy_free(wilc->wiphy); pr_info("Module_exit Done.\n"); } -int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type, - const struct wilc_hif_func *ops) + +static u8 wilc_get_available_idx(struct wilc *wl) { - int i, ret; + int idx = 0; struct wilc_vif *vif; - struct net_device *ndev; - struct wilc *wl; - struct wireless_dev *wdev; - - wl = kzalloc(sizeof(*wl), GFP_KERNEL); - if (!wl) - return -ENOMEM; - - *wilc = wl; - - wlan_init_locks(wl); + int srcu_idx; - ret = cfg_init(wl); - if (ret) - goto free_locks; - -#ifdef WILC_DEBUGFS - if (wilc_debugfs_init()) { - ret = -ENOMEM; - goto free_cfg; - } -#endif - wl->io_type = io_type; - wl->hif_func = ops; - - for (i = 0; i < NQUEUES; i++) - INIT_LIST_HEAD(&wl->txq[i].txq_head.list); - - INIT_LIST_HEAD(&wl->rxq_head.list); - - wl->hif_workqueue = create_singlethread_workqueue("WILC_wq"); - if (!wl->hif_workqueue) { - ret = -ENOMEM; - goto free_debug_fs; + srcu_idx = srcu_read_lock(&wl->srcu); + list_for_each_entry_rcu(vif, &wl->vif_list, list) { + if (vif->idx == 0) + idx = 1; + else + idx = 0; } + srcu_read_unlock(&wl->srcu, srcu_idx); + return idx; +} -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - register_inetaddr_notifier(&g_dev_notifier); -#endif - - for (i = 0; i < WILC_NUM_CONCURRENT_IFC; i++) { - ndev = alloc_etherdev(sizeof(struct wilc_vif)); - if (!ndev) { - ret = -ENOMEM; - goto free_ndev; - } - - vif = netdev_priv(ndev); +struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, + int iftype, enum nl80211_iftype type, + bool rtnl_locked) +{ + struct net_device *ndev; + struct wilc_vif *vif; + int ret; - if (i == 0) - strcpy(ndev->name, "wlan%d"); - else - strcpy(ndev->name, "p2p%d"); + ndev = alloc_etherdev(sizeof(struct wilc_vif)); + if (!ndev) + return ERR_PTR(-ENOMEM); - vif->idx = wl->vif_num; - vif->wilc = *wilc; - vif->ndev = ndev; - wl->vif[i] = vif; - wl->vif_num = i + 1; + vif = netdev_priv(ndev); - ndev->netdev_ops = &wilc_netdev_ops; + ndev->ieee80211_ptr = &vif->priv.wdev; - wdev = wilc_create_wiphy(ndev, dev); - if (!wdev) { - PRINT_ER(ndev, "Can't register WILC Wiphy\n"); - ret = -ENOMEM; - goto free_ndev; - } + vif->wilc = wl; + vif->ndev = ndev; + ndev->ml_priv = vif; + strcpy(ndev->name, name); + ndev->netdev_ops = &wilc_netdev_ops; - SET_NETDEV_DEV(ndev, dev); + SET_NETDEV_DEV(ndev, wiphy_dev(wl->wiphy)); - vif->ndev->ieee80211_ptr = wdev; - vif->ndev->ml_priv = vif; - wdev->netdev = vif->ndev; - vif->netstats.rx_packets = 0; - vif->netstats.tx_packets = 0; - vif->netstats.rx_bytes = 0; - vif->netstats.tx_bytes = 0; + vif->ndev->ml_priv = vif; + vif->priv.wdev.wiphy = wl->wiphy; + vif->priv.wdev.netdev = ndev; + vif->priv.wdev.iftype = type; + vif->priv.dev = ndev; + vif->priv.dev = ndev; + if (rtnl_locked) + ret = register_netdevice(ndev); + else ret = register_netdev(ndev); - if (ret) { - PRINT_ER(ndev, "Device couldn't be registered - %s\n", - ndev->name); - goto free_ndev; - } - vif->iftype = WILC_STATION_MODE; - vif->mac_opened = 0; - } - wilc_sysfs_init(wl->vif[0], wl->vif[1]); - - return 0; -free_ndev: - for (; i >= 0; i--) { - if (wl->vif[i]) { - if (wl->vif[i]->iftype == WILC_STATION_MODE) - unregister_netdev(wl->vif[i]->ndev); - - if (wl->vif[i]->ndev) { - wilc_free_wiphy(wl->vif[i]->ndev); - free_netdev(wl->vif[i]->ndev); - } - } + if (ret) { + pr_err("Device couldn't be registered - %s\n", ndev->name); + free_netdev(ndev); + return ERR_PTR(-EFAULT); } -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - unregister_inetaddr_notifier(&g_dev_notifier); +#if KERNEL_VERSION(4, 11, 9) <= LINUX_VERSION_CODE + ndev->needs_free_netdev = true; +#else + ndev->destructor = free_netdev; #endif - destroy_workqueue(wl->hif_workqueue); + vif->iftype = iftype; + vif->idx = wilc_get_available_idx(wl); + vif->mac_opened = 0; + mutex_lock(&wl->vif_mutex); + wl->vif_num += 1; + list_add_tail_rcu(&vif->list, &wl->vif_list); + mutex_unlock(&wl->vif_mutex); + synchronize_srcu(&wl->srcu); -free_debug_fs: -#ifdef WILC_DEBUGFS - wilc_debugfs_remove(); -free_cfg: -#endif - cfg_deinit(wl); -free_locks: - wlan_deinit_locks(wl); - kfree(wl); - return ret; + return vif; } #if KERNEL_VERSION(3, 13, 0) < LINUX_VERSION_CODE -static void wilc_wlan_power(struct wilc *wilc, int power) +static int wilc_wlan_power(struct wilc *wilc, int power) { struct gpio_desc *gpio_reset; struct gpio_desc *gpio_chip_en; + int ret = 0; pr_info("wifi_pm : %d\n", power); @@ -1708,7 +1440,7 @@ static void wilc_wlan_power(struct wilc *wilc, int power) if (!gpio_reset) { dev_warn(wilc->dev, "failed to get default Reset GPIO\r\n"); - return; + return -EIO; } } else { dev_info(wilc->dev, "succesfully got gpio_reset\r\n"); @@ -1721,25 +1453,53 @@ static void wilc_wlan_power(struct wilc *wilc, int power) dev_warn(wilc->dev, "failed to get default chip_en GPIO\r\n"); gpiod_put(gpio_reset); - return; + return -EIO; } } else { dev_info(wilc->dev, "succesfully got gpio_chip_en\r\n"); } if (power) { - gpiod_direction_output(gpio_chip_en, 1); + ret = gpiod_direction_output(gpio_chip_en, 1); + if (ret < 0) { + dev_warn(wilc->dev, + "failed to set chip_en GPIO direction\r\n"); + goto out; + ret = -EIO; + } mdelay(5); - gpiod_direction_output(gpio_reset, 1); + ret = gpiod_direction_output(gpio_reset, 1); + if (ret) { + dev_warn(wilc->dev, + "failed to set reset GPIO direction\r\n"); + goto out; + ret = -EIO; + } } else { - gpiod_direction_output(gpio_reset, 0); - gpiod_direction_output(gpio_chip_en, 0); + ret = gpiod_direction_output(gpio_reset, 0); + if (ret) { + dev_warn(wilc->dev, + "failed to set chip_en GPIO direction\r\n"); + goto out; + ret = -EIO; + } + ret = gpiod_direction_output(gpio_chip_en, 0); + if (ret) { + dev_warn(wilc->dev, + "failed to set reset GPIO direction\r\n"); + goto out; + ret = -EIO; + } } + +out: gpiod_put(gpio_chip_en); gpiod_put(gpio_reset); + + return ret; } #else -static void wilc_wlan_power(struct wilc *wilc, int power) +static int wilc_wlan_power(struct wilc *wilc, int power) { int gpio_reset; int gpio_chip_en; @@ -1780,20 +1540,36 @@ static void wilc_wlan_power(struct wilc *wilc, int power) } else { dev_err(wilc->dev, "Error requesting GPIOs for CHIP_EN and RESET"); + return -EIO; } + return 0; } #endif -void wilc_wlan_power_on_sequence(struct wilc *wilc) +int wilc_wlan_power_on_sequence(struct wilc *wilc) { - wilc_wlan_power(wilc, 0); - wilc_wlan_power(wilc, 1); + int ret; + + ret = wilc_wlan_power(wilc, 0); + if (ret) + return ret; + ret = wilc_wlan_power(wilc, 1); + if (ret) + return ret; + + return 0; } -void wilc_wlan_power_off_sequence(struct wilc *wilc) +int wilc_wlan_power_off_sequence(struct wilc *wilc) { - wilc_wlan_power(wilc, 0); + int ret; + + ret = wilc_wlan_power(wilc, 0); + if (ret) + return ret; + + return 0; } MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/mchp/wilc_netdev.h b/drivers/net/wireless/mchp/wilc_netdev.h index d882ea3c0682..f260fac6edf7 100644 --- a/drivers/net/wireless/mchp/wilc_netdev.h +++ b/drivers/net/wireless/mchp/wilc_netdev.h @@ -13,24 +13,9 @@ #include "wilc_wfi_netdevice.h" #include "wilc_wlan_if.h" -#define IP_STATE_OBTAINING 1 -#define IP_STATE_OBTAINED 2 -#define IP_STATE_GO_ASSIGNING 3 -#define IP_STATE_DEFAULT 4 - extern int wait_for_recovery; -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP -void handle_pwrsave_for_IP(struct wilc_vif *vif, uint8_t state); -void store_power_save_current_state(struct wilc_vif *vif, bool val); -#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE -void clear_during_ip(struct timer_list *t); -#else -void clear_during_ip(unsigned long arg); -#endif -#endif //DISABLE_PWRSAVE_AND_SCAN_DURING_IP struct net_device *wilc_get_if_netdev(struct wilc *wilc, uint8_t ifc); -struct host_if_drv *get_drv_hndl_by_ifc(struct wilc *wilc, uint8_t ifc); #if KERNEL_VERSION(3, 14, 0) > LINUX_VERSION_CODE static inline void ether_addr_copy(u8 *dst, const u8 *src) @@ -58,8 +43,15 @@ static inline bool ether_addr_equal_unaligned(const u8 *addr1, const u8 *addr2) } #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */ +#if KERNEL_VERSION(3, 12, 0) > LINUX_VERSION_CODE +#define PTR_ERR_OR_ZERO(ptr) PTR_RET(ptr) +#endif + int wilc_bt_power_up(struct wilc *wilc, int source); int wilc_bt_power_down(struct wilc *wilc, int source); void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size); +struct wilc_vif * +wilc_netdev_ifc_init(struct wilc *wl, const char *name, int iftype, + enum nl80211_iftype type, bool rtnl_locked); #endif /* WILC_NETDEV_H */ diff --git a/drivers/net/wireless/mchp/wilc_sdio.c b/drivers/net/wireless/mchp/wilc_sdio.c index a3fc4fb9f476..8e2bfe6cde7b 100644 --- a/drivers/net/wireless/mchp/wilc_sdio.c +++ b/drivers/net/wireless/mchp/wilc_sdio.c @@ -4,6 +4,7 @@ * All rights reserved. */ +#include #include #include #include @@ -12,6 +13,8 @@ #include "wilc_wfi_netdevice.h" #include "wilc_wlan.h" +#include "wilc_wfi_cfgoperations.h" +#include "wilc_netdev.h" enum sdio_host_lock { WILC_SDIO_HOST_NO_TAKEN = 0, @@ -39,6 +42,7 @@ struct wilc_sdio { u32 block_size; int nint; bool is_init; + struct wilc *wl; }; struct sdio_cmd52 { @@ -134,7 +138,7 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) } static int wilc_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) + const struct sdio_device_id *id) { struct wilc *wilc; int ret, io_type; @@ -150,7 +154,7 @@ static int wilc_sdio_probe(struct sdio_func *func, else io_type = WILC_HIF_SDIO; dev_dbg(&func->dev, "Initializing netdev\n"); - ret = wilc_netdev_init(&wilc, &func->dev, io_type, &wilc_hif_sdio); + ret = wilc_cfg80211_init(&wilc, &func->dev, io_type, &wilc_hif_sdio); if (ret) { dev_err(&func->dev, "Couldn't initialize netdev\n"); kfree(sdio_priv); @@ -160,9 +164,21 @@ static int wilc_sdio_probe(struct sdio_func *func, wilc->bus_data = sdio_priv; wilc->dev = &func->dev; wilc->dt_dev = &func->card->dev; + sdio_priv->wl = wilc; + + wilc->rtc_clk = devm_clk_get(&func->card->dev, "rtc_clk"); + if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else if (!IS_ERR(wilc->rtc_clk)) + clk_prepare_enable(wilc->rtc_clk); if (!init_power) { - wilc_wlan_power_on_sequence(wilc); + ret = wilc_wlan_power_on_sequence(wilc); + if (ret) { + wilc_netdev_cleanup(wilc); + kfree(sdio_priv); + return ret; + } init_power = 1; } @@ -176,6 +192,9 @@ static void wilc_sdio_remove(struct sdio_func *func) { struct wilc *wilc = sdio_get_drvdata(func); + if (!IS_ERR(wilc->rtc_clk)) + clk_disable_unprepare(wilc->rtc_clk); + wilc_netdev_cleanup(wilc); wilc_bt_deinit(); } @@ -1155,4 +1174,5 @@ module_driver(wilc_sdio_driver, sdio_register_driver, sdio_unregister_driver); MODULE_LICENSE("GPL"); +MODULE_VERSION("15.3"); diff --git a/drivers/net/wireless/mchp/wilc_spi.c b/drivers/net/wireless/mchp/wilc_spi.c index c20fbf45a7e7..db9cf2d20859 100644 --- a/drivers/net/wireless/mchp/wilc_spi.c +++ b/drivers/net/wireless/mchp/wilc_spi.c @@ -4,10 +4,13 @@ * All rights reserved. */ +#include #include #include #include "wilc_wfi_netdevice.h" +#include "wilc_wfi_cfgoperations.h" +#include "wilc_netdev.h" struct wilc_spi { int crc_off; @@ -123,7 +126,7 @@ static int wilc_bus_probe(struct spi_device *spi) if (!spi_priv) return -ENOMEM; - ret = wilc_netdev_init(&wilc, dev, WILC_HIF_SPI, &wilc_hif_spi); + ret = wilc_cfg80211_init(&wilc, dev, WILC_HIF_SPI, &wilc_hif_spi); if (ret) { kfree(spi_priv); return ret; @@ -134,9 +137,19 @@ static int wilc_bus_probe(struct spi_device *spi) wilc->bus_data = spi_priv; wilc->dt_dev = &spi->dev; + wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk"); + if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else if (!IS_ERR(wilc->rtc_clk)) + clk_prepare_enable(wilc->rtc_clk); if (!init_power) { - wilc_wlan_power_on_sequence(wilc); + ret = wilc_wlan_power_on_sequence(wilc); + if (ret) { + wilc_netdev_cleanup(wilc); + kfree(spi_priv); + return ret; + } init_power = 1; } @@ -150,6 +163,9 @@ static int wilc_bus_remove(struct spi_device *spi) { struct wilc *wilc = spi_get_drvdata(spi); + if (!IS_ERR(wilc->rtc_clk)) + clk_disable_unprepare(wilc->rtc_clk); + wilc_netdev_cleanup(wilc); wilc_bt_deinit(); return 0; @@ -222,6 +238,7 @@ static struct spi_driver wilc_spi_driver = { }; module_spi_driver(wilc_spi_driver); MODULE_LICENSE("GPL"); +MODULE_VERSION("15.3"); static int spi_data_rsp(struct wilc *wilc, u8 cmd) { @@ -524,7 +541,11 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, rsp = rb[rix++]; - if (rsp != cmd) { + /* + * Clockless registers operations might return unexptected responses, + * even if successful. + */ + if (rsp != cmd && !clockless) { dev_err(&spi->dev, "Failed cmd response, cmd (%02x), resp (%02x)\n", cmd, rsp); @@ -535,7 +556,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, * State response */ rsp = rb[rix++]; - if (rsp != 0x00) { + if (rsp != 0x00 && !clockless) { dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", rsp); return N_FAIL; @@ -562,7 +583,7 @@ static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz, break; } while (retry--); - if (retry <= 0) { + if (retry <= 0 && !clockless) { dev_err(&spi->dev, "Error, data read response (%02x)\n", rsp); return N_RESET; diff --git a/drivers/net/wireless/mchp/wilc_wfi_cfgoperations.c b/drivers/net/wireless/mchp/wilc_wfi_cfgoperations.c index 4693ad9c264f..4553637aafb8 100644 --- a/drivers/net/wireless/mchp/wilc_wfi_cfgoperations.c +++ b/drivers/net/wireless/mchp/wilc_wfi_cfgoperations.c @@ -57,7 +57,7 @@ static const struct ieee80211_txrx_stypes BIT(IEEE80211_STYPE_DISASSOC >> 4) | BIT(IEEE80211_STYPE_AUTH >> 4) | BIT(IEEE80211_STYPE_DEAUTH >> 4) - } + }, }; static const struct wiphy_wowlan_support wowlan_support = { @@ -77,8 +77,10 @@ static void cfg_scan_result(enum scan_event scan_event, { struct wilc_priv *priv = user_void; - if (!priv->cfg_scanning) + if (!priv || !priv->cfg_scanning) { + pr_err("%s is NULL\n", __func__); return; + } if (scan_event == SCAN_EVENT_NETWORK_FOUND) { s32 freq; @@ -153,6 +155,9 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, struct wilc_vif *vif = netdev_priv(dev); struct host_if_drv *wfi_drv = priv->hif_drv; struct wilc_conn_info *conn_info = &wfi_drv->conn_info; +#if KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; +#endif vif->connecting = false; @@ -174,7 +179,7 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, } if (connect_status == WLAN_STATUS_SUCCESS) { - PRINT_ER(dev, + PRINT_INFO(vif->ndev, CFG80211_DBG, "Connection Successful: BSSID: %x%x%x%x%x%x\n", conn_info->bssid[0], conn_info->bssid[1], conn_info->bssid[2], conn_info->bssid[3], @@ -189,18 +194,36 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, PRINT_INFO(vif->ndev, CFG80211_DBG, "Association response info elements length = %d\n", conn_info->resp_ies_len); +#if KERNEL_VERSION(4, 11, 0) <= LINUX_VERSION_CODE + cfg80211_ref_bss(wiphy, vif->bss); + cfg80211_connect_bss(dev, conn_info->bssid, vif->bss, + conn_info->req_ies, + conn_info->req_ies_len, + conn_info->resp_ies, + conn_info->resp_ies_len, + connect_status, GFP_KERNEL, + NL80211_TIMEOUT_UNSPECIFIED); +#elif KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE + cfg80211_ref_bss(wiphy, vif->bss); + cfg80211_connect_bss(dev, conn_info->bssid, vif->bss, + conn_info->req_ies, + conn_info->req_ies_len, + conn_info->resp_ies, + conn_info->resp_ies_len, + connect_status, GFP_KERNEL); +#else cfg80211_connect_result(dev, conn_info->bssid, conn_info->req_ies, conn_info->req_ies_len, conn_info->resp_ies, conn_info->resp_ies_len, connect_status, GFP_KERNEL); +#endif + vif->bss = NULL; } else if (conn_disconn_evt == EVENT_DISCONN_NOTIF) { u16 reason = 0; -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - vif->obtaining_ip = false; -#endif - PRINT_ER(vif->ndev, + + PRINT_INFO(vif->ndev, CFG80211_DBG, "Received WILC_MAC_STATUS_DISCONNECTED dev [%p]\n", priv->dev); priv->p2p.local_random = 0x01; @@ -225,33 +248,52 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, } } +struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl) +{ + struct wilc_vif *vif; + + vif = list_first_or_null_rcu(&wl->vif_list, typeof(*vif), list); + if (!vif) + return ERR_PTR(-EINVAL); + + return vif; +} + static int set_channel(struct wiphy *wiphy, struct cfg80211_chan_def *chandef) { + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; u32 channelnum = 0; - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); int result = 0; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) { + srcu_read_unlock(&wl->srcu, srcu_idx); + return 0; + } channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq); PRINT_INFO(vif->ndev, CFG80211_DBG, "Setting channel %d with frequency %d\n", channelnum, chandef->chan->center_freq); - vif->wilc->op_ch = channelnum; + wl->op_ch = channelnum; result = wilc_set_mac_chnl_num(vif, channelnum); - if (result != 0) - PRINT_ER(priv->dev, "Error in setting channel %d\n", + PRINT_ER(vif->ndev, "Error in setting channel %d\n", channelnum); + srcu_read_unlock(&wl->srcu, srcu_idx); return result; } static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(request->wdev->netdev); + struct wilc_priv *priv = &vif->priv; u32 i; int ret = 0; u8 scan_ch_list[WILC_MAX_NUM_SCANNED_CH]; @@ -305,8 +347,8 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) static int connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; struct host_if_drv *wfi_drv = priv->hif_drv; int ret; u32 i; @@ -451,7 +493,6 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, ret = -EINVAL; goto out_error; } - if (ether_addr_equal_unaligned(vif->bssid, bss->bssid)) { ret = -EALREADY; goto out_put_bss; @@ -464,7 +505,6 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, ret = -EINVAL; goto out_put_bss; } - ch = ieee80211_frequency_to_channel(bss->channel->center_freq); PRINT_D(vif->ndev, CFG80211_DBG, "Required Channel = %d\n", ch); vif->wilc->op_ch = ch; @@ -492,6 +532,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, goto out_put_bss; } kfree(join_params); + vif->bss = bss; cfg80211_put_bss(wiphy, bss); return 0; @@ -506,8 +547,8 @@ out_error: static int disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; struct wilc *wilc = vif->wilc; struct host_if_drv *wfi_drv; int ret; @@ -534,6 +575,8 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev, ret = -EINVAL; } + vif->bss = NULL; + return ret; } @@ -595,13 +638,13 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, { int ret = 0, keylen = params->key_len; - struct wilc_priv *priv = wiphy_priv(wiphy); const u8 *rx_mic = NULL; const u8 *tx_mic = NULL; u8 mode = WILC_FW_SEC_NO; u8 op_mode; int i; struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; PRINT_INFO(vif->ndev, CFG80211_DBG, "Adding key with cipher suite = %x\n", params->cipher); @@ -613,7 +656,7 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, switch (params->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: - if (priv->wdev->iftype == NL80211_IFTYPE_AP) { + if (priv->wdev.iftype == NL80211_IFTYPE_AP) { wilc_wfi_cfg_copy_wep_info(priv, key_index, params); PRINT_INFO(vif->ndev, CFG80211_DBG, @@ -658,8 +701,8 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: - if (priv->wdev->iftype == NL80211_IFTYPE_AP || - priv->wdev->iftype == NL80211_IFTYPE_P2P_GO) { + if (priv->wdev.iftype == NL80211_IFTYPE_AP || + priv->wdev.iftype == NL80211_IFTYPE_P2P_GO) { struct wilc_wfi_key *key; ret = wilc_wfi_cfg_allocate_wpa_entry(priv, key_index); @@ -737,11 +780,11 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac_addr) { int ret = 0; - struct wilc_priv *priv = wiphy_priv(wiphy); struct wilc_vif *vif = netdev_priv(netdev); - struct wilc *wl = vif->wilc; + struct wilc_priv *priv = &vif->priv; - if (netdev == wl->vif[0]->ndev) { + //TODO: Why to compare with only interface vif[0] + //if (netdev == wl->vif[0]->ndev) { if (priv->wilc_gtk[key_index]) { kfree(priv->wilc_gtk[key_index]->key); priv->wilc_gtk[key_index]->key = NULL; @@ -760,14 +803,13 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev, kfree(priv->wilc_ptk[key_index]); priv->wilc_ptk[key_index] = NULL; } - } + //} if (key_index <= 3 && priv->wep_key_len[key_index]) { memset(priv->wep_key[key_index], 0, priv->wep_key_len[key_index]); priv->wep_key_len[key_index] = 0; - PRINT_INFO(vif->ndev, CFG80211_DBG, - "Removing WEP key with index = %d\n", + pr_info("%s: Removing WEP key with index = %d\n", __func__, key_index); ret = wilc_remove_wep_key(vif, key_index); } @@ -779,9 +821,9 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr, void *cookie, void (*callback)(void *cookie, struct key_params *)) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct key_params key_params; struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; + struct key_params key_params; if (!pairwise) { PRINT_INFO(vif->ndev, CFG80211_DBG, @@ -808,8 +850,7 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, static int set_default_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool unicast, bool multicast) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(netdev); wilc_set_wep_default_keyid(vif, key_index); @@ -824,8 +865,8 @@ static int get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo) #endif { - struct wilc_priv *priv = wiphy_priv(wiphy); struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; struct wilc *wilc = vif->wilc; u32 i = 0; u32 associatedsta = ~0; @@ -911,8 +952,19 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) { int ret; struct cfg_param_attr cfg_param_val; - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + struct wilc_priv *priv; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) { + srcu_read_unlock(&wl->srcu, srcu_idx); + return 0; + } + + priv = &vif->priv; cfg_param_val.flag = 0; PRINT_INFO(vif->ndev, CFG80211_DBG, "Setting Wiphy params\n"); @@ -942,7 +994,8 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) } else { PRINT_ER(vif->ndev, "Fragmentation threshold out of range\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } } @@ -955,7 +1008,8 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) cfg_param_val.rts_threshold = wiphy->rts_threshold; } else { PRINT_ER(vif->ndev, "RTS threshold out of range\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } } @@ -965,14 +1019,17 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) if (ret) PRINT_ER(priv->dev, "Error in setting WIPHY PARAMS\n"); +out: + srcu_read_unlock(&wl->srcu, srcu_idx); + return ret; } static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev, struct cfg80211_pmksa *pmksa) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; u32 i; int ret = 0; u8 flag = 0; @@ -1015,7 +1072,8 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev, { u32 i; int ret = 0; - struct wilc_priv *priv = wiphy_priv(wiphy); + struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; PRINT_INFO(netdev, CFG80211_DBG, "Deleting PMKSA keys\n"); @@ -1049,7 +1107,8 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev, static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) { - struct wilc_priv *priv = wiphy_priv(wiphy); + struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; PRINT_INFO(netdev, CFG80211_DBG, "Flushing PMKID key values\n"); memset(&priv->pmkid_list, 0, sizeof(struct wilc_pmkid_attr)); @@ -1067,9 +1126,6 @@ static inline void wilc_wfi_cfg_parse_ch_attr(struct wilc_vif *vif, u8 *buf, if (ch_list_attr_idx) { u8 limit = ch_list_attr_idx + 3 + buf[ch_list_attr_idx + 1]; - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Modify channel list attribute [%d]\n", - sta_ch); for (i = ch_list_attr_idx + 3; i < limit; i++) { if (buf[i] == 0x51) { for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++) @@ -1080,9 +1136,6 @@ static inline void wilc_wfi_cfg_parse_ch_attr(struct wilc_vif *vif, u8 *buf, } if (op_ch_attr_idx) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Modify operating channel attribute %d\n", - sta_ch); buf[op_ch_attr_idx + 6] = 0x51; buf[op_ch_attr_idx + 7] = sta_ch; } @@ -1179,7 +1232,7 @@ static void wilc_wfi_cfg_parse_rx_vendor_spec(struct wilc_priv *priv, u8 *buff, for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < size; i++) { if (buff[i] == P2PELEM_ATTR_ID && !(memcmp(p2p_oui, &buff[i + 2], 4))) { - bool p2p_mode = vif->attr_sysfs.p2p_mode; + bool p2p_mode = vif->wilc->attr_sysfs.p2p_mode; wilc_wfi_cfg_parse_rx_action(vif, &buff[i + 6], size - (i + 6), @@ -1191,17 +1244,17 @@ static void wilc_wfi_cfg_parse_rx_vendor_spec(struct wilc_priv *priv, u8 *buff, } } -void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size) +bool wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size) { - struct wilc_priv *priv = wiphy_priv(dev->ieee80211_ptr->wiphy); - struct host_if_drv *wfi_drv = priv->hif_drv; - struct wilc_vif *vif = netdev_priv(dev); struct wilc *wl = vif->wilc; + struct wilc_priv *priv = &vif->priv; + struct host_if_drv *wfi_drv = priv->hif_drv; u32 header, pkt_offset; s32 freq; __le16 fc; + int ret; - memcpy(&header, (buff - HOST_HDR_OFFSET), HOST_HDR_OFFSET); + header = get_unaligned_le32(buff - HOST_HDR_OFFSET); pkt_offset = GET_PKT_OFFSET(header); @@ -1213,9 +1266,9 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size) pkt_offset & IS_MGMT_STATUS_SUCCES) ack = true; - cfg80211_mgmt_tx_status(priv->wdev, priv->tx_cookie, buff, size, - ack, GFP_KERNEL); - return; + cfg80211_mgmt_tx_status(&vif->priv.wdev, priv->tx_cookie, buff, + size, ack, GFP_KERNEL); + return true; } PRINT_D(vif->ndev, GENERIC_DBG, "Rx Frame Type:%x\n", fc); @@ -1226,8 +1279,8 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size) freq = ieee80211_channel_to_frequency(wl->op_ch, IEEE80211_BAND_2GHZ); #endif if (!ieee80211_is_action(fc)) { - cfg80211_rx_mgmt(priv->wdev, freq, 0, buff, size, 0); - return; + ret = cfg80211_rx_mgmt(&vif->priv.wdev, freq, 0, buff, size, 0); + return ret; } PRINT_D(vif->ndev, GENERIC_DBG, @@ -1236,8 +1289,9 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size) buff[P2P_PUB_ACTION_SUBTYPE]); if (priv->cfg_scanning && time_after_eq(jiffies, (unsigned long)wfi_drv->p2p_timeout)) { - PRINT_WRN(dev, GENERIC_DBG, "Receiving action wrong ch\n"); - return; + PRINT_WRN(vif->ndev, GENERIC_DBG, + "Receiving action wrong ch\n"); + return false; } if (buff[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) { u8 subtype = buff[P2P_PUB_ACTION_SUBTYPE]; @@ -1267,14 +1321,13 @@ void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size) break; default: - PRINT_WRN(dev, GENERIC_DBG, - "Not handled action frame type:%x\n", + pr_err("Not handled action frame type:%x\n", buff[ACTION_SUBTYPE_ID]); break; } } - - cfg80211_rx_mgmt(priv->wdev, freq, 0, buff, size, 0); + ret = cfg80211_rx_mgmt(&vif->priv.wdev, freq, 0, buff, size, 0); + return ret; } static void wilc_wfi_mgmt_tx_complete(void *priv, int status) @@ -1287,7 +1340,8 @@ static void wilc_wfi_mgmt_tx_complete(void *priv, int status) static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie) { - struct wilc_priv *priv = data; + struct wilc_vif *vif = data; + struct wilc_priv *priv = &vif->priv; struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params; if (cookie != priv->remain_on_ch_params.listen_cookie) { @@ -1297,9 +1351,9 @@ static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie) return; } - priv->p2p_listen_state = false; + vif->p2p_listen_state = false; - cfg80211_remain_on_channel_expired(priv->wdev, cookie, + cfg80211_remain_on_channel_expired(&vif->priv.wdev, cookie, params->listen_ch, GFP_KERNEL); } @@ -1309,16 +1363,12 @@ static int remain_on_channel(struct wiphy *wiphy, unsigned int duration, u64 *cookie) { int ret = 0; - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc_priv *priv = &vif->priv; u64 id; - PRINT_INFO(vif->ndev, GENERIC_DBG, "Remaining on channel [%d]\n", - chan->hw_value); - if (wdev->iftype == NL80211_IFTYPE_AP) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Required while in AP mode\n"); + pr_err("Required while in AP mode\n"); return ret; } @@ -1328,7 +1378,7 @@ static int remain_on_channel(struct wiphy *wiphy, ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value, wilc_wfi_remain_on_channel_expired, - (void *)priv); + (void *)vif); if (ret) return ret; @@ -1337,20 +1387,18 @@ static int remain_on_channel(struct wiphy *wiphy, priv->remain_on_ch_params.listen_cookie = id; *cookie = id; priv->remain_on_ch_params.listen_duration = duration; - priv->p2p_listen_state = true; - + vif->p2p_listen_state = true; cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_KERNEL); #if KERNEL_VERSION(4, 15, 0) > LINUX_VERSION_CODE vif->hif_drv->remain_on_ch_timer.data = (unsigned long)vif->hif_drv; #endif mod_timer(&vif->hif_drv->remain_on_ch_timer, - jiffies + msecs_to_jiffies(duration)); + jiffies + msecs_to_jiffies(duration + 1000)); PRINT_INFO(vif->ndev, GENERIC_DBG, "Remaining on duration [%d] [%llu]\n", duration, priv->remain_on_ch_params.listen_cookie); - return ret; } @@ -1358,8 +1406,8 @@ static int cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc_priv *priv = &vif->priv; PRINT_INFO(vif->ndev, CFG80211_DBG, "cookie received[%llu] expected[%llu]\n", @@ -1410,6 +1458,7 @@ static void wilc_wfi_cfg_tx_vendor_spec(struct wilc_priv *priv, if (buf[i] == P2PELEM_ATTR_ID && !memcmp(p2p_oui, &buf[i + 2], 4)) { bool oper_ch = false; + struct wilc *wl = vif->wilc; u8 *tx_buff = &mgmt_tx->buff[i + 6]; if (subtype == P2P_INV_REQ || subtype == P2P_INV_RSP) @@ -1417,8 +1466,8 @@ static void wilc_wfi_cfg_tx_vendor_spec(struct wilc_priv *priv, wilc_wfi_cfg_parse_tx_action(vif, tx_buff, len - (i + 6), oper_ch, - vif->wilc->sta_ch, - vif->attr_sysfs.p2p_mode); + wl->sta_ch, + wl->attr_sysfs.p2p_mode); break; } } @@ -1454,9 +1503,9 @@ static int mgmt_tx(struct wiphy *wiphy, #endif const struct ieee80211_mgmt *mgmt; struct wilc_p2p_mgmt_data *mgmt_tx; - struct wilc_priv *priv = wiphy_priv(wiphy); - struct host_if_drv *wfi_drv = priv->hif_drv; struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc_priv *priv = &vif->priv; + struct host_if_drv *wfi_drv = priv->hif_drv; u32 buf_len = len + sizeof(p2p_vendor_spec) + sizeof(priv->p2p.local_random); int ret = 0; @@ -1552,7 +1601,6 @@ static int mgmt_tx(struct wiphy *wiphy, break; } } - PRINT_INFO(vif->ndev, GENERIC_DBG, "TX: ACTION FRAME Type:%x : Chan:%d\n", buf[ACTION_SUBTYPE_ID], chan->hw_value); @@ -1560,7 +1608,8 @@ static int mgmt_tx(struct wiphy *wiphy, out_txq_add_pkt: - txq_add_mgmt_pkt(wdev->netdev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size, + txq_add_mgmt_pkt(priv->wdev.netdev, mgmt_tx, + mgmt_tx->buff, mgmt_tx->size, wilc_wfi_mgmt_tx_complete); out: @@ -1572,17 +1621,18 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie) { - struct wilc_priv *priv = wiphy_priv(wiphy); + struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc_priv *priv = &vif->priv; struct host_if_drv *wfi_drv = priv->hif_drv; wfi_drv->p2p_timeout = jiffies; - if (!priv->p2p_listen_state) { + if (!vif->p2p_listen_state) { struct wilc_wfi_p2p_listen_params *params; params = &priv->remain_on_ch_params; - cfg80211_remain_on_channel_expired(priv->wdev, + cfg80211_remain_on_channel_expired(wdev, params->listen_cookie, params->listen_ch, GFP_KERNEL); @@ -1594,14 +1644,13 @@ static int mgmt_tx_cancel_wait(struct wiphy *wiphy, void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, u16 frame_type, bool reg) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->wdev->netdev); - struct wilc *wl = vif->wilc; + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif = netdev_priv(wdev->netdev); if (!frame_type) return; - PRINT_INFO(vif->ndev, GENERIC_DBG, + PRINT_D(vif->ndev, GENERIC_DBG, "Frame registering Frame Type: %x: Boolean: %d\n", frame_type, reg); switch (frame_type) { @@ -1637,8 +1686,7 @@ static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev, static int dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(dev); int ret; if (idx != 0) @@ -1662,28 +1710,15 @@ static int dump_station(struct wiphy *wiphy, struct net_device *dev, static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; + PRINT_INFO(vif->ndev, GENERIC_DBG, "dev [%s]\n", dev->name); if (!priv->hif_drv) { PRINT_ER(dev, "hif driver is NULL\n"); return -EIO; } -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - /* Can't set PS during obtaining IP */ - if (vif->obtaining_ip == true) { - PRINT_ER(dev, - "Device obtaining IP, Power Managment will be handled after IP Obtained\n"); - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Save the Current state of the PS = %d\n", enabled); - - /* Save the current status of the PS */ - store_power_save_current_state(vif, enabled); - - return 0; - } -#endif PRINT_INFO(vif->ndev, CFG80211_DBG, " Power save Enabled= %d , TimeOut = %d\n", enabled, timeout); @@ -1703,13 +1738,9 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, struct vif_params *params) #endif { - struct wilc_priv *priv = wiphy_priv(wiphy); + struct wilc *wl = wiphy_priv(wiphy); struct wilc_vif *vif = netdev_priv(dev); - struct wilc *wl = vif->wilc; - struct net_device *net_device_1 = wilc_get_if_netdev(wl, WILC_P2P_IFC); - struct net_device *net_device_2 = wilc_get_if_netdev(wl, WILC_WLAN_IFC); - struct wilc_vif *vif_1 = netdev_priv(net_device_1); - struct wilc_vif *vif_2 = netdev_priv(net_device_2); + struct wilc_priv *priv = &vif->priv; PRINT_INFO(vif->ndev, HOSTAPD_DBG, "In Change virtual interface function\n"); @@ -1718,11 +1749,6 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, priv->p2p.local_random = 0x01; priv->p2p.recv_random = 0x00; priv->p2p.is_wilc_ie = false; -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Changing virtual interface, enable scan\n"); - handle_pwrsave_for_IP(vif, IP_STATE_DEFAULT); -#endif switch (type) { case NL80211_IFTYPE_STATION: @@ -1730,18 +1756,18 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, PRINT_INFO(vif->ndev, HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_STATION\n"); dev->ieee80211_ptr->iftype = type; - priv->wdev->iftype = type; + priv->wdev.iftype = type; vif->monitor_flag = 0; + if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) + wilc_wfi_deinit_mon_interface(wl, true); vif->iftype = WILC_STATION_MODE; - wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), - WILC_STATION_MODE, vif->ifc_id); - wilc_set_operation_mode(vif, WILC_STATION_MODE); + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_STATION_MODE, vif->idx); memset(priv->assoc_stainfo.sta_associated_bss, 0, WILC_MAX_NUM_STA * ETH_ALEN); - - wilc_set_power_mgmt(vif_1, 1, 0); - wilc_set_power_mgmt(vif_2, 1, 0); break; case NL80211_IFTYPE_P2P_CLIENT: @@ -1749,30 +1775,25 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, PRINT_INFO(vif->ndev, HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_P2P_CLIENT\n"); dev->ieee80211_ptr->iftype = type; - priv->wdev->iftype = type; + priv->wdev.iftype = type; vif->monitor_flag = 0; vif->iftype = WILC_CLIENT_MODE; - wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), - WILC_STATION_MODE, vif->ifc_id); - wilc_set_operation_mode(vif, WILC_STATION_MODE); - wilc_set_power_mgmt(vif_1, 0, 0); - wilc_set_power_mgmt(vif_2, 0, 0); + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_STATION_MODE, vif->idx); break; case NL80211_IFTYPE_AP: PRINT_INFO(vif->ndev, HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_AP\n"); dev->ieee80211_ptr->iftype = type; - priv->wdev->iftype = type; + priv->wdev.iftype = type; vif->iftype = WILC_AP_MODE; - if (wl->initialized) { - wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), - WILC_AP_MODE, vif->ifc_id); - wilc_set_operation_mode(vif, WILC_AP_MODE); - wilc_set_power_mgmt(vif_1, 0, 0); - wilc_set_power_mgmt(vif_2, 0, 0); - } + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_AP_MODE, vif->idx); break; case NL80211_IFTYPE_P2P_GO: @@ -1780,34 +1801,26 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, "Interface type = NL80211_IFTYPE_GO\n"); PRINT_INFO(vif->ndev, GENERIC_DBG, "start duringIP timer\n"); -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - handle_pwrsave_for_IP(vif, IP_STATE_GO_ASSIGNING); -#endif dev->ieee80211_ptr->iftype = type; - priv->wdev->iftype = type; + priv->wdev.iftype = type; vif->iftype = WILC_GO_MODE; - wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), - WILC_AP_MODE, vif->ifc_id); - wilc_set_operation_mode(vif, WILC_AP_MODE); - wilc_set_power_mgmt(vif_1, 0, 0); - wilc_set_power_mgmt(vif_2, 0, 0); + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_AP_MODE, vif->idx); break; case NL80211_IFTYPE_MONITOR: PRINT_INFO(vif->ndev, HOSTAPD_DBG, "Interface type = NL80211_IFTYPE_MONITOR\n"); dev->ieee80211_ptr->iftype = type; dev->type = ARPHRD_IEEE80211_RADIOTAP; - priv->wdev->iftype = type; + priv->wdev.iftype = type; vif->iftype = WILC_MONITOR_MODE; - if (wl->initialized) { - wilc_set_wfi_drv_handler(vif, wilc_get_vif_idx(vif), - WILC_MONITOR_MODE, - vif->ifc_id); - wilc_set_operation_mode(vif, WILC_MONITOR_MODE); - wilc_set_power_mgmt(vif_1, 0, 0); - wilc_set_power_mgmt(vif_2, 0, 0); - } + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_MONITOR_MODE, + vif->idx); break; default: @@ -1821,22 +1834,25 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, static int start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings) { - struct wilc_vif *vif = netdev_priv(dev); int ret; + struct wilc_vif *vif = netdev_priv(dev); + int freq = settings->chandef.chan->center_freq; + int channelnum = ieee80211_frequency_to_channel(freq); + + pr_info("%s,dev[%s]\n", __func__, dev->name); PRINT_INFO(vif->ndev, HOSTAPD_DBG, "Starting ap\n"); PRINT_INFO(vif->ndev, CFG80211_DBG, - "Interval= %d\n DTIM period= %d\n Head length= %d Tail length= %d\n", + "Interval= %d\n DTIM period= %d\n Head length= %d Tail length= %d channelnum[%d]\n", settings->beacon_interval, settings->dtim_period, - settings->beacon.head_len, settings->beacon.tail_len); - ret = set_channel(wiphy, &settings->chandef); - + settings->beacon.head_len, settings->beacon.tail_len, + channelnum); + ret = wilc_set_mac_chnl_num(vif, channelnum); if (ret != 0) PRINT_ER(dev, "Error in setting channel\n"); wilc_wlan_set_bssid(dev, dev->dev_addr, WILC_AP_MODE); - wilc_set_power_mgmt(vif, 0, 0); return wilc_add_beacon(vif, settings->beacon_interval, settings->dtim_period, &settings->beacon); @@ -1845,8 +1861,7 @@ static int start_ap(struct wiphy *wiphy, struct net_device *dev, static int change_beacon(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_beacon_data *beacon) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(dev); PRINT_INFO(vif->ndev, HOSTAPD_DBG, "Setting beacon\n"); @@ -1856,8 +1871,7 @@ static int change_beacon(struct wiphy *wiphy, struct net_device *dev, static int stop_ap(struct wiphy *wiphy, struct net_device *dev) { int ret; - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(dev); PRINT_INFO(vif->ndev, CFG80211_DBG, "Deleting beacon\n"); @@ -1867,7 +1881,6 @@ static int stop_ap(struct wiphy *wiphy, struct net_device *dev) if (ret) PRINT_ER(dev, "Host delete beacon fail\n"); - return ret; } @@ -1880,8 +1893,8 @@ static int add_station(struct wiphy *wiphy, struct net_device *dev, #endif { int ret = 0; - struct wilc_priv *priv = wiphy_priv(wiphy); struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; u8 *assoc_bss = priv->assoc_stainfo.sta_associated_bss[params->aid]; if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) { @@ -1946,8 +1959,8 @@ static int del_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac = params->mac; #endif int ret = 0; - struct wilc_priv *priv = wiphy_priv(wiphy); struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; struct sta_info *info; if (!(vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)) @@ -2025,6 +2038,17 @@ static int change_station(struct wiphy *wiphy, struct net_device *dev, return ret; } +struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type) +{ + struct wilc_vif *vif; + + list_for_each_entry_rcu(vif, &wl->vif_list, list) { + if (vif->iftype == type) + return vif; + } + return NULL; +} + #if KERNEL_VERSION(4, 12, 0) <= LINUX_VERSION_CODE static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy, const char *name, @@ -2052,80 +2076,161 @@ static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy, struct vif_params *params) #endif { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->wdev->netdev); - struct net_device *new_ifc; - - PRINT_INFO(vif->ndev, CFG80211_DBG, "Adding monitor interface[%p]\n", - priv->wdev->netdev); + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + struct wireless_dev *wdev; + u8 iftype; + /* check if interface type is mointor because AP mode is supported over + * monitor interface. No need to increment interface count check if + * monitor mode is associated with AP interface. The same approach is + * applied with p2p_device interface + */ if (type == NL80211_IFTYPE_MONITOR) { + struct wilc_vif *vif; + struct net_device *ndev; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_vif_from_type(wl, WILC_AP_MODE); + + if (!vif) { + vif = wilc_get_vif_from_type(wl, WILC_GO_MODE); + if (!vif) { + srcu_read_unlock(&wl->srcu, srcu_idx); + goto validate_interface; + } + } + + if (vif->monitor_flag) { + srcu_read_unlock(&wl->srcu, srcu_idx); + goto validate_interface; + } PRINT_INFO(vif->ndev, CFG80211_DBG, "Initializing mon ifc virtual device driver\n"); PRINT_INFO(vif->ndev, CFG80211_DBG, "Adding monitor interface[%p]\n", vif->ndev); - new_ifc = wilc_wfi_init_mon_interface(vif->wilc, name, - vif->ndev); - if (new_ifc) { + ndev = wilc_wfi_init_mon_interface(vif->wilc, name, vif->ndev); + if (ndev) { PRINT_INFO(vif->ndev, CFG80211_DBG, "Setting monitor flag in private structure\n"); - vif = netdev_priv(priv->wdev->netdev); vif->monitor_flag = 1; } else { PRINT_ER(vif->ndev, "Error in initializing monitor interface\n"); } + wdev = &vif->priv.wdev; + srcu_read_unlock(&wl->srcu, srcu_idx); + return wdev; + } + +validate_interface: + mutex_lock(&wl->vif_mutex); + if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) { + pr_err("Reached maximum number of supported vif\n"); + mutex_unlock(&wl->vif_mutex); + return ERR_PTR(-EINVAL); + } + mutex_unlock(&wl->vif_mutex); + + pr_info("add_interaface [%d] name[%s] type[%d]\n", wl->vif_num, + name, type); + + switch (type) { + case NL80211_IFTYPE_STATION: + iftype = WILC_STATION_MODE; + break; + case NL80211_IFTYPE_AP: + iftype = WILC_AP_MODE; + break; + case NL80211_IFTYPE_MONITOR: + iftype = WILC_MONITOR_MODE; + break; + default: + return ERR_PTR(-EINVAL); } - return priv->wdev; + + vif = wilc_netdev_ifc_init(wl, name, iftype, type, true); + if (IS_ERR(vif)) + return ERR_PTR(-EINVAL); + + return &vif->priv.wdev; } static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { - struct wilc_priv *priv = wiphy_priv(wiphy); + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; - PRINT_INFO(priv->dev, HOSTAPD_DBG, "Deleting virtual interface\n"); + /* delete the monitor mode interface */ + if (wdev->iftype == NL80211_IFTYPE_MONITOR) { + wilc_wfi_deinit_mon_interface(wl, true); + return 0; + } + /* delete the AP monitor mode interface */ + if (wdev->iftype == NL80211_IFTYPE_AP || + wdev->iftype == NL80211_IFTYPE_P2P_GO) + wilc_wfi_deinit_mon_interface(wl, true); + vif = netdev_priv(wdev->netdev); + unregister_netdevice(vif->ndev); + vif->monitor_flag = 0; + + /* update the vif list */ + mutex_lock(&wl->vif_mutex); + //delete the interface from rcu list + list_del_rcu(&vif->list); + wl->vif_num--; + mutex_unlock(&wl->vif_mutex); + synchronize_srcu(&wl->srcu); return 0; } static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) { - struct wilc_priv *priv = wiphy_priv(wiphy); - - if (!wow) - PRINT_INFO(priv->dev, GENERIC_DBG, - "No wake up triggers defined\n"); - else if (wow->any == 0) - PRINT_INFO(priv->dev, GENERIC_DBG, - "The only supported wake up trigger (any) is not set\n"); - return 0; } static int wilc_resume(struct wiphy *wiphy) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); - - PRINT_INFO(vif->ndev, GENERIC_DBG, "cfg resume\n"); return 0; } static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled) { - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) { + srcu_read_unlock(&wl->srcu, srcu_idx); + return; + } PRINT_INFO(vif->ndev, GENERIC_DBG, "cfg set wake up = %d\n", enabled); wilc_set_wowlan_trigger(vif, (u8)enabled); + srcu_read_unlock(&wl->srcu, srcu_idx); } static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { int ret; + int srcu_idx; s32 tx_power = MBM_TO_DBM(mbm); - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + + if (!wl->initialized) + return -EIO; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) { + srcu_read_unlock(&wl->srcu, srcu_idx); + return -EINVAL; + } PRINT_INFO(vif->ndev, CFG80211_DBG, "Setting tx power %d\n", tx_power); if (tx_power < 0) @@ -2136,6 +2241,8 @@ static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, if (ret) PRINT_ER(vif->ndev, "Failed to set tx power\n"); + srcu_read_unlock(&wl->srcu, srcu_idx); + return ret; } @@ -2143,8 +2250,7 @@ static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm) { int ret; - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(wdev->netdev); struct wilc *wl = vif->wilc; /* If firmware is not started, return. */ @@ -2163,16 +2269,27 @@ static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, static int set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) { int ret; - struct wilc_priv *priv = wiphy_priv(wiphy); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) { + srcu_read_unlock(&wl->srcu, srcu_idx); + return -EINVAL; + } PRINT_INFO(vif->ndev, CFG80211_DBG, "Select antenna mode %d\n", tx_ant); - if (!tx_ant || !rx_ant) + if (!tx_ant || !rx_ant) { + srcu_read_unlock(&wl->srcu, srcu_idx); return -EINVAL; + } ret = wilc_set_antenna(vif, (u8)(tx_ant-1)); if (ret) PRINT_ER(vif->ndev, "Failed to set tx antenna\n"); + srcu_read_unlock(&wl->srcu, srcu_idx); return ret; } @@ -2220,136 +2337,185 @@ static const struct cfg80211_ops wilc_cfg80211_ops = { .set_antenna = set_antenna, }; -static struct wireless_dev *wilc_wfi_cfg_alloc(struct net_device *net) +static void wlan_init_locks(struct wilc *wl) { - struct wireless_dev *wdev; + pr_info("Initializing Locks ...\n"); + mutex_init(&wl->vif_mutex); + mutex_init(&wl->rxq_cs); + mutex_init(&wl->cfg_cmd_lock); + mutex_init(&wl->deinit_lock); + mutex_init(&wl->hif_cs); + mutex_init(&wl->cs); + + spin_lock_init(&wl->txq_spinlock); + mutex_init(&wl->txq_add_to_head_cs); + + init_completion(&wl->txq_event); + + init_completion(&wl->cfg_event); + init_completion(&wl->sync_event); + init_completion(&wl->txq_thread_started); + init_completion(&wl->debug_thread_started); + init_srcu_struct(&wl->srcu); +} - PRINT_INFO(net, CFG80211_DBG, "Allocating wireless device\n"); - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (!wdev) { - PRINT_ER(net, "Cannot allocate wireless device\n"); - goto out; +void wlan_deinit_locks(struct wilc *wl) +{ + pr_info("De-Initializing Locks\n"); + mutex_destroy(&wl->hif_cs); + mutex_destroy(&wl->rxq_cs); + mutex_destroy(&wl->cfg_cmd_lock); + mutex_destroy(&wl->vif_mutex); + mutex_destroy(&wl->txq_add_to_head_cs); + mutex_destroy(&wl->cs); + mutex_destroy(&wl->deinit_lock); + cleanup_srcu_struct(&wl->srcu); +} + +int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, + const struct wilc_hif_func *ops) +{ + int i, ret; + struct wilc *wl; + struct wilc_vif *vif; + + wl = wilc_create_wiphy(dev); + if (!wl) { + pr_err("failed to create wiphy\n"); + return -EINVAL; } - wdev->wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(struct wilc_priv)); - if (!wdev->wiphy) { - PRINT_ER(net, "Cannot allocate wiphy\n"); - goto free_mem; + wlan_init_locks(wl); + + ret = cfg_init(wl); + if (ret) + goto free_wl; + + wilc_debugfs_init(); + *wilc = wl; + wl->io_type = io_type; + wl->hif_func = ops; + for (i = 0; i < NQUEUES; i++) + INIT_LIST_HEAD(&wl->txq[i].txq_head.list); + + INIT_LIST_HEAD(&wl->rxq_head.list); + INIT_LIST_HEAD(&wl->vif_list); + + wl->hif_workqueue = create_singlethread_workqueue("WILC_wq"); + if (!wl->hif_workqueue) { + ret = -ENOMEM; + goto free_debug_fs; + } + vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE, + NL80211_IFTYPE_STATION, false); + if (IS_ERR(vif)) { + ret = PTR_ERR(vif); + goto free_wq; } - return wdev; + wilc_sysfs_init(wl); -free_mem: - kfree(wdev); -out: - return NULL; + return 0; +free_wq: + destroy_workqueue(wl->hif_workqueue); +free_debug_fs: + wilc_debugfs_remove(); + cfg_deinit(wl); +free_wl: + wlan_deinit_locks(wl); + wiphy_unregister(wl->wiphy); + wiphy_free(wl->wiphy); + return ret; } -struct wireless_dev *wilc_create_wiphy(struct net_device *net, - struct device *dev) +struct wilc *wilc_create_wiphy(struct device *dev) { - struct wilc_priv *priv; - struct wireless_dev *wdev; + struct wiphy *wiphy; + struct wilc *wl; int ret; - PRINT_INFO(net, CFG80211_DBG, "Registering wifi device\n"); - wdev = wilc_wfi_cfg_alloc(net); - if (!wdev) { - PRINT_ER(net, "wiphy new allocate failed\n"); - return NULL; + wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(struct wilc)); + if (!wiphy) { + pr_err("wiphy new allocate failed\n"); + return ERR_PTR(-EFAULT); } - priv = wdev_priv(wdev); - priv->wdev = wdev; + wl = wiphy_priv(wiphy); + pr_info("Registering wifi device\n"); - memcpy(priv->bitrates, wilc_bitrates, sizeof(wilc_bitrates)); - memcpy(priv->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels)); - priv->band.bitrates = priv->bitrates; - priv->band.n_bitrates = ARRAY_SIZE(priv->bitrates); - priv->band.channels = priv->channels; - priv->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels); + memcpy(wl->bitrates, wilc_bitrates, sizeof(wilc_bitrates)); + memcpy(wl->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels)); + wl->band.bitrates = wl->bitrates; + wl->band.n_bitrates = ARRAY_SIZE(wl->bitrates); + wl->band.channels = wl->channels; + wl->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels); - priv->band.ht_cap.ht_supported = 1; - priv->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - priv->band.ht_cap.mcs.rx_mask[0] = 0xff; - priv->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K; - priv->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; + wl->band.ht_cap.ht_supported = 1; + wl->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + wl->band.ht_cap.mcs.rx_mask[0] = 0xff; + wl->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K; + wl->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; #if KERNEL_VERSION(4, 7, 0) <= LINUX_VERSION_CODE - wdev->wiphy->bands[NL80211_BAND_2GHZ] = &priv->band; + wiphy->bands[NL80211_BAND_2GHZ] = &wl->band; #else - wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + wiphy->bands[IEEE80211_BAND_2GHZ] = &wl->band; #endif - wdev->wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID; + wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID; #if KERNEL_VERSION(3, 11, 0) <= LINUX_VERSION_CODE - wdev->wiphy->wowlan = &wowlan_support; + wiphy->wowlan = &wowlan_support; #else - wdev->wiphy->wowlan = wowlan_support; + wiphy->wowlan = wowlan_support; #endif - wdev->wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS; - PRINT_D(net, CFG80211_DBG, "Max number of PMKIDs = %d\n", - wdev->wiphy->max_num_pmkids); - wdev->wiphy->max_scan_ie_len = 1000; - wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - memcpy(priv->cipher_suites, wilc_cipher_suites, + wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS; + wiphy->max_scan_ie_len = 1000; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + memcpy(wl->cipher_suites, wilc_cipher_suites, sizeof(wilc_cipher_suites)); - wdev->wiphy->cipher_suites = priv->cipher_suites; - wdev->wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites); - wdev->wiphy->available_antennas_tx = 0x3; - wdev->wiphy->available_antennas_rx = 0x3; - wdev->wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types; - - wdev->wiphy->max_remain_on_channel_duration = 500; - wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + wiphy->cipher_suites = wl->cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites); + wiphy->available_antennas_tx = 0x3; + wiphy->available_antennas_rx = 0x3; + wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types; + + wiphy->max_remain_on_channel_duration = 500; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT); - wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - wdev->iftype = NL80211_IFTYPE_STATION; - - PRINT_D(net, CFG80211_DBG, - "Max scan ids= %d,Max scan IE len= %d,Signal Type= %d,Interface Modes= %d,Interface Type= %d\n", - wdev->wiphy->max_scan_ssids, wdev->wiphy->max_scan_ie_len, - wdev->wiphy->signal_type, wdev->wiphy->interface_modes, - wdev->iftype); - - set_wiphy_dev(wdev->wiphy, dev); - - ret = wiphy_register(wdev->wiphy); + wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + pr_info("Max scan ids= %d,Max scan IE len= %d,Signal Type= %d,Interface Modes= %d\n", + wiphy->max_scan_ssids, wiphy->max_scan_ie_len, + wiphy->signal_type, wiphy->interface_modes); + + set_wiphy_dev(wiphy, dev); + wl->wiphy = wiphy; + ret = wiphy_register(wiphy); if (ret) { - PRINT_ER(net, "Cannot register wiphy device\n"); - wiphy_free(wdev->wiphy); - kfree(wdev); - return NULL; + pr_err("Cannot register wiphy device\n"); + wiphy_free(wiphy); + return ERR_PTR(-EFAULT); } - - priv->dev = net; - return wdev; + return wl; } int wilc_init_host_int(struct net_device *net) { int ret; - struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(net); + struct wilc_priv *priv = &vif->priv; PRINT_INFO(net, INIT_DBG, "Host[%p][%p]\n", net, net->ieee80211_ptr); #if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE - #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - timer_setup(&vif->during_ip_timer, clear_during_ip, 0); - #endif timer_setup(&priv->eap_buff_timer, eap_buff_timeout, 0); #else - #ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - setup_timer(&vif->during_ip_timer, clear_during_ip, 0); - #endif setup_timer(&priv->eap_buff_timer, eap_buff_timeout, 0); #endif - priv->p2p_listen_state = false; + vif->p2p_listen_state = false; mutex_init(&priv->scan_req_lock); ret = wilc_init(net, &priv->hif_drv); @@ -2362,17 +2528,15 @@ int wilc_init_host_int(struct net_device *net) void wilc_deinit_host_int(struct net_device *net) { int ret; - struct wilc_priv *priv = wdev_priv(net->ieee80211_ptr); - struct wilc_vif *vif = netdev_priv(priv->dev); + struct wilc_vif *vif = netdev_priv(net); + struct wilc_priv *priv = &vif->priv; - priv->p2p_listen_state = false; + vif->p2p_listen_state = false; + flush_workqueue(vif->wilc->hif_workqueue); mutex_destroy(&priv->scan_req_lock); ret = wilc_deinit(vif); -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - del_timer_sync(&vif->during_ip_timer); -#endif del_timer_sync(&priv->eap_buff_timer); if (ret) diff --git a/drivers/net/wireless/mchp/wilc_wfi_cfgoperations.h b/drivers/net/wireless/mchp/wilc_wfi_cfgoperations.h index 9c56c4d3f3ab..a31dfae332b6 100644 --- a/drivers/net/wireless/mchp/wilc_wfi_cfgoperations.h +++ b/drivers/net/wireless/mchp/wilc_wfi_cfgoperations.h @@ -8,18 +8,22 @@ #define NM_WFI_CFGOPERATIONS #include "wilc_wfi_netdevice.h" -struct wireless_dev *wilc_create_wiphy(struct net_device *net, - struct device *dev); +struct wilc *wilc_create_wiphy(struct device *dev); void wilc_free_wiphy(struct net_device *net); void wilc_deinit_host_int(struct net_device *net); int wilc_init_host_int(struct net_device *net); void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size); -void wilc_wfi_deinit_mon_interface(struct wilc *wl); +void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked); struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl, const char *name, struct net_device *real_dev); void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, u16 frame_type, bool reg); -void wilc_sysfs_init(struct wilc_vif *vif1, struct wilc_vif *vif2); +void wilc_sysfs_init(struct wilc *wilc); void wilc_sysfs_exit(void); +int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, + const struct wilc_hif_func *ops); +struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type); +struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl); +void wlan_deinit_locks(struct wilc *wl); #endif diff --git a/drivers/net/wireless/mchp/wilc_wfi_netdevice.h b/drivers/net/wireless/mchp/wilc_wfi_netdevice.h index 0380c6d3f744..00409f93f730 100644 --- a/drivers/net/wireless/mchp/wilc_wfi_netdevice.h +++ b/drivers/net/wireless/mchp/wilc_wfi_netdevice.h @@ -20,7 +20,7 @@ #include #endif -#include "host_interface.h" +#include "wilc_hif.h" #include "wilc_wlan.h" #include "wilc_wlan_cfg.h" @@ -156,7 +156,7 @@ static struct ieee80211_rate wilc_bitrates[] = { }; struct wilc_priv { - struct wireless_dev *wdev; + struct wireless_dev wdev; struct cfg80211_scan_request *scan_req; struct wilc_wfi_p2p_listen_params remain_on_ch_params; u64 tx_cookie; @@ -164,7 +164,7 @@ struct wilc_priv { u8 associated_bss[ETH_ALEN]; struct sta_info assoc_stainfo; struct sk_buff *skb; - struct net_device *dev; + struct net_device *dev; //TODO:need to remove it struct host_if_drv *hif_drv; struct wilc_pmkid_attr pmkid_list; u8 wep_key[4][WLAN_KEY_LEN_WEP104]; @@ -177,16 +177,11 @@ struct wilc_priv { struct mutex scan_req_lock; - bool p2p_listen_state; struct wilc_buffered_eap *buffered_eap; struct timer_list eap_buff_timer; int scanned_cnt; struct wilc_p2p_var p2p; - struct ieee80211_channel channels[ARRAY_SIZE(wilc_2ghz_channels)]; - struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)]; - struct ieee80211_supported_band band; - u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)]; u64 inc_roc_cookie; }; @@ -239,21 +234,20 @@ struct wilc_vif { u8 bssid[ETH_ALEN]; struct host_if_drv *hif_drv; struct net_device *ndev; - u8 ifc_id; - struct sysfs_attr_group attr_sysfs; -#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP - bool pwrsave_current_state; - struct timer_list during_ip_timer; - bool obtaining_ip; -#endif struct rf_info periodic_stats; struct timer_list periodic_rssi; struct tcp_ack_filter ack_filter; bool connecting; + struct wilc_priv priv; + struct list_head list; + u8 restart; + bool p2p_listen_state; + struct cfg80211_bss *bss; }; struct wilc { + struct wiphy *wiphy; const struct wilc_hif_func *hif_func; int io_type; s8 mac_status; @@ -262,11 +256,15 @@ struct wilc { #else int gpio_irq; #endif + struct clk *rtc_clk; bool initialized; int dev_irq_num; int close; u8 vif_num; - struct wilc_vif *vif[WILC_NUM_CONCURRENT_IFC]; + struct list_head vif_list; + struct srcu_struct srcu; + /*protect vif list queue*/ + struct mutex vif_mutex; u8 open_ifcs; /*protect head of transmit queue*/ struct mutex txq_add_to_head_cs; @@ -311,7 +309,6 @@ struct wilc { uint8_t power_status[DEV_MAX]; uint8_t keep_awake[DEV_MAX]; struct mutex cs; - int clients_count; struct workqueue_struct *hif_workqueue; struct wilc_cfg cfg; @@ -321,6 +318,11 @@ struct wilc { struct mutex deinit_lock; u8 sta_ch; u8 op_ch; + struct sysfs_attr_group attr_sysfs; + struct ieee80211_channel channels[ARRAY_SIZE(wilc_2ghz_channels)]; + struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)]; + struct ieee80211_supported_band band; + u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)]; }; struct wilc_wfi_mon_priv { @@ -331,8 +333,6 @@ void wilc_frmw_to_host(struct wilc_vif *vif, u8 *buff, u32 size, u32 pkt_offset, u8 status); void wilc_mac_indicate(struct wilc *wilc); void wilc_netdev_cleanup(struct wilc *wilc); -int wilc_netdev_init(struct wilc **wilc, struct device *dev, int io_type, - const struct wilc_hif_func *ops); void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size); void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode); diff --git a/drivers/net/wireless/mchp/wilc_wlan.c b/drivers/net/wireless/mchp/wilc_wlan.c index 2d6e261e5c3a..0ec1ee2fec16 100644 --- a/drivers/net/wireless/mchp/wilc_wlan.c +++ b/drivers/net/wireless/mchp/wilc_wlan.c @@ -11,6 +11,7 @@ #include "wilc_wfi_netdevice.h" #include "wilc_wlan_cfg.h" #include "wilc_netdev.h" +#include "wilc_wfi_cfgoperations.h" #define WAKUP_TRAILS_TIMEOUT (10000) @@ -51,12 +52,10 @@ static void wilc_wlan_txq_remove(struct wilc *wilc, u8 q_num, } static struct txq_entry_t * -wilc_wlan_txq_remove_from_head(struct net_device *dev, u8 q_num) +wilc_wlan_txq_remove_from_head(struct wilc *wilc, u8 q_num) { struct txq_entry_t *tqe = NULL; unsigned long flags; - struct wilc_vif *vif = netdev_priv(dev); - struct wilc *wilc = vif->wilc; spin_lock_irqsave(&wilc->txq_spinlock, flags); @@ -272,26 +271,24 @@ static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev) static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header) { u8 *bssid, *bssid1; - int i = 0; struct net_device *mon_netdev = NULL; + struct wilc_vif *vif; bssid = mac_header + 10; bssid1 = mac_header + 4; - for (i = 0; i < wilc->vif_num; i++) { - if (wilc->vif[i]->iftype == WILC_STATION_MODE) - if (ether_addr_equal_unaligned(bssid, - wilc->vif[i]->bssid)) - return wilc->vif[i]->ndev; - if (wilc->vif[i]->iftype == WILC_AP_MODE) - if (ether_addr_equal_unaligned(bssid1, - wilc->vif[i]->bssid)) - return wilc->vif[i]->ndev; - if (wilc->vif[i]->iftype == WILC_MONITOR_MODE) - mon_netdev = wilc->vif[i]->ndev; + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->iftype == WILC_STATION_MODE) + if (ether_addr_equal_unaligned(bssid, vif->bssid)) + return vif->ndev; + if (vif->iftype == WILC_AP_MODE) + if (ether_addr_equal_unaligned(bssid1, vif->bssid)) + return vif->ndev; + if (vif->iftype == WILC_MONITOR_MODE) + mon_netdev = vif->ndev; } if (!mon_netdev) - PRINT_WRN(wilc->vif[0]->ndev, GENERIC_DBG, "Invalid handle\n"); + pr_warn("%s Invalid handle\n", __func__); return mon_netdev; } @@ -330,6 +327,7 @@ static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer, tqe->priv = NULL; tqe->q_num = AC_VO_Q; tqe->ack_idx = NOT_TCP_ACK; + tqe->vif = vif; PRINT_INFO(vif->ndev, TX_DBG, "Adding the config packet at the Queue tail\n"); @@ -521,6 +519,7 @@ int txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, tqe->buffer_size = buffer_size; tqe->tx_complete_func = tx_complete_fn; tqe->priv = priv; + tqe->vif = vif; q_num = ac_classify(wilc, tqe); if (ac_change(wilc, &q_num)) { @@ -586,6 +585,7 @@ int txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, tqe->priv = priv; tqe->q_num = AC_BE_Q; tqe->ack_idx = NOT_TCP_ACK; + tqe->vif = vif; PRINT_INFO(vif->ndev, TX_DBG, "Adding Mgmt packet to Queue tail\n"); wilc_wlan_txq_add_to_tail(dev, AC_VO_Q, tqe); @@ -626,31 +626,23 @@ static struct txq_entry_t *txq_get_next(struct wilc *wilc, static void rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe) { - struct wilc_vif *vif = wilc->vif[0]; - if (wilc->quit) return; mutex_lock(&wilc->rxq_cs); list_add_tail(&rqe->list, &wilc->rxq_head.list); - PRINT_INFO(vif->ndev, RX_DBG, "Added to RX queue\n"); mutex_unlock(&wilc->rxq_cs); } static struct rxq_entry_t *rxq_remove(struct wilc *wilc) { - struct wilc_vif *vif = wilc->vif[0]; struct rxq_entry_t *rqe = NULL; - PRINT_INFO(vif->ndev, RX_DBG, "Getting rxQ element\n"); - mutex_lock(&wilc->rxq_cs); if (!list_empty(&wilc->rxq_head.list)) { rqe = list_first_entry(&wilc->rxq_head.list, struct rxq_entry_t, list); list_del(&rqe->list); - } else { - PRINT_INFO(vif->ndev, RX_DBG, "Nothing to get from Q\n"); } mutex_unlock(&wilc->rxq_cs); return rqe; @@ -762,7 +754,7 @@ void chip_allow_sleep(struct wilc *wilc, int source) void chip_wakeup_wilc1000(struct wilc *wilc, int source) { u32 ret = 0; - u32 reg = 0, clk_status_val = 0, trials = 0; + u32 clk_status_val = 0, trials = 0; u32 wakeup_reg, wakeup_bit; u32 clk_status_reg, clk_status_bit; u32 to_host_from_fw_reg, to_host_from_fw_bit; @@ -790,28 +782,18 @@ void chip_wakeup_wilc1000(struct wilc *wilc, int source) to_host_from_fw_bit = BIT(0); } - ret = hif_func->hif_read_reg(wilc, from_host_to_fw_reg, ®); + + /*USE bit 0 to indicate host wakeup*/ + ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, + from_host_to_fw_bit); if (!ret) goto _fail_; - if (!(reg & from_host_to_fw_bit)) { - /*USE bit 0 to indicate host wakeup*/ - ret = hif_func->hif_write_reg(wilc, from_host_to_fw_reg, - reg | from_host_to_fw_bit); - if (!ret) - goto _fail_; - } - - ret = hif_func->hif_read_reg(wilc, wakeup_reg, ®); + /* Set bit 1 */ + ret = hif_func->hif_write_reg(wilc, wakeup_reg, + wakeup_bit); if (!ret) goto _fail_; - /* Set bit 1 */ - if (!(reg & wakeup_bit)) { - ret = hif_func->hif_write_reg(wilc, wakeup_reg, - reg | wakeup_bit); - if (!ret) - goto _fail_; - } do { ret = hif_func->hif_read_reg(wilc, clk_status_reg, @@ -941,7 +923,7 @@ void host_sleep_notify(struct wilc *wilc, int source) } static u8 ac_fw_count[NQUEUES] = {0, 0, 0, 0}; -int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) +int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) { int i, entries = 0; u8 k, ac; @@ -961,9 +943,9 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) int timeout; u32 vmm_table[WILC_VMM_TBL_SIZE]; u8 ac_pkt_num_to_chip[NQUEUES] = {0, 0, 0, 0}; - struct wilc_vif *vif = netdev_priv(dev); - struct wilc *wilc = vif->wilc; + struct wilc_vif *vif; const struct wilc_hif_func *func; + int srcu_idx; txb = wilc->tx_buffer; if (!wilc->txq_entries) { @@ -977,11 +959,15 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) return -1; mutex_lock(&wilc->txq_add_to_head_cs); - wilc_wlan_txq_filter_dup_tcp_ack(dev); - PRINT_INFO(vif->ndev, TX_DBG, "Getting the head of the TxQ\n"); + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) + wilc_wlan_txq_filter_dup_tcp_ack(vif->ndev); + srcu_read_unlock(&wilc->srcu, srcu_idx); + for (ac = 0; ac < NQUEUES; ac++) tqe_q[ac] = txq_get_first(wilc, ac); + i = 0; sum = 0; max_size_over = 0; @@ -991,7 +977,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) for (ac = 0; (ac < NQUEUES) && (!max_size_over); ac++) { if (!tqe_q[ac]) continue; - + vif = tqe_q[ac]->vif; ac_exist = 1; for (k = 0; (k < num_pkts_to_add[ac]) && (!max_size_over) && tqe_q[ac]; k++) { @@ -1044,10 +1030,8 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) num_pkts_to_add = ac_preserve_ratio; } while (!max_size_over && ac_exist); - if (i == 0) { - PRINT_INFO(vif->ndev, TX_DBG, "Nothing in TX-Q\n"); + if (i == 0) goto out; - } vmm_table[i] = 0x0; acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP, DEV_WIFI); @@ -1056,7 +1040,8 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) do { ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®); if (!ret) { - PRINT_ER(vif->ndev, "fail read reg vmm_tbl_entry..\n"); + PRINT_ER(vif->ndev, + "fail read reg vmm_tbl_entry..\n"); break; } if ((reg & 0x1) == 0) { @@ -1069,7 +1054,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) if (counter > 200) { counter = 0; PRINT_INFO(vif->ndev, TX_DBG, - "Looping in tx ctrl , force quit\n"); + "Looping in tx ctrl , force quit\n"); ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0); break; } @@ -1085,7 +1070,8 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) (u8 *)vmm_table, ((i + 1) * 4)); if (!ret) { - PRINT_ER(vif->ndev, "ERR block TX of VMM table.\n"); + PRINT_ER(vif->ndev, + "ERR block TX of VMM table.\n"); break; } @@ -1200,7 +1186,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) struct txq_entry_t *tqe; u32 header, buffer_offset; - tqe = wilc_wlan_txq_remove_from_head(dev, vmm_entries_ac[i]); + tqe = wilc_wlan_txq_remove_from_head(wilc, vmm_entries_ac[i]); ac_pkt_num_to_chip[vmm_entries_ac[i]]++; if (!tqe) break; @@ -1208,6 +1194,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) if (vmm_table[i] == 0) break; + vif = tqe->vif; le32_to_cpus(&vmm_table[i]); vmm_sz = (vmm_table[i] & 0x3ff); vmm_sz *= 4; @@ -1224,8 +1211,7 @@ int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count) if (tqe->type == WILC_CFG_PKT) { buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET; } else if (tqe->type == WILC_NET_PKT) { - char *bssid = ((struct tx_complete_data *) - (tqe->priv))->bssid; + char *bssid = tqe->vif->bssid; int prio = tqe->q_num; buffer_offset = ETH_ETHERNET_HDR_OFFSET; @@ -1270,7 +1256,6 @@ out_release_bus: out: mutex_unlock(&wilc->txq_add_to_head_cs); - PRINT_INFO(vif->ndev, TX_DBG, "THREAD: Exiting txq\n"); *txq_count = wilc->txq_entries; if (ret == 1) cfg_packet_timeout = 0; @@ -1284,15 +1269,10 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size) u32 pkt_len, pkt_offset, tp_len; int is_cfg_packet; u8 *buff_ptr; - struct wilc_vif *vif = wilc->vif[0]; do { - PRINT_INFO(vif->ndev, RX_DBG, "Handling rx buffer\n"); buff_ptr = buffer + offset; - memcpy(&header, buff_ptr, 4); - le32_to_cpus(&header); - PRINT_INFO(vif->ndev, RX_DBG, - "Header = %04x - Offset = %d\n", header, offset); + header = get_unaligned_le32(buff_ptr); is_cfg_packet = (header >> 31) & 0x1; pkt_offset = (header >> 22) & 0x1ff; @@ -1300,8 +1280,7 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size) pkt_len = header & 0x7ff; if (pkt_len == 0 || tp_len == 0) { - PRINT_INFO(vif->ndev, RX_DBG, - "Data corrupted %d, %d\n", + pr_err("%s: Data corrupted %d, %d\n", __func__, pkt_len, tp_len); break; } @@ -1314,10 +1293,6 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size) cfg_indicate_rx(wilc, buff_ptr, pkt_len, &rsp); if (rsp.type == WILC_CFG_RSP) { - PRINT_INFO(vif->ndev, RX_DBG, - "cfg_seq %d rsp.seq %d\n", - wilc->cfg_seq_no, rsp.seq_no); - if (wilc->cfg_seq_no == rsp.seq_no) complete(&wilc->cfg_event); } else if (rsp.type == WILC_CFG_RSP_STATUS) { @@ -1332,16 +1307,21 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size) wilc_wfi_handle_monitor_rx(wilc, buff_ptr, pkt_len); } else if (pkt_len > 0) { struct net_device *wilc_netdev; + struct wilc_vif *vif; + int srcu_idx; + srcu_idx = srcu_read_lock(&wilc->srcu); wilc_netdev = get_if_handler(wilc, buff_ptr); if (!wilc_netdev) { - PRINT_ER(vif->ndev, - "wilc_netdev in wilc is NULL"); + pr_err("%s: wilc_netdev in wilc is NULL\n", + __func__); + srcu_read_unlock(&wilc->srcu, srcu_idx); return; } vif = netdev_priv(wilc_netdev); wilc_frmw_to_host(vif, buff_ptr, pkt_len, pkt_offset, PKT_STATUS_NEW); + srcu_read_unlock(&wilc->srcu, srcu_idx); } offset += tp_len; @@ -1355,34 +1335,25 @@ static void wilc_wlan_handle_rxq(struct wilc *wilc) int size; u8 *buffer; struct rxq_entry_t *rqe; - struct wilc_vif *vif = wilc->vif[0]; do { if (wilc->quit) { - PRINT_INFO(vif->ndev, RX_DBG, - "Quitting. Exit handle RX queue\n"); + pr_info("%s Quitting. Exit handle RX queue\n", + __func__); complete(&wilc->cfg_event); break; } rqe = rxq_remove(wilc); - if (!rqe) { - PRINT_INFO(vif->ndev, RX_DBG, - "nothing in RX queue\n"); + if (!rqe) break; - } buffer = rqe->buffer; size = rqe->buffer_size; - PRINT_INFO(vif->ndev, RX_DBG, - "rxQ entery Size = %d - Address = %p\n", - size, buffer); wilc_wlan_handle_rx_buff(wilc, buffer, size); kfree(rqe); } while (1); - - PRINT_INFO(vif->ndev, RX_DBG, "THREAD: Exiting RX thread\n"); } static void wilc_unknown_isr_ext(struct wilc *wilc) @@ -1398,13 +1369,12 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) u32 retries = 0; int ret = 0; struct rxq_entry_t *rqe; - struct wilc_vif *vif = wilc->vif[0]; size = (int_status & 0x7fff) << 2; while (!size && retries < 10) { - PRINT_ER(vif->ndev, - "RX Size equal zero Trying to read it again\n"); + pr_err("%s: RX Size equal zero Trying to read it again\n", + __func__); wilc->hif_func->hif_read_size(wilc, &size); size = (size & 0x7fff) << 2; retries++; @@ -1422,7 +1392,7 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size); if (!ret) { - PRINT_ER(vif->ndev, "fail block rx\n"); + pr_err("%s: fail block rx\n", __func__); return; } @@ -1434,9 +1404,6 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) rqe->buffer = buffer; rqe->buffer_size = size; - PRINT_INFO(vif->ndev, RX_DBG, - "rxq entery Size= %d Address= %p\n", - rqe->buffer_size, rqe->buffer); rxq_add(wilc, rqe); wilc_wlan_handle_rxq(wilc); } @@ -1444,7 +1411,6 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) void wilc_handle_isr(struct wilc *wilc) { u32 int_status; - struct wilc_vif *vif = wilc->vif[0]; acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP, DEV_WIFI); wilc->hif_func->hif_read_int(wilc, &int_status); @@ -1453,7 +1419,7 @@ void wilc_handle_isr(struct wilc *wilc) wilc_wlan_handle_isr_ext(wilc, int_status); if (!(int_status & (ALL_INT_EXT))) { - PRINT_WRN(vif->ndev, TX_DBG, ">> UNKNOWN_INTERRUPT - 0x%08x\n", + pr_warn("%s,>> UNKNOWN_INTERRUPT - 0x%08x\n", __func__, int_status); wilc_unknown_isr_ext(wilc); } @@ -1469,20 +1435,15 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, u8 *dma_buffer; int ret = 0; u32 reg = 0; - struct wilc_vif *vif = wilc->vif[0]; blksz = BIT(12); dma_buffer = kmalloc(blksz, GFP_KERNEL); - if (!dma_buffer) { - PRINT_ER(vif->ndev, - "Can't allocate buffer for fw download IO error\n"); + if (!dma_buffer) return -EIO; - } offset = 0; - PRINT_INFO(vif->ndev, INIT_DBG, "Downloading firmware size = %d\n", - buffer_size); + pr_info("%sDownloading firmware size = %d\n", __func__, buffer_size); acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP, DEV_WIFI); @@ -1491,14 +1452,12 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); if ((reg & (1ul << 10)) != 0) - PRINT_ER(vif->ndev, "Failed to reset Wifi CPU\n"); + pr_err("%s: Failed to reset Wifi CPU\n", __func__); release_bus(wilc, WILC_BUS_RELEASE_ONLY, DEV_WIFI); do { - memcpy(&addr, &buffer[offset], 4); - memcpy(&size, &buffer[offset + 4], 4); - le32_to_cpus(&addr); - le32_to_cpus(&size); + addr = get_unaligned_le32(&buffer[offset]); + size = get_unaligned_le32(&buffer[offset + 4]); acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP, DEV_WIFI); offset += 8; while (((int)size) && (offset < buffer_size)) { @@ -1521,10 +1480,10 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, if (!ret) { ret = -EIO; - PRINT_ER(vif->ndev, "Bus error\n"); + pr_err("%s Bus error\n", __func__); goto fail; } - PRINT_INFO(vif->ndev, INIT_DBG, "Offset = %d\n", offset); + pr_info("%s Offset = %d\n", __func__, offset); } while (offset < buffer_size); fail: @@ -1538,7 +1497,6 @@ int wilc_wlan_start(struct wilc *wilc) { u32 reg = 0; int ret; - struct wilc_vif *vif = wilc->vif[0]; if (wilc->io_type == WILC_HIF_SDIO || wilc->io_type == WILC_HIF_SDIO_GPIO_IRQ) @@ -1549,8 +1507,7 @@ int wilc_wlan_start(struct wilc *wilc) acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP, DEV_WIFI); ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg); if (!ret) { - PRINT_ER(vif->ndev, - "[wilc start]: fail write reg vmm_core_cfg...\n"); + pr_err("[wilc start]: fail write reg vmm_core_cfg...\n"); release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); return -EIO; } @@ -1563,8 +1520,7 @@ int wilc_wlan_start(struct wilc *wilc) ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg); if (!ret) { - PRINT_ER(vif->ndev, - "[wilc start]: fail write WILC_GP_REG_1...\n"); + pr_err("[wilc start]: fail write WILC_GP_REG_1...\n"); release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); return -EIO; } @@ -1596,7 +1552,6 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) { u32 reg = 0; int ret; - u8 timeout = 10; acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP, DEV_WIFI); @@ -1605,7 +1560,7 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) if (!ret) { PRINT_ER(vif->ndev, "Error while reading reg\n"); release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); - return ret; + return -EIO; } reg &= ~BIT(0); @@ -1613,7 +1568,7 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) if (!ret) { PRINT_ER(vif->ndev, "Error while writing reg\n"); release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); - return ret; + return -EIO; } /* Configure the power sequencer to ignore WIFI sleep signal on making @@ -1623,7 +1578,7 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) if (!ret) { PRINT_ER(vif->ndev, "Error while reading reg\n"); release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); - return ret; + return -EIO; } reg &= ~BIT(28); @@ -1631,79 +1586,42 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) if (!ret) { PRINT_ER(vif->ndev, "Error while writing reg\n"); release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); - return ret; + return -EIO; } - ret = wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); + ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); if (!ret) { PRINT_ER(vif->ndev, "Error while reading reg\n"); release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); - return ret; + return -EIO; } - reg &= ~BIT(10); - ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); + ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0, + (reg | WILC_ABORT_REQ_BIT)); if (!ret) { PRINT_ER(vif->ndev, "Error while writing reg\n"); release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); - return ret; + return -EIO; } - do { - ret = wilc->hif_func->hif_read_reg(wilc, - WILC_GLB_RESET_0, ®); - if (!ret) { - PRINT_ER(vif->ndev, "Error while reading reg\n"); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, - DEV_WIFI); - return ret; - } - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Read RESET Reg %x : Retry%d\n", reg, timeout); - if ((reg & BIT(10))) { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Bit 10 not reset : Retry %d\n", timeout); - reg &= ~BIT(10); - ret = wilc->hif_func->hif_write_reg(wilc, - WILC_GLB_RESET_0, - reg); - timeout--; - } else { - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Bit 10 reset after : Retry %d\n", timeout); - ret = wilc->hif_func->hif_read_reg(wilc, - WILC_GLB_RESET_0, - ®); - if (!ret) { - PRINT_ER(vif->ndev, "Error reading reg\n"); - release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, - DEV_WIFI); - return ret; - } - PRINT_INFO(vif->ndev, GENERIC_DBG, - "Read RESET Reg %x : Retry%d\n", reg, - timeout); - break; - } - - } while (timeout); - - if (wilc->chip == WILC_1000) { - reg = (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | - BIT(26) | BIT(29) | BIT(30) | BIT(31)); - } else { - reg = (BIT(0) | BIT(2) | BIT(3) | BIT(8) | BIT(9) | - BIT(20) | BIT(26) | BIT(29) | BIT(30) | BIT(31)); + ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®); + if (!ret) { + PRINT_ER(vif->ndev, "Error while reading reg\n"); + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); + return -EIO; } - - wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®); reg = BIT(0); ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg); + if (!ret) { + PRINT_ER(vif->ndev, "Error while writing reg\n"); + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); + return -EIO; + } release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP, DEV_WIFI); - return ret; + return 0; } void wilc_wlan_cleanup(struct net_device *dev) @@ -1717,7 +1635,7 @@ void wilc_wlan_cleanup(struct net_device *dev) wilc->quit = 1; for (ac = 0; ac < NQUEUES; ac++) { do { - tqe = wilc_wlan_txq_remove_from_head(dev, ac); + tqe = wilc_wlan_txq_remove_from_head(wilc, ac); if (!tqe) break; if (tqe->tx_complete_func) @@ -1794,7 +1712,7 @@ int cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer, if (!wait_for_completion_timeout(&wilc->cfg_event, WILC_CFG_PKTS_TIMEOUT)) { - PRINT_ER(vif->ndev, "Timed Out\n"); + pr_err("%s Timed Out\n", __func__); ret_size = 0; } @@ -1832,10 +1750,10 @@ int cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit, if (!wait_for_completion_timeout(&wilc->cfg_event, WILC_CFG_PKTS_TIMEOUT)) { - PRINT_INFO(vif->ndev, TX_DBG, "Timed Out\n"); + pr_err("%s Timed Out\n", __func__); ret_size = 0; } - PRINT_INFO(vif->ndev, TX_DBG, "Get Response received\n"); + wilc->cfg_frame_offset = 0; wilc->cfg_seq_no += 1; mutex_unlock(&wilc->cfg_cmd_lock); @@ -1843,16 +1761,13 @@ int cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit, return ret_size; } -int cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size) -{ - return cfg_get_wid_value(wl, wid, buffer, buffer_size); -} unsigned int cfg_packet_timeout; int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, - u32 count, u32 drv) + u32 count) { int i; int ret = 0; + u32 drv = wilc_get_vif_idx(vif); if (wait_for_recovery) { PRINT_INFO(vif->ndev, CORECONFIG_DBG, diff --git a/drivers/net/wireless/mchp/wilc_wlan.h b/drivers/net/wireless/mchp/wilc_wlan.h index ad230cef6648..10d187ed480b 100644 --- a/drivers/net/wireless/mchp/wilc_wlan.h +++ b/drivers/net/wireless/mchp/wilc_wlan.h @@ -142,7 +142,7 @@ static inline bool is_wilc3000(u32 id) #define WILC_CFG_RSP 1 #define WILC_CFG_RSP_STATUS 2 #define WILC_CFG_RSP_SCAN 3 -#define ABORT_INT BIT(31) +#define WILC_ABORT_REQ_BIT BIT(31) #define WILC_RX_BUFF_SIZE (96 * 1024) #define WILC_TX_BUFF_SIZE (64 * 1024) @@ -246,6 +246,7 @@ struct txq_entry_t { int buffer_size; void *priv; int status; + struct wilc_vif *vif; void (*tx_complete_func)(void *priv, int status); }; @@ -296,7 +297,6 @@ struct wilc_hif_func { struct tx_complete_data { int size; void *buff; - u8 *bssid; struct sk_buff *skb; struct wilc_vif *vif; }; @@ -328,31 +328,29 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif); int txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, u32 buffer_size, void (*tx_complete_fn)(void *, int)); -int wilc_wlan_handle_txq(struct net_device *dev, u32 *txq_count); +int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count); void wilc_handle_isr(struct wilc *wilc); void wilc_wlan_cleanup(struct net_device *dev); int cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer, u32 buffer_size, int commit, u32 drv_handler); int cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit, u32 drv_handler); -int cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size); int txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, u32 buffer_size, void (*tx_complete_fn)(void *, int)); void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value); -int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc); netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev); -void wilc_wfi_p2p_rx(struct net_device *dev, u8 *buff, u32 size); +bool wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size); void host_wakeup_notify(struct wilc *wilc, int source); void host_sleep_notify(struct wilc *wilc, int source); void chip_allow_sleep(struct wilc *wilc, int source); void chip_wakeup(struct wilc *wilc, int source); int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, - u32 count, u32 drv); -void wilc_wlan_power_on_sequence(struct wilc *wilc); -void wilc_wlan_power_off_sequence(struct wilc *wilc); + u32 count); +int wilc_wlan_power_on_sequence(struct wilc *wilc); +int wilc_wlan_power_off_sequence(struct wilc *wilc); void wilc_bt_init(struct wilc *wilc); void wilc_bt_deinit(void); diff --git a/drivers/net/wireless/mchp/wilc_wlan_cfg.c b/drivers/net/wireless/mchp/wilc_wlan_cfg.c index 2ee45faf60fd..3bea59f47947 100644 --- a/drivers/net/wireless/mchp/wilc_wlan_cfg.c +++ b/drivers/net/wireless/mchp/wilc_wlan_cfg.c @@ -8,6 +8,7 @@ #include "wilc_wlan.h" #include "wilc_wlan_cfg.h" #include "wilc_wfi_netdevice.h" +#include "wilc_wfi_cfgoperations.h" enum cfg_cmd_type { CFG_BYTE_CMD = 0, @@ -59,105 +60,71 @@ static struct wilc_cfg_bin g_cfg_bin[] = { static int wilc_wlan_cfg_set_byte(u8 *frame, u32 offset, u16 id, u8 val8) { - u8 *buf; if ((offset + 4) >= WILC_MAX_CFG_FRAME_SIZE) return 0; - buf = &frame[offset]; - - buf[0] = (u8)id; - buf[1] = (u8)(id >> 8); - buf[2] = 1; - buf[3] = 0; - buf[4] = val8; + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(1, &frame[offset + 2]); + frame[offset + 4] = val8; return 5; } static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16) { - u8 *buf; - if ((offset + 5) >= WILC_MAX_CFG_FRAME_SIZE) return 0; - buf = &frame[offset]; - - buf[0] = (u8)id; - buf[1] = (u8)(id >> 8); - buf[2] = 2; - buf[3] = 0; - buf[4] = (u8)val16; - buf[5] = (u8)(val16 >> 8); - + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(2, &frame[offset + 2]); + put_unaligned_le16(val16, &frame[offset + 4]); return 6; } static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32) { - u8 *buf; - if ((offset + 7) >= WILC_MAX_CFG_FRAME_SIZE) return 0; - buf = &frame[offset]; - - buf[0] = (u8)id; - buf[1] = (u8)(id >> 8); - buf[2] = 4; - buf[3] = 0; - buf[4] = (u8)val32; - buf[5] = (u8)(val32 >> 8); - buf[6] = (u8)(val32 >> 16); - buf[7] = (u8)(val32 >> 24); - + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(4, &frame[offset + 2]); + put_unaligned_le32(val32, &frame[offset + 4]); return 8; } static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str, u32 size) { - u8 *buf; - if ((offset + size + 4) >= WILC_MAX_CFG_FRAME_SIZE) return 0; - buf = &frame[offset]; - - buf[0] = (u8)id; - buf[1] = (u8)(id >> 8); - buf[2] = (u8)size; - buf[3] = (u8)(size >> 8); + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(size, &frame[offset + 2]); if (str && size != 0) - memcpy(&buf[4], str, size); + memcpy(&frame[offset + 4], str, size); return (size + 4); } static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size) { - u8 *buf; u32 i; u8 checksum = 0; if ((offset + size + 5) >= WILC_MAX_CFG_FRAME_SIZE) return 0; - buf = &frame[offset]; - buf[0] = (u8)id; - buf[1] = (u8)(id >> 8); - buf[2] = (u8)size; - buf[3] = (u8)(size >> 8); + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(size, &frame[offset + 2]); if ((b) && size != 0) { - memcpy(&buf[4], b, size); + memcpy(&frame[offset + 4], b, size); for (i = 0; i < size; i++) - checksum += buf[i + 4]; + checksum += frame[offset + i + 4]; } - buf[size + 4] = checksum; - + frame[offset + size + 4] = checksum; return (size + 5); } @@ -173,14 +140,11 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, { u16 wid; u32 len = 0, i = 0; - struct wilc_vif *vif = wl->vif[0]; while (size > 0) { i = 0; wid = get_unaligned_le16(info); - PRINT_D(vif->ndev, GENERIC_DBG, "Processing response for %d\n", - wid); switch (GET_WID_TYPE(wid)) { case WID_CHAR: do { @@ -267,7 +231,8 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, * DATA */ if (checksum != info[4 + length]) { - PRINT_ER(vif->ndev, "Checksum Failed"); + pr_err("%s: Checksum Failed\n", + __func__); return; } @@ -291,13 +256,11 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, static void wilc_wlan_parse_info_frame(struct wilc *wl, u8 *info) { - struct wilc_vif *vif = wl->vif[0]; u32 wid, len; wid = get_unaligned_le16(info); len = info[2]; - PRINT_D(vif->ndev, GENERIC_DBG, "Status Len = %d Id= %d\n", len, wid); if (len == 1 && wid == WID_STATUS) { int i = 0; @@ -361,20 +324,14 @@ int cfg_set_wid(struct wilc_vif *vif, u8 *frame, u32 offset, u16 id, u8 *buf, int cfg_get_wid(u8 *frame, u32 offset, u16 id) { - u8 *buf; - if ((offset + 2) >= WILC_MAX_CFG_FRAME_SIZE) return 0; - buf = &frame[offset]; - - buf[0] = (u8)id; - buf[1] = (u8)(id >> 8); - + put_unaligned_le16(id, &frame[offset]); return 2; } -int cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size) +int cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size) { u32 type = (wid >> 12) & 0xf; int i, ret = 0; @@ -445,7 +402,7 @@ int cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size) (wl->cfg.bin[i].bin[1]<<8); if (buffer_size >= size) { memcpy(buffer, &wl->cfg.bin[i].bin[2], - size); + size); ret = size; } break; @@ -453,14 +410,14 @@ int cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size) i++; } while (1); } else { - PRINT_ER(wl->vif[0]->ndev, "[CFG]: illegal type (%08x)\n", wid); + pr_err("[CFG]: illegal type (%08x)\n", wid); } return ret; } void cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size, - struct wilc_cfg_rsp *rsp) + struct wilc_cfg_rsp *rsp) { u8 msg_type; u8 msg_id; @@ -490,7 +447,7 @@ void cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size, rsp->type = WILC_CFG_RSP_STATUS; rsp->seq_no = msg_id; /*call host interface info parse as well*/ - PRINT_D(wilc->vif[0]->ndev, RX_DBG, "Info message received\n"); + pr_info("%s: Info message received\n", __func__); wilc_gnrl_async_info_received(wilc, frame - 4, size + 4); break; @@ -499,16 +456,14 @@ void cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size, break; case 'S': - PRINT_D(wilc->vif[0]->ndev, RX_DBG, - "Scan Notification Received\n"); + pr_info("%s: Scan Notification Received\n", __func__); wilc_scan_complete_received(wilc, frame - 4, size + 4); break; default: - PRINT_D(wilc->vif[0]->ndev, RX_DBG, - "Receive unknown message %d-%d-%d-%d-%d-%d-%d-%d\n", - frame[0], frame[1], frame[2], frame[3], frame[4], - frame[5], frame[6], frame[7]); + pr_err("%s: Receive unknown message %d-%d-%d-%d-%d-%d-%d-%d\n", + __func__, frame[0], frame[1], frame[2], frame[3], + frame[4], frame[5], frame[6], frame[7]); rsp->seq_no = msg_id; break; } @@ -540,7 +495,6 @@ int cfg_init(struct wilc *wl) if (!str_vals) goto out_s; - wl->cfg.bin = kmemdup(g_cfg_bin, sizeof(g_cfg_bin), GFP_KERNEL); if (!wl->cfg.bin) goto out_str_val; diff --git a/drivers/net/wireless/mchp/wilc_wlan_cfg.h b/drivers/net/wireless/mchp/wilc_wlan_cfg.h index 3f78a154f973..d24ab36c1031 100644 --- a/drivers/net/wireless/mchp/wilc_wlan_cfg.h +++ b/drivers/net/wireless/mchp/wilc_wlan_cfg.h @@ -56,7 +56,7 @@ struct wilc; int cfg_set_wid(struct wilc_vif *vif, u8 *frame, u32 offset, u16 id, u8 *buf, int size); int cfg_get_wid(u8 *frame, u32 offset, u16 id); -int cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size); +int cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, u32 buffer_size); void cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size, struct wilc_cfg_rsp *rsp); int cfg_init(struct wilc *wl); diff --git a/drivers/net/wireless/mchp/wilc_wlan_if.h b/drivers/net/wireless/mchp/wilc_wlan_if.h index 2bf853b6da90..6f479ca115ad 100644 --- a/drivers/net/wireless/mchp/wilc_wlan_if.h +++ b/drivers/net/wireless/mchp/wilc_wlan_if.h @@ -735,7 +735,6 @@ enum { /* NMAC Integer WID list */ /* Custom Integer WID list */ WID_GET_INACTIVE_TIME = 0x2084, - WID_SET_OPERATION_MODE = 0X2086, /* EMAC String WID list */ WID_SSID = 0x3000, WID_FIRMWARE_VERSION = 0x3001, @@ -768,7 +767,7 @@ enum { WID_DEVICE_NAME = 0x3029, /*Added for CAPI tool */ /* NMAC String WID list */ - WID_SET_DRV_HANDLER = 0x3079, + WID_SET_OPERATION_MODE = 0x3079, WID_11N_P_ACTION_REQ = 0x3080, WID_HUT_TEST_ID = 0x3081, WID_PMKID_INFO = 0x3082,