2021 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.4 * All rights reserved.5 */6 7#include "netdev.h"8 9#define WILC_HIF_SCAN_TIMEOUT_MS 500010#define WILC_HIF_CONNECT_TIMEOUT_MS 950011 12#define WILC_FALSE_FRMWR_CHANNEL 10013 14#define WILC_SCAN_WID_LIST_SIZE 615 16struct wilc_rcvd_mac_info {17 u8 status;18};19 20struct wilc_set_multicast {21 u32 enabled;22 u32 cnt;23 u8 *mc_list;24};25 26struct host_if_wowlan_trigger {27 u8 wowlan_trigger;28};29 30struct wilc_del_all_sta {31 u8 assoc_sta;32 u8 mac[WILC_MAX_NUM_STA][ETH_ALEN];33};34 35union wilc_message_body {36 struct wilc_rcvd_net_info net_info;37 struct wilc_rcvd_mac_info mac_info;38 struct wilc_set_multicast mc_info;39 struct wilc_remain_ch remain_on_ch;40 char *data;41 struct host_if_wowlan_trigger wow_trigger;42};43 44struct host_if_msg {45 union wilc_message_body body;46 struct wilc_vif *vif;47 struct work_struct work;48 void (*fn)(struct work_struct *ws);49 struct completion work_comp;50 bool is_sync;51};52 53/* 'msg' should be free by the caller for syc */54static struct host_if_msg*55wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *),56 bool is_sync)57{58 struct host_if_msg *msg;59 60 if (!work_fun)61 return ERR_PTR(-EINVAL);62 63 msg = kzalloc(sizeof(*msg), GFP_ATOMIC);64 if (!msg)65 return ERR_PTR(-ENOMEM);66 msg->fn = work_fun;67 msg->vif = vif;68 msg->is_sync = is_sync;69 if (is_sync)70 init_completion(&msg->work_comp);71 72 return msg;73}74 75static int wilc_enqueue_work(struct host_if_msg *msg)76{77 INIT_WORK(&msg->work, msg->fn);78 79 if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue)80 return -EINVAL;81 82 if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work))83 return -EINVAL;84 85 return 0;86}87 88/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as89 * special purpose in wilc device, so we add 1 to the index to starts from 1.90 * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC.91 */92int wilc_get_vif_idx(struct wilc_vif *vif)93{94 return vif->idx + 1;95}96 97/* We need to minus 1 from idx which is from wilc device to get real index98 * of wilc->vif[], because we add 1 when pass to wilc device in the function99 * wilc_get_vif_idx.100 * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1).101 */102static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx)103{104 int index = idx - 1;105 struct wilc_vif *vif;106 107 if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC)108 return NULL;109 110 wilc_for_each_vif(wilc, vif) {111 if (vif->idx == index)112 return vif;113 }114 115 return NULL;116}117 118static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt)119{120 int result = 0;121 u8 abort_running_scan;122 struct wid wid;123 struct host_if_drv *hif_drv = vif->hif_drv;124 struct wilc_user_scan_req *scan_req;125 126 if (evt == SCAN_EVENT_ABORTED) {127 abort_running_scan = 1;128 wid.id = WID_ABORT_RUNNING_SCAN;129 wid.type = WID_CHAR;130 wid.val = (s8 *)&abort_running_scan;131 wid.size = sizeof(char);132 133 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);134 if (result) {135 netdev_err(vif->ndev, "Failed to set abort running\n");136 result = -EFAULT;137 }138 }139 140 if (!hif_drv) {141 netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);142 return result;143 }144 145 scan_req = &hif_drv->usr_scan_req;146 if (scan_req->scan_result) {147 scan_req->scan_result(evt, NULL, scan_req->priv);148 scan_req->scan_result = NULL;149 }150 151 return result;152}153 154int wilc_scan(struct wilc_vif *vif, u8 scan_source,155 u8 scan_type, u8 *ch_freq_list,156 void (*scan_result_fn)(enum scan_event,157 struct wilc_rcvd_net_info *,158 struct wilc_priv *),159 struct cfg80211_scan_request *request)160{161 int result = 0;162 struct wid wid_list[WILC_SCAN_WID_LIST_SIZE];163 u32 index = 0;164 u32 i, scan_timeout;165 u8 *buffer;166 u8 valuesize = 0;167 u8 *search_ssid_vals = NULL;168 const u8 ch_list_len = request->n_channels;169 struct host_if_drv *hif_drv = vif->hif_drv;170 171 if (hif_drv->hif_state >= HOST_IF_SCANNING &&172 hif_drv->hif_state < HOST_IF_CONNECTED) {173 netdev_err(vif->ndev, "Already scan\n");174 result = -EBUSY;175 goto error;176 }177 178 if (vif->connecting) {179 netdev_err(vif->ndev, "Don't do obss scan\n");180 result = -EBUSY;181 goto error;182 }183 184 hif_drv->usr_scan_req.ch_cnt = 0;185 186 if (request->n_ssids) {187 for (i = 0; i < request->n_ssids; i++)188 valuesize += ((request->ssids[i].ssid_len) + 1);189 search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL);190 if (search_ssid_vals) {191 wid_list[index].id = WID_SSID_PROBE_REQ;192 wid_list[index].type = WID_STR;193 wid_list[index].val = search_ssid_vals;194 buffer = wid_list[index].val;195 196 *buffer++ = request->n_ssids;197 198 for (i = 0; i < request->n_ssids; i++) {199 *buffer++ = request->ssids[i].ssid_len;200 memcpy(buffer, request->ssids[i].ssid,201 request->ssids[i].ssid_len);202 buffer += request->ssids[i].ssid_len;203 }204 wid_list[index].size = (s32)(valuesize + 1);205 index++;206 }207 }208 209 wid_list[index].id = WID_INFO_ELEMENT_PROBE;210 wid_list[index].type = WID_BIN_DATA;211 wid_list[index].val = (s8 *)request->ie;212 wid_list[index].size = request->ie_len;213 index++;214 215 wid_list[index].id = WID_SCAN_TYPE;216 wid_list[index].type = WID_CHAR;217 wid_list[index].size = sizeof(char);218 wid_list[index].val = (s8 *)&scan_type;219 index++;220 221 if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) {222 wid_list[index].id = WID_PASSIVE_SCAN_TIME;223 wid_list[index].type = WID_SHORT;224 wid_list[index].size = sizeof(u16);225 wid_list[index].val = (s8 *)&request->duration;226 index++;227 228 scan_timeout = (request->duration * ch_list_len) + 500;229 } else {230 scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS;231 }232 233 wid_list[index].id = WID_SCAN_CHANNEL_LIST;234 wid_list[index].type = WID_BIN_DATA;235 236 if (ch_freq_list && ch_list_len > 0) {237 for (i = 0; i < ch_list_len; i++) {238 if (ch_freq_list[i] > 0)239 ch_freq_list[i] -= 1;240 }241 }242 243 wid_list[index].val = ch_freq_list;244 wid_list[index].size = ch_list_len;245 index++;246 247 wid_list[index].id = WID_START_SCAN_REQ;248 wid_list[index].type = WID_CHAR;249 wid_list[index].size = sizeof(char);250 wid_list[index].val = (s8 *)&scan_source;251 index++;252 253 hif_drv->usr_scan_req.scan_result = scan_result_fn;254 hif_drv->usr_scan_req.priv = &vif->priv;255 256 result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index);257 if (result) {258 netdev_err(vif->ndev, "Failed to send scan parameters\n");259 goto error;260 }261 262 hif_drv->scan_timer_vif = vif;263 mod_timer(&hif_drv->scan_timer,264 jiffies + msecs_to_jiffies(scan_timeout));265 266error:267 268 kfree(search_ssid_vals);269 270 return result;271}272 273static int wilc_send_connect_wid(struct wilc_vif *vif)274{275 int result = 0;276 struct wid wid_list[5];277 u32 wid_cnt = 0;278 struct host_if_drv *hif_drv = vif->hif_drv;279 struct wilc_conn_info *conn_attr = &hif_drv->conn_info;280 struct wilc_join_bss_param *bss_param = conn_attr->param;281 282 283 wid_list[wid_cnt].id = WID_SET_MFP;284 wid_list[wid_cnt].type = WID_CHAR;285 wid_list[wid_cnt].size = sizeof(char);286 wid_list[wid_cnt].val = (s8 *)&conn_attr->mfp_type;287 wid_cnt++;288 289 wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;290 wid_list[wid_cnt].type = WID_BIN_DATA;291 wid_list[wid_cnt].val = conn_attr->req_ies;292 wid_list[wid_cnt].size = conn_attr->req_ies_len;293 wid_cnt++;294 295 wid_list[wid_cnt].id = WID_11I_MODE;296 wid_list[wid_cnt].type = WID_CHAR;297 wid_list[wid_cnt].size = sizeof(char);298 wid_list[wid_cnt].val = (s8 *)&conn_attr->security;299 wid_cnt++;300 301 wid_list[wid_cnt].id = WID_AUTH_TYPE;302 wid_list[wid_cnt].type = WID_CHAR;303 wid_list[wid_cnt].size = sizeof(char);304 wid_list[wid_cnt].val = (s8 *)&conn_attr->auth_type;305 wid_cnt++;306 307 wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED;308 wid_list[wid_cnt].type = WID_STR;309 wid_list[wid_cnt].size = sizeof(*bss_param);310 wid_list[wid_cnt].val = (u8 *)bss_param;311 wid_cnt++;312 313 result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt);314 if (result) {315 netdev_err(vif->ndev, "failed to send config packet\n");316 goto error;317 } else {318 if (conn_attr->auth_type == WILC_FW_AUTH_SAE)319 hif_drv->hif_state = HOST_IF_EXTERNAL_AUTH;320 else321 hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;322 }323 324 return 0;325 326error:327 328 kfree(conn_attr->req_ies);329 conn_attr->req_ies = NULL;330 331 return result;332}333 334static void handle_connect_timeout(struct work_struct *work)335{336 struct host_if_msg *msg = container_of(work, struct host_if_msg, work);337 struct wilc_vif *vif = msg->vif;338 int result;339 struct wid wid;340 u16 dummy_reason_code = 0;341 struct host_if_drv *hif_drv = vif->hif_drv;342 343 if (!hif_drv) {344 netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);345 goto out;346 }347 348 hif_drv->hif_state = HOST_IF_IDLE;349 350 if (hif_drv->conn_info.conn_result) {351 hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP,352 WILC_MAC_STATUS_DISCONNECTED,353 hif_drv->conn_info.priv);354 355 } else {356 netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);357 }358 359 wid.id = WID_DISCONNECT;360 wid.type = WID_CHAR;361 wid.val = (s8 *)&dummy_reason_code;362 wid.size = sizeof(char);363 364 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);365 if (result)366 netdev_err(vif->ndev, "Failed to send disconnect\n");367 368 hif_drv->conn_info.req_ies_len = 0;369 kfree(hif_drv->conn_info.req_ies);370 hif_drv->conn_info.req_ies = NULL;371 372out:373 kfree(msg);374}375 376struct wilc_join_bss_param *377wilc_parse_join_bss_param(struct cfg80211_bss *bss,378 struct cfg80211_crypto_settings *crypto)379{380 const u8 *ies_data, *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie;381 const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie;382 struct ieee80211_p2p_noa_attr noa_attr;383 const struct cfg80211_bss_ies *ies;384 struct wilc_join_bss_param *param;385 u8 rates_len = 0;386 int ies_len;387 u64 ies_tsf;388 int ret;389 390 param = kzalloc(sizeof(*param), GFP_KERNEL);391 if (!param)392 return NULL;393 394 rcu_read_lock();395 ies = rcu_dereference(bss->ies);396 ies_data = kmemdup(ies->data, ies->len, GFP_ATOMIC);397 if (!ies_data) {398 rcu_read_unlock();399 kfree(param);400 return NULL;401 }402 ies_len = ies->len;403 ies_tsf = ies->tsf;404 rcu_read_unlock();405 406 param->beacon_period = cpu_to_le16(bss->beacon_interval);407 param->cap_info = cpu_to_le16(bss->capability);408 param->bss_type = WILC_FW_BSS_TYPE_INFRA;409 param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq);410 ether_addr_copy(param->bssid, bss->bssid);411 412 ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies_data, ies_len);413 if (ssid_elm) {414 if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN)415 memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]);416 }417 418 tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies_data, ies_len);419 if (tim_elm && tim_elm[1] >= 2)420 param->dtim_period = tim_elm[3];421 422 memset(param->p_suites, 0xFF, 3);423 memset(param->akm_suites, 0xFF, 3);424 425 rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies_data, ies_len);426 if (rates_ie) {427 rates_len = rates_ie[1];428 if (rates_len > WILC_MAX_RATES_SUPPORTED)429 rates_len = WILC_MAX_RATES_SUPPORTED;430 param->supp_rates[0] = rates_len;431 memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len);432 }433 434 if (rates_len < WILC_MAX_RATES_SUPPORTED) {435 supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES,436 ies_data, ies_len);437 if (supp_rates_ie) {438 u8 ext_rates = supp_rates_ie[1];439 440 if (ext_rates > (WILC_MAX_RATES_SUPPORTED - rates_len))441 param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED;442 else443 param->supp_rates[0] += ext_rates;444 445 memcpy(¶m->supp_rates[rates_len + 1],446 supp_rates_ie + 2,447 (param->supp_rates[0] - rates_len));448 }449 }450 451 ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies_data, ies_len);452 if (ht_ie)453 param->ht_capable = true;454 455 ret = cfg80211_get_p2p_attr(ies_data, ies_len,456 IEEE80211_P2P_ATTR_ABSENCE_NOTICE,457 (u8 *)&noa_attr, sizeof(noa_attr));458 if (ret > 0) {459 param->tsf_lo = cpu_to_le32(ies_tsf);460 param->noa_enabled = 1;461 param->idx = noa_attr.index;462 if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) {463 param->opp_enabled = 1;464 param->opp_en.ct_window = noa_attr.oppps_ctwindow;465 param->opp_en.cnt = noa_attr.desc[0].count;466 param->opp_en.duration = noa_attr.desc[0].duration;467 param->opp_en.interval = noa_attr.desc[0].interval;468 param->opp_en.start_time = noa_attr.desc[0].start_time;469 } else {470 param->opp_enabled = 0;471 param->opp_dis.cnt = noa_attr.desc[0].count;472 param->opp_dis.duration = noa_attr.desc[0].duration;473 param->opp_dis.interval = noa_attr.desc[0].interval;474 param->opp_dis.start_time = noa_attr.desc[0].start_time;475 }476 }477 wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,478 WLAN_OUI_TYPE_MICROSOFT_WMM,479 ies_data, ies_len);480 if (wmm_ie) {481 struct ieee80211_wmm_param_ie *ie;482 483 ie = (struct ieee80211_wmm_param_ie *)wmm_ie;484 if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) &&485 ie->version == 1) {486 param->wmm_cap = true;487 if (ie->qos_info & BIT(7))488 param->uapsd_cap = true;489 }490 }491 492 wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,493 WLAN_OUI_TYPE_MICROSOFT_WPA,494 ies_data, ies_len);495 if (wpa_ie) {496 param->mode_802_11i = 1;497 param->rsn_found = true;498 }499 500 rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies_data, ies_len);501 if (rsn_ie) {502 int rsn_ie_len = sizeof(struct element) + rsn_ie[1];503 int offset = 8;504 505 param->mode_802_11i = 2;506 param->rsn_found = true;507 508 /* extract RSN capabilities */509 if (offset < rsn_ie_len) {510 /* skip over pairwise suites */511 offset += (rsn_ie[offset] * 4) + 2;512 513 if (offset < rsn_ie_len) {514 /* skip over authentication suites */515 offset += (rsn_ie[offset] * 4) + 2;516 517 if (offset + 1 < rsn_ie_len)518 memcpy(param->rsn_cap, &rsn_ie[offset], 2);519 }520 }521 }522 523 if (param->rsn_found) {524 int i;525 526 param->rsn_grp_policy = crypto->cipher_group & 0xFF;527 for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++)528 param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF;529 530 for (i = 0; i < crypto->n_akm_suites && i < 3; i++)531 param->akm_suites[i] = crypto->akm_suites[i] & 0xFF;532 }533 534 kfree(ies_data);535 return (void *)param;536}537 538static void handle_rcvd_ntwrk_info(struct work_struct *work)539{540 struct host_if_msg *msg = container_of(work, struct host_if_msg, work);541 struct wilc_rcvd_net_info *rcvd_info = &msg->body.net_info;542 struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req;543 const u8 *ch_elm;544 u8 *ies;545 int ies_len;546 size_t offset;547 548 if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control))549 offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);550 else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control))551 offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);552 else553 goto done;554 555 ies = rcvd_info->mgmt->u.beacon.variable;556 ies_len = rcvd_info->frame_len - offset;557 if (ies_len <= 0)558 goto done;559 560 ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len);561 if (ch_elm && ch_elm[1] > 0)562 rcvd_info->ch = ch_elm[2];563 564 if (scan_req->scan_result)565 scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info,566 scan_req->priv);567 568done:569 kfree(rcvd_info->mgmt);570 kfree(msg);571}572 573static void host_int_get_assoc_res_info(struct wilc_vif *vif,574 u8 *assoc_resp_info,575 u32 max_assoc_resp_info_len,576 u32 *rcvd_assoc_resp_info_len)577{578 int result;579 struct wid wid;580 581 wid.id = WID_ASSOC_RES_INFO;582 wid.type = WID_STR;583 wid.val = assoc_resp_info;584 wid.size = max_assoc_resp_info_len;585 586 result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);587 if (result) {588 *rcvd_assoc_resp_info_len = 0;589 netdev_err(vif->ndev, "Failed to send association response\n");590 return;591 }592 593 *rcvd_assoc_resp_info_len = wid.size;594}595 596static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,597 struct wilc_conn_info *ret_conn_info)598{599 u8 *ies;600 u16 ies_len;601 struct wilc_assoc_resp *res = (struct wilc_assoc_resp *)buffer;602 603 ret_conn_info->status = le16_to_cpu(res->status_code);604 if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {605 ies = &buffer[sizeof(*res)];606 ies_len = buffer_len - sizeof(*res);607 608 ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL);609 if (!ret_conn_info->resp_ies)610 return -ENOMEM;611 612 ret_conn_info->resp_ies_len = ies_len;613 }614 615 return 0;616}617 618static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,619 u8 mac_status)620{621 struct host_if_drv *hif_drv = vif->hif_drv;622 struct wilc_conn_info *conn_info = &hif_drv->conn_info;623 624 if (mac_status == WILC_MAC_STATUS_CONNECTED) {625 u32 assoc_resp_info_len;626 627 memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE);628 629 host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,630 WILC_MAX_ASSOC_RESP_FRAME_SIZE,631 &assoc_resp_info_len);632 633 if (assoc_resp_info_len != 0) {634 s32 err = 0;635 636 err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp,637 assoc_resp_info_len,638 conn_info);639 if (err)640 netdev_err(vif->ndev,641 "wilc_parse_assoc_resp_info() returned error %d\n",642 err);643 }644 }645 646 del_timer(&hif_drv->connect_timer);647 conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,648 hif_drv->conn_info.priv);649 650 if (mac_status == WILC_MAC_STATUS_CONNECTED &&651 conn_info->status == WLAN_STATUS_SUCCESS) {652 ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid);653 hif_drv->hif_state = HOST_IF_CONNECTED;654 } else {655 hif_drv->hif_state = HOST_IF_IDLE;656 }657 658 kfree(conn_info->resp_ies);659 conn_info->resp_ies = NULL;660 conn_info->resp_ies_len = 0;661 662 kfree(conn_info->req_ies);663 conn_info->req_ies = NULL;664 conn_info->req_ies_len = 0;665}666 667void wilc_handle_disconnect(struct wilc_vif *vif)668{669 struct host_if_drv *hif_drv = vif->hif_drv;670 671 if (hif_drv->usr_scan_req.scan_result) {672 del_timer(&hif_drv->scan_timer);673 handle_scan_done(vif, SCAN_EVENT_ABORTED);674 }675 676 if (hif_drv->conn_info.conn_result)677 hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,678 0, hif_drv->conn_info.priv);679 680 eth_zero_addr(hif_drv->assoc_bssid);681 682 hif_drv->conn_info.req_ies_len = 0;683 kfree(hif_drv->conn_info.req_ies);684 hif_drv->conn_info.req_ies = NULL;685 hif_drv->hif_state = HOST_IF_IDLE;686}687 688static void handle_rcvd_gnrl_async_info(struct work_struct *work)689{690 struct host_if_msg *msg = container_of(work, struct host_if_msg, work);691 struct wilc_vif *vif = msg->vif;692 struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info;693 struct host_if_drv *hif_drv = vif->hif_drv;694 695 if (!hif_drv) {696 netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);697 goto free_msg;698 }699 700 if (!hif_drv->conn_info.conn_result) {701 netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);702 goto free_msg;703 }704 705 706 if (hif_drv->hif_state == HOST_IF_EXTERNAL_AUTH) {707 cfg80211_external_auth_request(vif->ndev, &vif->auth,708 GFP_KERNEL);709 hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;710 } else if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {711 host_int_parse_assoc_resp_info(vif, mac_info->status);712 } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) {713 if (hif_drv->hif_state == HOST_IF_CONNECTED) {714 wilc_handle_disconnect(vif);715 } else if (hif_drv->usr_scan_req.scan_result) {716 del_timer(&hif_drv->scan_timer);717 handle_scan_done(vif, SCAN_EVENT_ABORTED);718 }719 }720 721free_msg:722 kfree(msg);723}724 725int wilc_disconnect(struct wilc_vif *vif)726{727 struct wid wid;728 struct host_if_drv *hif_drv = vif->hif_drv;729 struct wilc_user_scan_req *scan_req;730 struct wilc_conn_info *conn_info;731 int result;732 u16 dummy_reason_code = 0;733 734 wid.id = WID_DISCONNECT;735 wid.type = WID_CHAR;736 wid.val = (s8 *)&dummy_reason_code;737 wid.size = sizeof(char);738 739 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);740 if (result) {741 netdev_err(vif->ndev, "Failed to send disconnect\n");742 return result;743 }744 745 scan_req = &hif_drv->usr_scan_req;746 conn_info = &hif_drv->conn_info;747 748 if (scan_req->scan_result) {749 del_timer(&hif_drv->scan_timer);750 scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->priv);751 scan_req->scan_result = NULL;752 }753 754 if (conn_info->conn_result) {755 if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||756 hif_drv->hif_state == HOST_IF_EXTERNAL_AUTH)757 del_timer(&hif_drv->connect_timer);758 759 conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,760 conn_info->priv);761 } else {762 netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);763 }764 765 hif_drv->hif_state = HOST_IF_IDLE;766 767 eth_zero_addr(hif_drv->assoc_bssid);768 769 conn_info->req_ies_len = 0;770 kfree(conn_info->req_ies);771 conn_info->req_ies = NULL;772 773 return 0;774}775 776int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)777{778 struct wid wid_list[5];779 u32 wid_cnt = 0, result;780 781 wid_list[wid_cnt].id = WID_LINKSPEED;782 wid_list[wid_cnt].type = WID_CHAR;783 wid_list[wid_cnt].size = sizeof(char);784 wid_list[wid_cnt].val = (s8 *)&stats->link_speed;785 wid_cnt++;786 787 wid_list[wid_cnt].id = WID_RSSI;788 wid_list[wid_cnt].type = WID_CHAR;789 wid_list[wid_cnt].size = sizeof(char);790 wid_list[wid_cnt].val = (s8 *)&stats->rssi;791 wid_cnt++;792 793 wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;794 wid_list[wid_cnt].type = WID_INT;795 wid_list[wid_cnt].size = sizeof(u32);796 wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt;797 wid_cnt++;798 799 wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;800 wid_list[wid_cnt].type = WID_INT;801 wid_list[wid_cnt].size = sizeof(u32);802 wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt;803 wid_cnt++;804 805 wid_list[wid_cnt].id = WID_FAILED_COUNT;806 wid_list[wid_cnt].type = WID_INT;807 wid_list[wid_cnt].size = sizeof(u32);808 wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt;809 wid_cnt++;810 811 result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list, wid_cnt);812 if (result) {813 netdev_err(vif->ndev, "Failed to send scan parameters\n");814 return result;815 }816 817 if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&818 stats->link_speed != DEFAULT_LINK_SPEED)819 wilc_enable_tcp_ack_filter(vif, true);820 else if (stats->link_speed != DEFAULT_LINK_SPEED)821 wilc_enable_tcp_ack_filter(vif, false);822 823 return result;824}825 826static void handle_get_statistics(struct work_struct *work)827{828 struct host_if_msg *msg = container_of(work, struct host_if_msg, work);829 struct wilc_vif *vif = msg->vif;830 struct rf_info *stats = (struct rf_info *)msg->body.data;831 832 wilc_get_statistics(vif, stats);833 834 kfree(msg);835}836 837static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,838 struct station_parameters *params)839{840 ether_addr_copy(cur_byte, mac);841 cur_byte += ETH_ALEN;842 843 put_unaligned_le16(params->aid, cur_byte);844 cur_byte += 2;845 846 *cur_byte++ = params->link_sta_params.supported_rates_len;847 if (params->link_sta_params.supported_rates_len > 0)848 memcpy(cur_byte, params->link_sta_params.supported_rates,849 params->link_sta_params.supported_rates_len);850 cur_byte += params->link_sta_params.supported_rates_len;851 852 if (params->link_sta_params.ht_capa) {853 *cur_byte++ = true;854 memcpy(cur_byte, params->link_sta_params.ht_capa,855 sizeof(struct ieee80211_ht_cap));856 } else {857 *cur_byte++ = false;858 }859 cur_byte += sizeof(struct ieee80211_ht_cap);860 861 put_unaligned_le16(params->sta_flags_mask, cur_byte);862 cur_byte += 2;863 put_unaligned_le16(params->sta_flags_set, cur_byte);864}865 866static int handle_remain_on_chan(struct wilc_vif *vif,867 struct wilc_remain_ch *hif_remain_ch)868{869 int result;870 u8 remain_on_chan_flag;871 struct wid wid;872 struct host_if_drv *hif_drv = vif->hif_drv;873 874 if (hif_drv->usr_scan_req.scan_result)875 return -EBUSY;876 877 if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)878 return -EBUSY;879 880 if (vif->connecting)881 return -EBUSY;882 883 remain_on_chan_flag = true;884 wid.id = WID_REMAIN_ON_CHAN;885 wid.type = WID_STR;886 wid.size = 2;887 wid.val = kmalloc(wid.size, GFP_KERNEL);888 if (!wid.val)889 return -ENOMEM;890 891 wid.val[0] = remain_on_chan_flag;892 wid.val[1] = (s8)hif_remain_ch->ch;893 894 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);895 kfree(wid.val);896 if (result)897 return -EBUSY;898 899 hif_drv->remain_on_ch.vif = hif_remain_ch->vif;900 hif_drv->remain_on_ch.expired = hif_remain_ch->expired;901 hif_drv->remain_on_ch.ch = hif_remain_ch->ch;902 hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie;903 hif_drv->remain_on_ch_timer_vif = vif;904 905 return 0;906}907 908static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)909{910 u8 remain_on_chan_flag;911 struct wid wid;912 int result;913 struct host_if_drv *hif_drv = vif->hif_drv;914 915 if (vif->priv.p2p_listen_state) {916 remain_on_chan_flag = false;917 wid.id = WID_REMAIN_ON_CHAN;918 wid.type = WID_STR;919 wid.size = 2;920 921 wid.val = kmalloc(wid.size, GFP_KERNEL);922 if (!wid.val)923 return -ENOMEM;924 925 wid.val[0] = remain_on_chan_flag;926 wid.val[1] = WILC_FALSE_FRMWR_CHANNEL;927 928 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);929 kfree(wid.val);930 if (result != 0) {931 netdev_err(vif->ndev, "Failed to set remain channel\n");932 return -EINVAL;933 }934 935 if (hif_drv->remain_on_ch.expired) {936 hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.vif,937 cookie);938 }939 } else {940 netdev_dbg(vif->ndev, "Not in listen state\n");941 }942 943 return 0;944}945 946static void wilc_handle_listen_state_expired(struct work_struct *work)947{948 struct host_if_msg *msg = container_of(work, struct host_if_msg, work);949 950 wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie);951 kfree(msg);952}953 954static void listen_timer_cb(struct timer_list *t)955{956 struct host_if_drv *hif_drv = from_timer(hif_drv, t,957 remain_on_ch_timer);958 struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif;959 int result;960 struct host_if_msg *msg;961 962 del_timer(&vif->hif_drv->remain_on_ch_timer);963 964 msg = wilc_alloc_work(vif, wilc_handle_listen_state_expired, false);965 if (IS_ERR(msg))966 return;967 968 msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie;969 970 result = wilc_enqueue_work(msg);971 if (result) {972 netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);973 kfree(msg);974 }975}976 977static void handle_set_mcast_filter(struct work_struct *work)978{979 struct host_if_msg *msg = container_of(work, struct host_if_msg, work);980 struct wilc_vif *vif = msg->vif;981 struct wilc_set_multicast *set_mc = &msg->body.mc_info;982 int result;983 struct wid wid;984 u8 *cur_byte;985 986 wid.id = WID_SETUP_MULTICAST_FILTER;987 wid.type = WID_BIN;988 wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN);989 wid.val = kmalloc(wid.size, GFP_KERNEL);990 if (!wid.val)991 goto error;992 993 cur_byte = wid.val;994 put_unaligned_le32(set_mc->enabled, cur_byte);995 cur_byte += 4;996 997 put_unaligned_le32(set_mc->cnt, cur_byte);998 cur_byte += 4;999 1000 if (set_mc->cnt > 0 && set_mc->mc_list)1001 memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN);1002 1003 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1004 if (result)1005 netdev_err(vif->ndev, "Failed to send setup multicast\n");1006 1007error:1008 kfree(set_mc->mc_list);1009 kfree(wid.val);1010 kfree(msg);1011}1012 1013void wilc_set_wowlan_trigger(struct wilc_vif *vif, bool enabled)1014{1015 int ret;1016 struct wid wid;1017 u8 wowlan_trigger = 0;1018 1019 if (enabled)1020 wowlan_trigger = 1;1021 1022 wid.id = WID_WOWLAN_TRIGGER;1023 wid.type = WID_CHAR;1024 wid.val = &wowlan_trigger;1025 wid.size = sizeof(char);1026 1027 ret = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1028 if (ret)1029 pr_err("Failed to send wowlan trigger config packet\n");1030}1031 1032int wilc_set_external_auth_param(struct wilc_vif *vif,1033 struct cfg80211_external_auth_params *auth)1034{1035 int ret;1036 struct wid wid;1037 struct wilc_external_auth_param *param;1038 1039 wid.id = WID_EXTERNAL_AUTH_PARAM;1040 wid.type = WID_BIN_DATA;1041 wid.size = sizeof(*param);1042 param = kzalloc(sizeof(*param), GFP_KERNEL);1043 if (!param)1044 return -EINVAL;1045 1046 wid.val = (u8 *)param;1047 param->action = auth->action;1048 ether_addr_copy(param->bssid, auth->bssid);1049 memcpy(param->ssid, auth->ssid.ssid, auth->ssid.ssid_len);1050 param->ssid_len = auth->ssid.ssid_len;1051 ret = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1052 1053 kfree(param);1054 return ret;1055}1056 1057static void handle_scan_timer(struct work_struct *work)1058{1059 struct host_if_msg *msg = container_of(work, struct host_if_msg, work);1060 1061 handle_scan_done(msg->vif, SCAN_EVENT_ABORTED);1062 kfree(msg);1063}1064 1065static void handle_scan_complete(struct work_struct *work)1066{1067 struct host_if_msg *msg = container_of(work, struct host_if_msg, work);1068 1069 del_timer(&msg->vif->hif_drv->scan_timer);1070 1071 handle_scan_done(msg->vif, SCAN_EVENT_DONE);1072 1073 kfree(msg);1074}1075 1076static void timer_scan_cb(struct timer_list *t)1077{1078 struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer);1079 struct wilc_vif *vif = hif_drv->scan_timer_vif;1080 struct host_if_msg *msg;1081 int result;1082 1083 msg = wilc_alloc_work(vif, handle_scan_timer, false);1084 if (IS_ERR(msg))1085 return;1086 1087 result = wilc_enqueue_work(msg);1088 if (result)1089 kfree(msg);1090}1091 1092static void timer_connect_cb(struct timer_list *t)1093{1094 struct host_if_drv *hif_drv = from_timer(hif_drv, t,1095 connect_timer);1096 struct wilc_vif *vif = hif_drv->connect_timer_vif;1097 struct host_if_msg *msg;1098 int result;1099 1100 msg = wilc_alloc_work(vif, handle_connect_timeout, false);1101 if (IS_ERR(msg))1102 return;1103 1104 result = wilc_enqueue_work(msg);1105 if (result)1106 kfree(msg);1107}1108 1109int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,1110 const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,1111 u8 mode, u8 cipher_mode, u8 index)1112{1113 int result = 0;1114 u8 t_key_len = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;1115 1116 if (mode == WILC_AP_MODE) {1117 struct wid wid_list[2];1118 struct wilc_ap_wpa_ptk *key_buf;1119 1120 wid_list[0].id = WID_11I_MODE;1121 wid_list[0].type = WID_CHAR;1122 wid_list[0].size = sizeof(char);1123 wid_list[0].val = (s8 *)&cipher_mode;1124 1125 key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);1126 if (!key_buf)1127 return -ENOMEM;1128 1129 ether_addr_copy(key_buf->mac_addr, mac_addr);1130 key_buf->index = index;1131 key_buf->key_len = t_key_len;1132 memcpy(&key_buf->key[0], ptk, ptk_key_len);1133 1134 if (rx_mic)1135 memcpy(&key_buf->key[ptk_key_len], rx_mic,1136 WILC_RX_MIC_KEY_LEN);1137 1138 if (tx_mic)1139 memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],1140 tx_mic, WILC_TX_MIC_KEY_LEN);1141 1142 wid_list[1].id = WID_ADD_PTK;1143 wid_list[1].type = WID_STR;1144 wid_list[1].size = sizeof(*key_buf) + t_key_len;1145 wid_list[1].val = (u8 *)key_buf;1146 result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,1147 ARRAY_SIZE(wid_list));1148 kfree(key_buf);1149 } else if (mode == WILC_STATION_MODE) {1150 struct wid wid;1151 struct wilc_sta_wpa_ptk *key_buf;1152 1153 key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);1154 if (!key_buf)1155 return -ENOMEM;1156 1157 ether_addr_copy(key_buf->mac_addr, mac_addr);1158 key_buf->key_len = t_key_len;1159 memcpy(&key_buf->key[0], ptk, ptk_key_len);1160 1161 if (rx_mic)1162 memcpy(&key_buf->key[ptk_key_len], rx_mic,1163 WILC_RX_MIC_KEY_LEN);1164 1165 if (tx_mic)1166 memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],1167 tx_mic, WILC_TX_MIC_KEY_LEN);1168 1169 wid.id = WID_ADD_PTK;1170 wid.type = WID_STR;1171 wid.size = sizeof(*key_buf) + t_key_len;1172 wid.val = (s8 *)key_buf;1173 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1174 kfree(key_buf);1175 }1176 1177 return result;1178}1179 1180int wilc_add_igtk(struct wilc_vif *vif, const u8 *igtk, u8 igtk_key_len,1181 const u8 *pn, u8 pn_len, const u8 *mac_addr, u8 mode, u8 index)1182{1183 int result = 0;1184 u8 t_key_len = igtk_key_len;1185 struct wid wid;1186 struct wilc_wpa_igtk *key_buf;1187 1188 key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);1189 if (!key_buf)1190 return -ENOMEM;1191 1192 key_buf->index = index;1193 1194 memcpy(&key_buf->pn[0], pn, pn_len);1195 key_buf->pn_len = pn_len;1196 1197 memcpy(&key_buf->key[0], igtk, igtk_key_len);1198 key_buf->key_len = t_key_len;1199 1200 wid.id = WID_ADD_IGTK;1201 wid.type = WID_STR;1202 wid.size = sizeof(*key_buf) + t_key_len;1203 wid.val = (s8 *)key_buf;1204 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1205 kfree(key_buf);1206 1207 return result;1208}1209 1210int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,1211 u8 index, u32 key_rsc_len, const u8 *key_rsc,1212 const u8 *rx_mic, const u8 *tx_mic, u8 mode,1213 u8 cipher_mode)1214{1215 int result = 0;1216 struct wilc_gtk_key *gtk_key;1217 int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;1218 1219 gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL);1220 if (!gtk_key)1221 return -ENOMEM;1222 1223 /* fill bssid value only in station mode */1224 if (mode == WILC_STATION_MODE &&1225 vif->hif_drv->hif_state == HOST_IF_CONNECTED)1226 memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN);1227 1228 if (key_rsc)1229 memcpy(gtk_key->rsc, key_rsc, 8);1230 gtk_key->index = index;1231 gtk_key->key_len = t_key_len;1232 memcpy(>k_key->key[0], rx_gtk, gtk_key_len);1233 1234 if (rx_mic)1235 memcpy(>k_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN);1236 1237 if (tx_mic)1238 memcpy(>k_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN],1239 tx_mic, WILC_TX_MIC_KEY_LEN);1240 1241 if (mode == WILC_AP_MODE) {1242 struct wid wid_list[2];1243 1244 wid_list[0].id = WID_11I_MODE;1245 wid_list[0].type = WID_CHAR;1246 wid_list[0].size = sizeof(char);1247 wid_list[0].val = (s8 *)&cipher_mode;1248 1249 wid_list[1].id = WID_ADD_RX_GTK;1250 wid_list[1].type = WID_STR;1251 wid_list[1].size = sizeof(*gtk_key) + t_key_len;1252 wid_list[1].val = (u8 *)gtk_key;1253 1254 result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,1255 ARRAY_SIZE(wid_list));1256 } else if (mode == WILC_STATION_MODE) {1257 struct wid wid;1258 1259 wid.id = WID_ADD_RX_GTK;1260 wid.type = WID_STR;1261 wid.size = sizeof(*gtk_key) + t_key_len;1262 wid.val = (u8 *)gtk_key;1263 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1264 }1265 1266 kfree(gtk_key);1267 return result;1268}1269 1270int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid)1271{1272 struct wid wid;1273 1274 wid.id = WID_PMKID_INFO;1275 wid.type = WID_STR;1276 wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1;1277 wid.val = (u8 *)pmkid;1278 1279 return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1280}1281 1282int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr)1283{1284 int result;1285 struct wid wid;1286 1287 wid.id = WID_MAC_ADDR;1288 wid.type = WID_STR;1289 wid.size = ETH_ALEN;1290 wid.val = mac_addr;1291 1292 result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);1293 if (result)1294 netdev_err(vif->ndev, "Failed to get mac address\n");1295 1296 return result;1297}1298 1299int wilc_set_mac_address(struct wilc_vif *vif, const u8 *mac_addr)1300{1301 struct wid wid;1302 int result;1303 1304 wid.id = WID_MAC_ADDR;1305 wid.type = WID_STR;1306 wid.size = ETH_ALEN;1307 wid.val = (u8 *)mac_addr;1308 1309 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1310 if (result)1311 netdev_err(vif->ndev, "Failed to set mac address\n");1312 1313 return result;1314}1315 1316int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,1317 size_t ies_len)1318{1319 int result;1320 struct host_if_drv *hif_drv = vif->hif_drv;1321 struct wilc_conn_info *conn_info = &hif_drv->conn_info;1322 1323 if (bssid)1324 ether_addr_copy(conn_info->bssid, bssid);1325 1326 if (ies) {1327 conn_info->req_ies_len = ies_len;1328 conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL);1329 if (!conn_info->req_ies)1330 return -ENOMEM;1331 }1332 1333 result = wilc_send_connect_wid(vif);1334 if (result)1335 goto free_ies;1336 1337 hif_drv->connect_timer_vif = vif;1338 mod_timer(&hif_drv->connect_timer,1339 jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS));1340 1341 return 0;1342 1343free_ies:1344 kfree(conn_info->req_ies);1345 1346 return result;1347}1348 1349int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel)1350{1351 struct wid wid;1352 int result;1353 1354 wid.id = WID_CURRENT_CHANNEL;1355 wid.type = WID_CHAR;1356 wid.size = sizeof(char);1357 wid.val = &channel;1358 1359 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1360 if (result)1361 netdev_err(vif->ndev, "Failed to set channel\n");1362 1363 return result;1364}1365 1366int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,1367 u8 ifc_id)1368{1369 struct wid wid;1370 int result;1371 struct wilc_drv_handler drv;1372 1373 wid.id = WID_SET_OPERATION_MODE;1374 wid.type = WID_STR;1375 wid.size = sizeof(drv);1376 wid.val = (u8 *)&drv;1377 1378 drv.handler = cpu_to_le32(index);1379 drv.mode = (ifc_id | (mode << 1));1380 1381 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1382 if (result)1383 netdev_err(vif->ndev, "Failed to set driver handler\n");1384 1385 return result;1386}1387 1388s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val)1389{1390 struct wid wid;1391 s32 result;1392 1393 wid.id = WID_SET_STA_MAC_INACTIVE_TIME;1394 wid.type = WID_STR;1395 wid.size = ETH_ALEN;1396 wid.val = kzalloc(wid.size, GFP_KERNEL);1397 if (!wid.val)1398 return -ENOMEM;1399 1400 ether_addr_copy(wid.val, mac);1401 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1402 kfree(wid.val);1403 if (result) {1404 netdev_err(vif->ndev, "Failed to set inactive mac\n");1405 return result;1406 }1407 1408 wid.id = WID_GET_INACTIVE_TIME;1409 wid.type = WID_INT;1410 wid.val = (s8 *)out_val;1411 wid.size = sizeof(u32);1412 result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);1413 if (result)1414 netdev_err(vif->ndev, "Failed to get inactive time\n");1415 1416 return result;1417}1418 1419int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level)1420{1421 struct wid wid;1422 int result;1423 1424 if (!rssi_level) {1425 netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__);1426 return -EFAULT;1427 }1428 1429 wid.id = WID_RSSI;1430 wid.type = WID_CHAR;1431 wid.size = sizeof(char);1432 wid.val = rssi_level;1433 result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);1434 if (result)1435 netdev_err(vif->ndev, "Failed to get RSSI value\n");1436 1437 return result;1438}1439 1440static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats)1441{1442 int result;1443 struct host_if_msg *msg;1444 1445 msg = wilc_alloc_work(vif, handle_get_statistics, false);1446 if (IS_ERR(msg))1447 return PTR_ERR(msg);1448 1449 msg->body.data = (char *)stats;1450 1451 result = wilc_enqueue_work(msg);1452 if (result) {1453 netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);1454 kfree(msg);1455 return result;1456 }1457 1458 return result;1459}1460 1461int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param)1462{1463 struct wid wid_list[4];1464 int i = 0;1465 1466 if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) {1467 wid_list[i].id = WID_SHORT_RETRY_LIMIT;1468 wid_list[i].val = (s8 *)¶m->short_retry_limit;1469 wid_list[i].type = WID_SHORT;1470 wid_list[i].size = sizeof(u16);1471 i++;1472 }1473 if (param->flag & WILC_CFG_PARAM_RETRY_LONG) {1474 wid_list[i].id = WID_LONG_RETRY_LIMIT;1475 wid_list[i].val = (s8 *)¶m->long_retry_limit;1476 wid_list[i].type = WID_SHORT;1477 wid_list[i].size = sizeof(u16);1478 i++;1479 }1480 if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) {1481 wid_list[i].id = WID_FRAG_THRESHOLD;1482 wid_list[i].val = (s8 *)¶m->frag_threshold;1483 wid_list[i].type = WID_SHORT;1484 wid_list[i].size = sizeof(u16);1485 i++;1486 }1487 if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) {1488 wid_list[i].id = WID_RTS_THRESHOLD;1489 wid_list[i].val = (s8 *)¶m->rts_threshold;1490 wid_list[i].type = WID_SHORT;1491 wid_list[i].size = sizeof(u16);1492 i++;1493 }1494 1495 return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, i);1496}1497 1498static void get_periodic_rssi(struct timer_list *t)1499{1500 struct wilc_vif *vif = from_timer(vif, t, periodic_rssi);1501 1502 if (!vif->hif_drv) {1503 netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);1504 return;1505 }1506 1507 if (vif->hif_drv->hif_state == HOST_IF_CONNECTED)1508 wilc_get_stats_async(vif, &vif->periodic_stat);1509 1510 mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));1511}1512 1513int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler)1514{1515 struct host_if_drv *hif_drv;1516 struct wilc_vif *vif = netdev_priv(dev);1517 1518 hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL);1519 if (!hif_drv)1520 return -ENOMEM;1521 1522 *hif_drv_handler = hif_drv;1523 1524 vif->hif_drv = hif_drv;1525 1526 timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0);1527 mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000));1528 1529 timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0);1530 timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0);1531 timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0);1532 1533 hif_drv->hif_state = HOST_IF_IDLE;1534 1535 hif_drv->p2p_timeout = 0;1536 1537 return 0;1538}1539 1540int wilc_deinit(struct wilc_vif *vif)1541{1542 int result = 0;1543 struct host_if_drv *hif_drv = vif->hif_drv;1544 1545 if (!hif_drv) {1546 netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);1547 return -EFAULT;1548 }1549 1550 mutex_lock(&vif->wilc->deinit_lock);1551 1552 timer_shutdown_sync(&hif_drv->scan_timer);1553 timer_shutdown_sync(&hif_drv->connect_timer);1554 del_timer_sync(&vif->periodic_rssi);1555 timer_shutdown_sync(&hif_drv->remain_on_ch_timer);1556 1557 if (hif_drv->usr_scan_req.scan_result) {1558 hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,1559 hif_drv->usr_scan_req.priv);1560 hif_drv->usr_scan_req.scan_result = NULL;1561 }1562 1563 hif_drv->hif_state = HOST_IF_IDLE;1564 1565 kfree(hif_drv);1566 vif->hif_drv = NULL;1567 mutex_unlock(&vif->wilc->deinit_lock);1568 return result;1569}1570 1571void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length)1572{1573 struct host_if_drv *hif_drv;1574 struct host_if_msg *msg;1575 struct wilc_vif *vif;1576 int srcu_idx;1577 int result;1578 int id;1579 1580 id = get_unaligned_le32(&buffer[length - 4]);1581 srcu_idx = srcu_read_lock(&wilc->srcu);1582 vif = wilc_get_vif_from_idx(wilc, id);1583 if (!vif)1584 goto out;1585 1586 hif_drv = vif->hif_drv;1587 if (!hif_drv) {1588 netdev_err(vif->ndev, "driver not init[%p]\n", hif_drv);1589 goto out;1590 }1591 1592 msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false);1593 if (IS_ERR(msg))1594 goto out;1595 1596 msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1;1597 msg->body.net_info.rssi = buffer[8];1598 msg->body.net_info.mgmt = kmemdup(&buffer[9],1599 msg->body.net_info.frame_len,1600 GFP_KERNEL);1601 if (!msg->body.net_info.mgmt) {1602 kfree(msg);1603 goto out;1604 }1605 1606 result = wilc_enqueue_work(msg);1607 if (result) {1608 netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);1609 kfree(msg->body.net_info.mgmt);1610 kfree(msg);1611 }1612out:1613 srcu_read_unlock(&wilc->srcu, srcu_idx);1614}1615 1616void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length)1617{1618 struct host_if_drv *hif_drv;1619 struct host_if_msg *msg;1620 struct wilc_vif *vif;1621 int srcu_idx;1622 int result;1623 int id;1624 1625 mutex_lock(&wilc->deinit_lock);1626 1627 id = get_unaligned_le32(&buffer[length - 4]);1628 srcu_idx = srcu_read_lock(&wilc->srcu);1629 vif = wilc_get_vif_from_idx(wilc, id);1630 if (!vif)1631 goto out;1632 1633 hif_drv = vif->hif_drv;1634 1635 if (!hif_drv) {1636 goto out;1637 }1638 1639 if (!hif_drv->conn_info.conn_result) {1640 netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);1641 goto out;1642 }1643 1644 msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false);1645 if (IS_ERR(msg))1646 goto out;1647 1648 msg->body.mac_info.status = buffer[7];1649 result = wilc_enqueue_work(msg);1650 if (result) {1651 netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);1652 kfree(msg);1653 }1654out:1655 srcu_read_unlock(&wilc->srcu, srcu_idx);1656 mutex_unlock(&wilc->deinit_lock);1657}1658 1659void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length)1660{1661 struct host_if_drv *hif_drv;1662 struct wilc_vif *vif;1663 int srcu_idx;1664 int result;1665 int id;1666 1667 id = get_unaligned_le32(&buffer[length - 4]);1668 srcu_idx = srcu_read_lock(&wilc->srcu);1669 vif = wilc_get_vif_from_idx(wilc, id);1670 if (!vif)1671 goto out;1672 1673 hif_drv = vif->hif_drv;1674 if (!hif_drv) {1675 goto out;1676 }1677 1678 if (hif_drv->usr_scan_req.scan_result) {1679 struct host_if_msg *msg;1680 1681 msg = wilc_alloc_work(vif, handle_scan_complete, false);1682 if (IS_ERR(msg))1683 goto out;1684 1685 result = wilc_enqueue_work(msg);1686 if (result) {1687 netdev_err(vif->ndev, "%s: enqueue work failed\n",1688 __func__);1689 kfree(msg);1690 }1691 }1692out:1693 srcu_read_unlock(&wilc->srcu, srcu_idx);1694}1695 1696int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan,1697 void (*expired)(struct wilc_vif *, u64))1698{1699 struct wilc_remain_ch roc;1700 int result;1701 1702 roc.ch = chan;1703 roc.expired = expired;1704 roc.vif = vif;1705 roc.cookie = cookie;1706 result = handle_remain_on_chan(vif, &roc);1707 if (result)1708 netdev_err(vif->ndev, "%s: failed to set remain on channel\n",1709 __func__);1710 1711 return result;1712}1713 1714int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie)1715{1716 if (!vif->hif_drv) {1717 netdev_err(vif->ndev, "%s: hif driver is NULL", __func__);1718 return -EFAULT;1719 }1720 1721 del_timer(&vif->hif_drv->remain_on_ch_timer);1722 1723 return wilc_handle_roc_expired(vif, cookie);1724}1725 1726void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)1727{1728 struct wid wid;1729 int result;1730 struct wilc_reg_frame reg_frame;1731 1732 wid.id = WID_REGISTER_FRAME;1733 wid.type = WID_STR;1734 wid.size = sizeof(reg_frame);1735 wid.val = (u8 *)®_frame;1736 1737 memset(®_frame, 0x0, sizeof(reg_frame));1738 1739 if (reg)1740 reg_frame.reg = 1;1741 1742 switch (frame_type) {1743 case IEEE80211_STYPE_ACTION:1744 reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX;1745 break;1746 1747 case IEEE80211_STYPE_PROBE_REQ:1748 reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX;1749 break;1750 1751 case IEEE80211_STYPE_AUTH:1752 reg_frame.reg_id = WILC_FW_AUTH_REQ_IDX;1753 break;1754 1755 default:1756 break;1757 }1758 reg_frame.frame_type = cpu_to_le16(frame_type);1759 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1760 if (result)1761 netdev_err(vif->ndev, "Failed to frame register\n");1762}1763 1764int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period,1765 struct cfg80211_beacon_data *params)1766{1767 struct wid wid;1768 int result;1769 u8 *cur_byte;1770 1771 wid.id = WID_ADD_BEACON;1772 wid.type = WID_BIN;1773 wid.size = params->head_len + params->tail_len + 16;1774 wid.val = kzalloc(wid.size, GFP_KERNEL);1775 if (!wid.val)1776 return -ENOMEM;1777 1778 cur_byte = wid.val;1779 put_unaligned_le32(interval, cur_byte);1780 cur_byte += 4;1781 put_unaligned_le32(dtim_period, cur_byte);1782 cur_byte += 4;1783 put_unaligned_le32(params->head_len, cur_byte);1784 cur_byte += 4;1785 1786 if (params->head_len > 0)1787 memcpy(cur_byte, params->head, params->head_len);1788 cur_byte += params->head_len;1789 1790 put_unaligned_le32(params->tail_len, cur_byte);1791 cur_byte += 4;1792 1793 if (params->tail_len > 0)1794 memcpy(cur_byte, params->tail, params->tail_len);1795 1796 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1797 if (result)1798 netdev_err(vif->ndev, "Failed to send add beacon\n");1799 1800 kfree(wid.val);1801 1802 return result;1803}1804 1805int wilc_del_beacon(struct wilc_vif *vif)1806{1807 int result;1808 struct wid wid;1809 u8 del_beacon = 0;1810 1811 wid.id = WID_DEL_BEACON;1812 wid.type = WID_CHAR;1813 wid.size = sizeof(char);1814 wid.val = &del_beacon;1815 1816 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1817 if (result)1818 netdev_err(vif->ndev, "Failed to send delete beacon\n");1819 1820 return result;1821}1822 1823int wilc_add_station(struct wilc_vif *vif, const u8 *mac,1824 struct station_parameters *params)1825{1826 struct wid wid;1827 int result;1828 u8 *cur_byte;1829 1830 wid.id = WID_ADD_STA;1831 wid.type = WID_BIN;1832 wid.size = WILC_ADD_STA_LENGTH +1833 params->link_sta_params.supported_rates_len;1834 wid.val = kmalloc(wid.size, GFP_KERNEL);1835 if (!wid.val)1836 return -ENOMEM;1837 1838 cur_byte = wid.val;1839 wilc_hif_pack_sta_param(cur_byte, mac, params);1840 1841 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1842 if (result != 0)1843 netdev_err(vif->ndev, "Failed to send add station\n");1844 1845 kfree(wid.val);1846 1847 return result;1848}1849 1850int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr)1851{1852 struct wid wid;1853 int result;1854 1855 wid.id = WID_REMOVE_STA;1856 wid.type = WID_BIN;1857 wid.size = ETH_ALEN;1858 wid.val = kzalloc(wid.size, GFP_KERNEL);1859 if (!wid.val)1860 return -ENOMEM;1861 1862 if (!mac_addr)1863 eth_broadcast_addr(wid.val);1864 else1865 ether_addr_copy(wid.val, mac_addr);1866 1867 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1868 if (result)1869 netdev_err(vif->ndev, "Failed to del station\n");1870 1871 kfree(wid.val);1872 1873 return result;1874}1875 1876int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])1877{1878 struct wid wid;1879 int result;1880 int i;1881 u8 assoc_sta = 0;1882 struct wilc_del_all_sta del_sta;1883 1884 memset(&del_sta, 0x0, sizeof(del_sta));1885 for (i = 0; i < WILC_MAX_NUM_STA; i++) {1886 if (!is_zero_ether_addr(mac_addr[i])) {1887 assoc_sta++;1888 ether_addr_copy(del_sta.mac[i], mac_addr[i]);1889 }1890 }1891 1892 if (!assoc_sta)1893 return 0;1894 1895 del_sta.assoc_sta = assoc_sta;1896 1897 wid.id = WID_DEL_ALL_STA;1898 wid.type = WID_STR;1899 wid.size = (assoc_sta * ETH_ALEN) + 1;1900 wid.val = (u8 *)&del_sta;1901 1902 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1903 if (result)1904 netdev_err(vif->ndev, "Failed to send delete all station\n");1905 1906 return result;1907}1908 1909int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,1910 struct station_parameters *params)1911{1912 struct wid wid;1913 int result;1914 u8 *cur_byte;1915 1916 wid.id = WID_EDIT_STA;1917 wid.type = WID_BIN;1918 wid.size = WILC_ADD_STA_LENGTH +1919 params->link_sta_params.supported_rates_len;1920 wid.val = kmalloc(wid.size, GFP_KERNEL);1921 if (!wid.val)1922 return -ENOMEM;1923 1924 cur_byte = wid.val;1925 wilc_hif_pack_sta_param(cur_byte, mac, params);1926 1927 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1928 if (result)1929 netdev_err(vif->ndev, "Failed to send edit station\n");1930 1931 kfree(wid.val);1932 return result;1933}1934 1935int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)1936{1937 struct wilc *wilc = vif->wilc;1938 struct wid wid;1939 int result;1940 s8 power_mode;1941 1942 if (enabled)1943 power_mode = WILC_FW_MIN_FAST_PS;1944 else1945 power_mode = WILC_FW_NO_POWERSAVE;1946 1947 wid.id = WID_POWER_MANAGEMENT;1948 wid.val = &power_mode;1949 wid.size = sizeof(char);1950 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1951 if (result)1952 netdev_err(vif->ndev, "Failed to send power management\n");1953 else1954 wilc->power_save_mode = enabled;1955 1956 return result;1957}1958 1959int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,1960 u8 *mc_list)1961{1962 int result;1963 struct host_if_msg *msg;1964 1965 msg = wilc_alloc_work(vif, handle_set_mcast_filter, false);1966 if (IS_ERR(msg))1967 return PTR_ERR(msg);1968 1969 msg->body.mc_info.enabled = enabled;1970 msg->body.mc_info.cnt = count;1971 msg->body.mc_info.mc_list = mc_list;1972 1973 result = wilc_enqueue_work(msg);1974 if (result) {1975 netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);1976 kfree(msg);1977 }1978 return result;1979}1980 1981int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power)1982{1983 struct wid wid;1984 1985 wid.id = WID_TX_POWER;1986 wid.type = WID_CHAR;1987 wid.val = &tx_power;1988 wid.size = sizeof(char);1989 1990 return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1991}1992 1993int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)1994{1995 struct wid wid;1996 1997 wid.id = WID_TX_POWER;1998 wid.type = WID_CHAR;1999 wid.val = tx_power;2000 wid.size = sizeof(char);2001 2002 return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);2003}2004 2005int wilc_set_default_mgmt_key_index(struct wilc_vif *vif, u8 index)2006{2007 struct wid wid;2008 int result;2009 2010 wid.id = WID_DEFAULT_MGMT_KEY_ID;2011 wid.type = WID_CHAR;2012 wid.size = sizeof(char);2013 wid.val = &index;2014 result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);2015 if (result)2016 netdev_err(vif->ndev,2017 "Failed to send default mgmt key index\n");2018 2019 return result;2020}2021