diff options
Diffstat (limited to 'drivers/staging/wilc1000/hif.c')
-rw-r--r-- | drivers/staging/wilc1000/hif.c | 1961 |
1 files changed, 0 insertions, 1961 deletions
diff --git a/drivers/staging/wilc1000/hif.c b/drivers/staging/wilc1000/hif.c deleted file mode 100644 index d025a3093015..000000000000 --- a/drivers/staging/wilc1000/hif.c +++ /dev/null @@ -1,1961 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. - * All rights reserved. - */ - -#include "netdev.h" - -#define WILC_HIF_SCAN_TIMEOUT_MS 5000 -#define WILC_HIF_CONNECT_TIMEOUT_MS 9500 - -#define WILC_FALSE_FRMWR_CHANNEL 100 - -#define WILC_SCAN_WID_LIST_SIZE 6 - -struct wilc_rcvd_mac_info { - u8 status; -}; - -struct wilc_set_multicast { - u32 enabled; - u32 cnt; - u8 *mc_list; -}; - -struct wilc_del_all_sta { - u8 assoc_sta; - u8 mac[WILC_MAX_NUM_STA][ETH_ALEN]; -}; - -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 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; -}; - -/* '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 int handle_scan_done(struct wilc_vif *vif, enum scan_event evt) -{ - int 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; - - if (evt == SCAN_EVENT_ABORTED) { - 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) { - netdev_err(vif->ndev, "Failed to set abort running\n"); - result = -EFAULT; - } - } - - if (!hif_drv) { - netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__); - return result; - } - - 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; -} - -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[WILC_SCAN_WID_LIST_SIZE]; - 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; - - if (hif_drv->hif_state >= HOST_IF_SCANNING && - hif_drv->hif_state < HOST_IF_CONNECTED) { - netdev_err(vif->ndev, "Already scan\n"); - result = -EBUSY; - goto error; - } - - if (vif->connecting) { - netdev_err(vif->ndev, "Don't do obss scan\n"); - result = -EBUSY; - goto error; - } - - 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; - - 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 (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; - } - - 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) { - netdev_err(vif->ndev, "Failed to send scan parameters\n"); - goto error; - } - - hif_drv->scan_timer_vif = vif; - mod_timer(&hif_drv->scan_timer, - jiffies + msecs_to_jiffies(scan_timeout)); - -error: - - kfree(search_ssid_vals); - - 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 = conn_attr->param; - - 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++; - - 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++; - - 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++; - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt); - if (result) { - netdev_err(vif->ndev, "failed to send config packet\n"); - goto error; - } else { - 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) { - netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__); - goto out; - } - - hif_drv->hif_state = HOST_IF_IDLE; - - if (hif_drv->conn_info.conn_result) { - hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP, - WILC_MAC_STATUS_DISCONNECTED, - hif_drv->conn_info.arg); - - } else { - netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); - } - - wid.id = WID_DISCONNECT; - wid.type = WID_CHAR; - wid.val = (s8 *)&dummy_reason_code; - wid.size = sizeof(char); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); - if (result) - netdev_err(vif->ndev, "Failed to send disconnect\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); - } - - if (rates_len < WILC_MAX_RATES_SUPPORTED) { - supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, - ies->data, ies->len); - if (supp_rates_ie) { - u8 ext_rates = supp_rates_ie[1]; - - if (ext_rates > (WILC_MAX_RATES_SUPPORTED - rates_len)) - param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED; - else - param->supp_rates[0] += ext_rates; - - 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; - - 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; - - 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; - netdev_err(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 wilc_assoc_resp *res = (struct wilc_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); - - if (assoc_resp_info_len != 0) { - s32 err = 0; - - err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp, - assoc_resp_info_len, - conn_info); - if (err) - netdev_err(vif->ndev, - "wilc_parse_assoc_resp_info() returned error %d\n", - err); - } - } - - del_timer(&hif_drv->connect_timer); - conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status, - hif_drv->conn_info.arg); - - if (mac_status == WILC_MAC_STATUS_CONNECTED && - conn_info->status == WLAN_STATUS_SUCCESS) { - ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid); - hif_drv->hif_state = HOST_IF_CONNECTED; - } else { - 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; - - if (hif_drv->usr_scan_req.scan_result) { - 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(CONN_DISCONN_EVENT_DISCONN_NOTIF, - 0, hif_drv->conn_info.arg); - else - netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); - - 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; - } - - if (!hif_drv->conn_info.conn_result) { - netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); - 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) { - 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; - - wid.id = WID_DISCONNECT; - wid.type = WID_CHAR; - wid.val = (s8 *)&dummy_reason_code; - wid.size = sizeof(char); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); - if (result) { - netdev_err(vif->ndev, "Failed to send disconnect\n"); - return result; - } - - 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) - del_timer(&hif_drv->connect_timer); - - conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0, - conn_info->arg); - } else { - netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); - } - - 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; -} - -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) { - netdev_err(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) - wilc_enable_tcp_ack_filter(vif, true); - else if (stats->link_speed != DEFAULT_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(u8 *cur_byte, const u8 *mac, - struct station_parameters *params) -{ - 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, params->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; - - if (hif_drv->usr_scan_req.scan_result) - return -EBUSY; - - if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) - return -EBUSY; - - if (vif->connecting) - return -EBUSY; - - 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) - 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->remain_on_ch_timer_vif = vif; - - return 0; -} - -static int wilc_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; - - if (vif->priv.p2p_listen_state) { - 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) - 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) { - netdev_err(vif->ndev, "Failed to set remain channel\n"); - return -EINVAL; - } - - if (hif_drv->remain_on_ch.expired) { - hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg, - cookie); - } - } else { - netdev_dbg(vif->ndev, "Not in listen state\n"); - } - - return 0; -} - -static void wilc_handle_listen_state_expired(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - - wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie); - kfree(msg); -} - -static void listen_timer_cb(struct timer_list *t) -{ - struct host_if_drv *hif_drv = from_timer(hif_drv, t, - remain_on_ch_timer); - 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, wilc_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) { - netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); - 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; - - 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) - netdev_err(vif->ndev, "Failed to send setup multicast\n"); - -error: - kfree(set_mc->mc_list); - kfree(wid.val); - kfree(msg); -} - -static void handle_scan_timer(struct work_struct *work) -{ - struct host_if_msg *msg = container_of(work, struct host_if_msg, work); - - handle_scan_done(msg->vif, SCAN_EVENT_ABORTED); - 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); - - handle_scan_done(msg->vif, SCAN_EVENT_DONE); - - kfree(msg); -} - -static void timer_scan_cb(struct timer_list *t) -{ - struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer); - 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); -} - -static void timer_connect_cb(struct timer_list *t) -{ - struct host_if_drv *hif_drv = from_timer(hif_drv, t, - connect_timer); - 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); -} - -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) - netdev_err(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) - netdev_err(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; - - 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) - 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; - - 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) - 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) - netdev_err(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) - 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) - 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) - 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)); - } 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_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) - goto free_ies; - - 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) - netdev_err(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) - netdev_err(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) - return -ENOMEM; - - ether_addr_copy(wid.val, mac); - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); - kfree(wid.val); - if (result) { - netdev_err(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) - netdev_err(vif->ndev, "Failed to get inactive time\n"); - - return result; -} - -int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level) -{ - struct wid wid; - int result; - - if (!rssi_level) { - netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__); - 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; -} - -static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats) -{ - int result; - struct host_if_msg *msg; - - 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) { - netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); - 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); -} - -static void get_periodic_rssi(struct timer_list *t) -{ - struct wilc_vif *vif = from_timer(vif, t, periodic_rssi); - - if (!vif->hif_drv) { - netdev_err(vif->ndev, "%s: hif driver is NULL", __func__); - return; - } - - if (vif->hif_drv->hif_state == HOST_IF_CONNECTED) - wilc_get_stats_async(vif, &vif->periodic_stat); - - 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; - - hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL); - if (!hif_drv) - return -ENOMEM; - - *hif_drv_handler = hif_drv; - - vif->hif_drv = hif_drv; - - if (wilc->clients_count == 0) - mutex_init(&wilc->deinit_lock); - - timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0); - mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000)); - - 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); - - 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) { - netdev_err(vif->ndev, "%s: hif driver is NULL", __func__); - 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; - 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) { - netdev_err(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) { - netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); - 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; - } - - hif_drv = vif->hif_drv; - - if (!hif_drv) { - mutex_unlock(&wilc->deinit_lock); - return; - } - - if (!hif_drv->conn_info.conn_result) { - netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); - 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]; - result = wilc_enqueue_work(msg); - if (result) { - netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); - 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; - - if (!hif_drv) - 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) { - netdev_err(vif->ndev, "%s: enqueue work failed\n", - __func__); - 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; - - 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) - netdev_err(vif->ndev, "%s: failed to set remain on channel\n", - __func__); - - return result; -} - -int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie) -{ - if (!vif->hif_drv) { - netdev_err(vif->ndev, "%s: hif driver is NULL", __func__); - return -EFAULT; - } - - del_timer(&vif->hif_drv->remain_on_ch_timer); - - return wilc_handle_roc_expired(vif, cookie); -} - -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)); - - if (reg) - reg_frame.reg = 1; - - switch (frame_type) { - case IEEE80211_STYPE_ACTION: - reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX; - break; - - case IEEE80211_STYPE_PROBE_REQ: - reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX; - break; - - default: - break; - } - reg_frame.frame_type = cpu_to_le16(frame_type); - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); - if (result) - netdev_err(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; - - 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) - 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) - netdev_err(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; - - 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) - netdev_err(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; - - 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(cur_byte, mac, params); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); - if (result != 0) - netdev_err(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; - - wid.id = WID_REMOVE_STA; - wid.type = WID_BIN; - wid.size = ETH_ALEN; - wid.val = kzalloc(wid.size, GFP_KERNEL); - if (!wid.val) - 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) - netdev_err(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; - - memset(&del_sta, 0x0, sizeof(del_sta)); - for (i = 0; i < WILC_MAX_NUM_STA; i++) { - if (!is_zero_ether_addr(mac_addr[i])) { - assoc_sta++; - ether_addr_copy(del_sta.mac[i], mac_addr[i]); - } - } - - if (!assoc_sta) - 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) - netdev_err(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; - - 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(cur_byte, mac, params); - - result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); - if (result) - netdev_err(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 (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) - netdev_err(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; - - 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) { - netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); - 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); -} |