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(&param->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(&param->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(&gtk_key->key[0], rx_gtk, gtk_key_len);
1224
1225	if (rx_mic)
1226		memcpy(&gtk_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN);
1227
1228	if (tx_mic)
1229		memcpy(&gtk_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 *)&param->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 *)&param->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 *)&param->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 *)&param->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 *)&reg_frame;
1714
1715	memset(&reg_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