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