Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   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 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 as
  89 * 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 index
  98 * of wilc->vif[], because we add 1 when pass to wilc device in the function
  99 * 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                else
 321                        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(&param->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			else
 443				param->supp_rates[0] += ext_rates;
 444
 445			memcpy(&param->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	else
 553		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(&gtk_key->key[0], rx_gtk, gtk_key_len);
1233
1234	if (rx_mic)
1235		memcpy(&gtk_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN);
1236
1237	if (tx_mic)
1238		memcpy(&gtk_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 *)&param->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 *)&param->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 *)&param->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 *)&param->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 *)&reg_frame;
1736
1737	memset(&reg_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	else
1865		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	else
1945		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	else
1954		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}