· 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 <jorga@somdevices.com>
# 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
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
- * All rights reserved.
- */
-
-#include <linux/etherdevice.h>
-
-#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;
-}
+++ /dev/null
-/* 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 <linux/ieee80211.h>
-#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
+++ /dev/null
-* 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>;
- }
- };
-}
+++ /dev/null
-* 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";
- };
-};
--- /dev/null
+* 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>;
+ }
+ };
+}
--- /dev/null
+* 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";
+ };
+};
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)
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);
}
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;
.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;
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)
sysfs_remove_group(wilc_kobj, &attr_group);
kobject_put(wilc_kobj);
}
-
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;
}
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");
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;
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
+ * All rights reserved.
+ */
+
+#include <linux/etherdevice.h>
+
+#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;
+}
--- /dev/null
+/* 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 <linux/ieee80211.h>
+#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
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");
}
/* 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
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;
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;
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;
#include <linux/interrupt.h>
#include <net/ip.h>
#include <linux/module.h>
-#ifdef DISABLE_PWRSAVE_AND_SCAN_DURING_IP
-#include <linux/inetdevice.h>
-#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);
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;
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,
- "<Recover>\n");
+ pr_info("%s <Recover>\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;
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);
}
}
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;
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;
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) {
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,
{
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)
#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");
}
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) {
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;
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);
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);
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");
}
}
-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);
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");
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");
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) {
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");
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");
{
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;
}
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);
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);
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;
if (vif->ndev) {
netif_stop_queue(vif->ndev);
+ handle_connect_cancel(vif);
+
if (!recovery_on)
wilc_deinit_host_int(vif->ndev);
}
if (wl->open_ifcs == 0) {
PRINT_INFO(ndev, GENERIC_DBG, "Deinitializing wilc\n");
wl->close = 1;
+
wilc_wlan_deinitialize(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 = {
.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;
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();
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);
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");
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;
} 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");
#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)
}
#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 */
* All rights reserved.
*/
+#include <linux/clk.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#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,
u32 block_size;
int nint;
bool is_init;
+ struct wilc *wl;
};
struct sdio_cmd52 {
}
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;
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);
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;
}
{
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();
}
sdio_register_driver,
sdio_unregister_driver);
MODULE_LICENSE("GPL");
+MODULE_VERSION("15.3");
* All rights reserved.
*/
+#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include "wilc_wfi_netdevice.h"
+#include "wilc_wfi_cfgoperations.h"
+#include "wilc_netdev.h"
struct wilc_spi {
int crc_off;
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;
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;
}
{
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;
};
module_spi_driver(wilc_spi_driver);
MODULE_LICENSE("GPL");
+MODULE_VERSION("15.3");
static int spi_data_rsp(struct wilc *wilc, u8 cmd)
{
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);
* 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;
break;
} while (retry--);
- if (retry <= 0) {
+ if (retry <= 0 && !clockless) {
dev_err(&spi->dev,
"Error, data read response (%02x)\n", rsp);
return N_RESET;
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4)
- }
+ },
};
static const struct wiphy_wowlan_support wowlan_support = {
{
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;
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;
}
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],
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;
}
}
+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];
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;
ret = -EINVAL;
goto out_error;
}
-
if (ether_addr_equal_unaligned(vif->bssid, bss->bssid)) {
ret = -EALREADY;
goto out_put_bss;
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;
goto out_put_bss;
}
kfree(join_params);
+ vif->bss = bss;
cfg80211_put_bss(wiphy, bss);
return 0;
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;
ret = -EINVAL;
}
+ vif->bss = NULL;
+
return ret;
}
{
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);
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,
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);
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;
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);
}
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,
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);
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;
{
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");
} else {
PRINT_ER(vif->ndev,
"Fragmentation threshold out of range\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
}
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;
}
}
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;
{
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");
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));
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++)
}
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;
}
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),
}
}
-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);
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);
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,
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];
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)
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) {
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);
}
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;
}
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;
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;
}
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",
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)
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;
}
}
#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;
break;
}
}
-
PRINT_INFO(vif->ndev, GENERIC_DBG,
"TX: ACTION FRAME Type:%x : Chan:%d\n",
buf[ACTION_SUBTYPE_ID], chan->hw_value);
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:
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);
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) {
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)
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);
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");
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:
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:
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:
"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:
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);
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");
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");
if (ret)
PRINT_ER(dev, "Host delete beacon fail\n");
-
return ret;
}
#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) {
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))
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,
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)
if (ret)
PRINT_ER(vif->ndev, "Failed to set tx power\n");
+ srcu_read_unlock(&wl->srcu, srcu_idx);
+
return ret;
}
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. */
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;
}
.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);
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)
#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
#include <linux/gpio.h>
#endif
-#include "host_interface.h"
+#include "wilc_hif.h"
#include "wilc_wlan.h"
#include "wilc_wlan_cfg.h"
};
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;
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];
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;
};
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;
#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;
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;
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 {
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);
#include "wilc_wfi_netdevice.h"
#include "wilc_wlan_cfg.h"
#include "wilc_netdev.h"
+#include "wilc_wfi_cfgoperations.h"
#define WAKUP_TRAILS_TIMEOUT (10000)
}
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);
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;
}
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");
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)) {
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);
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;
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;
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,
}
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;
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) {
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;
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++) {
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);
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) {
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;
}
(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;
}
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;
if (vmm_table[i] == 0)
break;
+ vif = tqe->vif;
le32_to_cpus(&vmm_table[i]);
vmm_sz = (vmm_table[i] & 0x3ff);
vmm_sz *= 4;
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;
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;
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;
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;
}
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) {
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;
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)
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++;
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;
}
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);
}
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);
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);
}
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);
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)) {
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:
{
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)
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;
}
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;
}
{
u32 reg = 0;
int ret;
- u8 timeout = 10;
acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP, DEV_WIFI);
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);
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
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);
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)
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)
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;
}
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);
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,
#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)
int buffer_size;
void *priv;
int status;
+ struct wilc_vif *vif;
void (*tx_complete_func)(void *priv, int status);
};
struct tx_complete_data {
int size;
void *buff;
- u8 *bssid;
struct sk_buff *skb;
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);
#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,
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);
}
{
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 {
* DATA
*/
if (checksum != info[4 + length]) {
- PRINT_ER(vif->ndev, "Checksum Failed");
+ pr_err("%s: Checksum Failed\n",
+ __func__);
return;
}
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;
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;
(wl->cfg.bin[i].bin[1]<<8);
if (buffer_size >= size) {
memcpy(buffer, &wl->cfg.bin[i].bin[2],
- size);
+ size);
ret = size;
}
break;
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;
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;
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;
}
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;
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);
/* 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,
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,