brintos

brintos / linux-shallow public Read only

0
0
Text · 48.7 KiB · bba5330 Raw
2021 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.4 * All rights reserved.5 */6 7#include "netdev.h"8 9#define WILC_HIF_SCAN_TIMEOUT_MS                500010#define WILC_HIF_CONNECT_TIMEOUT_MS             950011 12#define WILC_FALSE_FRMWR_CHANNEL		10013 14#define WILC_SCAN_WID_LIST_SIZE		615 16struct wilc_rcvd_mac_info {17	u8 status;18};19 20struct wilc_set_multicast {21	u32 enabled;22	u32 cnt;23	u8 *mc_list;24};25 26struct host_if_wowlan_trigger {27	u8 wowlan_trigger;28};29 30struct wilc_del_all_sta {31	u8 assoc_sta;32	u8 mac[WILC_MAX_NUM_STA][ETH_ALEN];33};34 35union wilc_message_body {36	struct wilc_rcvd_net_info net_info;37	struct wilc_rcvd_mac_info mac_info;38	struct wilc_set_multicast mc_info;39	struct wilc_remain_ch remain_on_ch;40	char *data;41	struct host_if_wowlan_trigger wow_trigger;42};43 44struct host_if_msg {45	union wilc_message_body body;46	struct wilc_vif *vif;47	struct work_struct work;48	void (*fn)(struct work_struct *ws);49	struct completion work_comp;50	bool is_sync;51};52 53/* 'msg' should be free by the caller for syc */54static struct host_if_msg*55wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *),56		bool is_sync)57{58	struct host_if_msg *msg;59 60	if (!work_fun)61		return ERR_PTR(-EINVAL);62 63	msg = kzalloc(sizeof(*msg), GFP_ATOMIC);64	if (!msg)65		return ERR_PTR(-ENOMEM);66	msg->fn = work_fun;67	msg->vif = vif;68	msg->is_sync = is_sync;69	if (is_sync)70		init_completion(&msg->work_comp);71 72	return msg;73}74 75static int wilc_enqueue_work(struct host_if_msg *msg)76{77	INIT_WORK(&msg->work, msg->fn);78 79	if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue)80		return -EINVAL;81 82	if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work))83		return -EINVAL;84 85	return 0;86}87 88/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as89 * special purpose in wilc device, so we add 1 to the index to starts from 1.90 * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC.91 */92int wilc_get_vif_idx(struct wilc_vif *vif)93{94	return vif->idx + 1;95}96 97/* We need to minus 1 from idx which is from wilc device to get real index98 * of wilc->vif[], because we add 1 when pass to wilc device in the function99 * wilc_get_vif_idx.100 * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1).101 */102static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx)103{104	int index = idx - 1;105	struct wilc_vif *vif;106 107	if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC)108		return NULL;109 110	wilc_for_each_vif(wilc, vif) {111		if (vif->idx == index)112			return vif;113	}114 115	return NULL;116}117 118static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt)119{120	int result = 0;121	u8 abort_running_scan;122	struct wid wid;123	struct host_if_drv *hif_drv = vif->hif_drv;124	struct wilc_user_scan_req *scan_req;125 126	if (evt == SCAN_EVENT_ABORTED) {127		abort_running_scan = 1;128		wid.id = WID_ABORT_RUNNING_SCAN;129		wid.type = WID_CHAR;130		wid.val = (s8 *)&abort_running_scan;131		wid.size = sizeof(char);132 133		result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);134		if (result) {135			netdev_err(vif->ndev, "Failed to set abort running\n");136			result = -EFAULT;137		}138	}139 140	if (!hif_drv) {141		netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);142		return result;143	}144 145	scan_req = &hif_drv->usr_scan_req;146	if (scan_req->scan_result) {147		scan_req->scan_result(evt, NULL, scan_req->priv);148		scan_req->scan_result = NULL;149	}150 151	return result;152}153 154int wilc_scan(struct wilc_vif *vif, u8 scan_source,155	      u8 scan_type, u8 *ch_freq_list,156	      void (*scan_result_fn)(enum scan_event,157				     struct wilc_rcvd_net_info *,158				     struct wilc_priv *),159	      struct cfg80211_scan_request *request)160{161	int result = 0;162	struct wid wid_list[WILC_SCAN_WID_LIST_SIZE];163	u32 index = 0;164	u32 i, scan_timeout;165	u8 *buffer;166	u8 valuesize = 0;167	u8 *search_ssid_vals = NULL;168	const u8 ch_list_len = request->n_channels;169	struct host_if_drv *hif_drv = vif->hif_drv;170 171	if (hif_drv->hif_state >= HOST_IF_SCANNING &&172	    hif_drv->hif_state < HOST_IF_CONNECTED) {173		netdev_err(vif->ndev, "Already scan\n");174		result = -EBUSY;175		goto error;176	}177 178	if (vif->connecting) {179		netdev_err(vif->ndev, "Don't do obss scan\n");180		result = -EBUSY;181		goto error;182	}183 184	hif_drv->usr_scan_req.ch_cnt = 0;185 186	if (request->n_ssids) {187		for (i = 0; i < request->n_ssids; i++)188			valuesize += ((request->ssids[i].ssid_len) + 1);189		search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL);190		if (search_ssid_vals) {191			wid_list[index].id = WID_SSID_PROBE_REQ;192			wid_list[index].type = WID_STR;193			wid_list[index].val = search_ssid_vals;194			buffer = wid_list[index].val;195 196			*buffer++ = request->n_ssids;197 198			for (i = 0; i < request->n_ssids; i++) {199				*buffer++ = request->ssids[i].ssid_len;200				memcpy(buffer, request->ssids[i].ssid,201				       request->ssids[i].ssid_len);202				buffer += request->ssids[i].ssid_len;203			}204			wid_list[index].size = (s32)(valuesize + 1);205			index++;206		}207	}208 209	wid_list[index].id = WID_INFO_ELEMENT_PROBE;210	wid_list[index].type = WID_BIN_DATA;211	wid_list[index].val = (s8 *)request->ie;212	wid_list[index].size = request->ie_len;213	index++;214 215	wid_list[index].id = WID_SCAN_TYPE;216	wid_list[index].type = WID_CHAR;217	wid_list[index].size = sizeof(char);218	wid_list[index].val = (s8 *)&scan_type;219	index++;220 221	if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) {222		wid_list[index].id = WID_PASSIVE_SCAN_TIME;223		wid_list[index].type = WID_SHORT;224		wid_list[index].size = sizeof(u16);225		wid_list[index].val = (s8 *)&request->duration;226		index++;227 228		scan_timeout = (request->duration * ch_list_len) + 500;229	} else {230		scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS;231	}232 233	wid_list[index].id = WID_SCAN_CHANNEL_LIST;234	wid_list[index].type = WID_BIN_DATA;235 236	if (ch_freq_list && ch_list_len > 0) {237		for (i = 0; i < ch_list_len; i++) {238			if (ch_freq_list[i] > 0)239				ch_freq_list[i] -= 1;240		}241	}242 243	wid_list[index].val = ch_freq_list;244	wid_list[index].size = ch_list_len;245	index++;246 247	wid_list[index].id = WID_START_SCAN_REQ;248	wid_list[index].type = WID_CHAR;249	wid_list[index].size = sizeof(char);250	wid_list[index].val = (s8 *)&scan_source;251	index++;252 253	hif_drv->usr_scan_req.scan_result = scan_result_fn;254	hif_drv->usr_scan_req.priv = &vif->priv;255 256	result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index);257	if (result) {258		netdev_err(vif->ndev, "Failed to send scan parameters\n");259		goto error;260	}261 262	hif_drv->scan_timer_vif = vif;263	mod_timer(&hif_drv->scan_timer,264		  jiffies + msecs_to_jiffies(scan_timeout));265 266error:267 268	kfree(search_ssid_vals);269 270	return result;271}272 273static int wilc_send_connect_wid(struct wilc_vif *vif)274{275	int result = 0;276	struct wid wid_list[5];277	u32 wid_cnt = 0;278	struct host_if_drv *hif_drv = vif->hif_drv;279	struct wilc_conn_info *conn_attr = &hif_drv->conn_info;280	struct wilc_join_bss_param *bss_param = conn_attr->param;281 282 283        wid_list[wid_cnt].id = WID_SET_MFP;284        wid_list[wid_cnt].type = WID_CHAR;285        wid_list[wid_cnt].size = sizeof(char);286        wid_list[wid_cnt].val = (s8 *)&conn_attr->mfp_type;287        wid_cnt++;288 289	wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;290	wid_list[wid_cnt].type = WID_BIN_DATA;291	wid_list[wid_cnt].val = conn_attr->req_ies;292	wid_list[wid_cnt].size = conn_attr->req_ies_len;293	wid_cnt++;294 295	wid_list[wid_cnt].id = WID_11I_MODE;296	wid_list[wid_cnt].type = WID_CHAR;297	wid_list[wid_cnt].size = sizeof(char);298	wid_list[wid_cnt].val = (s8 *)&conn_attr->security;299	wid_cnt++;300 301	wid_list[wid_cnt].id = WID_AUTH_TYPE;302	wid_list[wid_cnt].type = WID_CHAR;303	wid_list[wid_cnt].size = sizeof(char);304	wid_list[wid_cnt].val = (s8 *)&conn_attr->auth_type;305	wid_cnt++;306 307	wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED;308	wid_list[wid_cnt].type = WID_STR;309	wid_list[wid_cnt].size = sizeof(*bss_param);310	wid_list[wid_cnt].val = (u8 *)bss_param;311	wid_cnt++;312 313	result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt);314	if (result) {315		netdev_err(vif->ndev, "failed to send config packet\n");316		goto error;317	} else {318                if (conn_attr->auth_type == WILC_FW_AUTH_SAE)319                        hif_drv->hif_state = HOST_IF_EXTERNAL_AUTH;320                else321                        hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;322	}323 324	return 0;325 326error:327 328	kfree(conn_attr->req_ies);329	conn_attr->req_ies = NULL;330 331	return result;332}333 334static void handle_connect_timeout(struct work_struct *work)335{336	struct host_if_msg *msg = container_of(work, struct host_if_msg, work);337	struct wilc_vif *vif = msg->vif;338	int result;339	struct wid wid;340	u16 dummy_reason_code = 0;341	struct host_if_drv *hif_drv = vif->hif_drv;342 343	if (!hif_drv) {344		netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);345		goto out;346	}347 348	hif_drv->hif_state = HOST_IF_IDLE;349 350	if (hif_drv->conn_info.conn_result) {351		hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP,352					       WILC_MAC_STATUS_DISCONNECTED,353					       hif_drv->conn_info.priv);354 355	} else {356		netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);357	}358 359	wid.id = WID_DISCONNECT;360	wid.type = WID_CHAR;361	wid.val = (s8 *)&dummy_reason_code;362	wid.size = sizeof(char);363 364	result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);365	if (result)366		netdev_err(vif->ndev, "Failed to send disconnect\n");367 368	hif_drv->conn_info.req_ies_len = 0;369	kfree(hif_drv->conn_info.req_ies);370	hif_drv->conn_info.req_ies = NULL;371 372out:373	kfree(msg);374}375 376struct wilc_join_bss_param *377wilc_parse_join_bss_param(struct cfg80211_bss *bss,378			  struct cfg80211_crypto_settings *crypto)379{380	const u8 *ies_data, *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie;381	const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie;382	struct ieee80211_p2p_noa_attr noa_attr;383	const struct cfg80211_bss_ies *ies;384	struct wilc_join_bss_param *param;385	u8 rates_len = 0;386	int ies_len;387	u64 ies_tsf;388	int ret;389 390	param = kzalloc(sizeof(*param), GFP_KERNEL);391	if (!param)392		return NULL;393 394	rcu_read_lock();395	ies = rcu_dereference(bss->ies);396	ies_data = kmemdup(ies->data, ies->len, GFP_ATOMIC);397	if (!ies_data) {398		rcu_read_unlock();399		kfree(param);400		return NULL;401	}402	ies_len = ies->len;403	ies_tsf = ies->tsf;404	rcu_read_unlock();405 406	param->beacon_period = cpu_to_le16(bss->beacon_interval);407	param->cap_info = cpu_to_le16(bss->capability);408	param->bss_type = WILC_FW_BSS_TYPE_INFRA;409	param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq);410	ether_addr_copy(param->bssid, bss->bssid);411 412	ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies_data, ies_len);413	if (ssid_elm) {414		if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN)415			memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]);416	}417 418	tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies_data, ies_len);419	if (tim_elm && tim_elm[1] >= 2)420		param->dtim_period = tim_elm[3];421 422	memset(param->p_suites, 0xFF, 3);423	memset(param->akm_suites, 0xFF, 3);424 425	rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies_data, ies_len);426	if (rates_ie) {427		rates_len = rates_ie[1];428		if (rates_len > WILC_MAX_RATES_SUPPORTED)429			rates_len = WILC_MAX_RATES_SUPPORTED;430		param->supp_rates[0] = rates_len;431		memcpy(&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			else443				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	else553		goto done;554 555	ies = rcvd_info->mgmt->u.beacon.variable;556	ies_len = rcvd_info->frame_len - offset;557	if (ies_len <= 0)558		goto done;559 560	ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len);561	if (ch_elm && ch_elm[1] > 0)562		rcvd_info->ch = ch_elm[2];563 564	if (scan_req->scan_result)565		scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info,566				      scan_req->priv);567 568done:569	kfree(rcvd_info->mgmt);570	kfree(msg);571}572 573static void host_int_get_assoc_res_info(struct wilc_vif *vif,574					u8 *assoc_resp_info,575					u32 max_assoc_resp_info_len,576					u32 *rcvd_assoc_resp_info_len)577{578	int result;579	struct wid wid;580 581	wid.id = WID_ASSOC_RES_INFO;582	wid.type = WID_STR;583	wid.val = assoc_resp_info;584	wid.size = max_assoc_resp_info_len;585 586	result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);587	if (result) {588		*rcvd_assoc_resp_info_len = 0;589		netdev_err(vif->ndev, "Failed to send association response\n");590		return;591	}592 593	*rcvd_assoc_resp_info_len = wid.size;594}595 596static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,597				      struct wilc_conn_info *ret_conn_info)598{599	u8 *ies;600	u16 ies_len;601	struct wilc_assoc_resp *res = (struct wilc_assoc_resp *)buffer;602 603	ret_conn_info->status = le16_to_cpu(res->status_code);604	if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {605		ies = &buffer[sizeof(*res)];606		ies_len = buffer_len - sizeof(*res);607 608		ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL);609		if (!ret_conn_info->resp_ies)610			return -ENOMEM;611 612		ret_conn_info->resp_ies_len = ies_len;613	}614 615	return 0;616}617 618static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,619						  u8 mac_status)620{621	struct host_if_drv *hif_drv = vif->hif_drv;622	struct wilc_conn_info *conn_info = &hif_drv->conn_info;623 624	if (mac_status == WILC_MAC_STATUS_CONNECTED) {625		u32 assoc_resp_info_len;626 627		memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE);628 629		host_int_get_assoc_res_info(vif, hif_drv->assoc_resp,630					    WILC_MAX_ASSOC_RESP_FRAME_SIZE,631					    &assoc_resp_info_len);632 633		if (assoc_resp_info_len != 0) {634			s32 err = 0;635 636			err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp,637							 assoc_resp_info_len,638							 conn_info);639			if (err)640				netdev_err(vif->ndev,641					   "wilc_parse_assoc_resp_info() returned error %d\n",642					   err);643		}644	}645 646	del_timer(&hif_drv->connect_timer);647	conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,648			       hif_drv->conn_info.priv);649 650	if (mac_status == WILC_MAC_STATUS_CONNECTED &&651	    conn_info->status == WLAN_STATUS_SUCCESS) {652		ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid);653		hif_drv->hif_state = HOST_IF_CONNECTED;654	} else {655		hif_drv->hif_state = HOST_IF_IDLE;656	}657 658	kfree(conn_info->resp_ies);659	conn_info->resp_ies = NULL;660	conn_info->resp_ies_len = 0;661 662	kfree(conn_info->req_ies);663	conn_info->req_ies = NULL;664	conn_info->req_ies_len = 0;665}666 667void wilc_handle_disconnect(struct wilc_vif *vif)668{669	struct host_if_drv *hif_drv = vif->hif_drv;670 671	if (hif_drv->usr_scan_req.scan_result) {672		del_timer(&hif_drv->scan_timer);673		handle_scan_done(vif, SCAN_EVENT_ABORTED);674	}675 676	if (hif_drv->conn_info.conn_result)677		hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,678					       0, hif_drv->conn_info.priv);679 680	eth_zero_addr(hif_drv->assoc_bssid);681 682	hif_drv->conn_info.req_ies_len = 0;683	kfree(hif_drv->conn_info.req_ies);684	hif_drv->conn_info.req_ies = NULL;685	hif_drv->hif_state = HOST_IF_IDLE;686}687 688static void handle_rcvd_gnrl_async_info(struct work_struct *work)689{690	struct host_if_msg *msg = container_of(work, struct host_if_msg, work);691	struct wilc_vif *vif = msg->vif;692	struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info;693	struct host_if_drv *hif_drv = vif->hif_drv;694 695	if (!hif_drv) {696		netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__);697		goto free_msg;698	}699 700	if (!hif_drv->conn_info.conn_result) {701		netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);702		goto free_msg;703	}704 705 706        if (hif_drv->hif_state == HOST_IF_EXTERNAL_AUTH) {707                cfg80211_external_auth_request(vif->ndev, &vif->auth,708					       GFP_KERNEL);709                hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;710        } else if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {711		host_int_parse_assoc_resp_info(vif, mac_info->status);712	} else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) {713		if (hif_drv->hif_state == HOST_IF_CONNECTED) {714			wilc_handle_disconnect(vif);715		} else if (hif_drv->usr_scan_req.scan_result) {716			del_timer(&hif_drv->scan_timer);717			handle_scan_done(vif, SCAN_EVENT_ABORTED);718		}719	}720 721free_msg:722	kfree(msg);723}724 725int wilc_disconnect(struct wilc_vif *vif)726{727	struct wid wid;728	struct host_if_drv *hif_drv = vif->hif_drv;729	struct wilc_user_scan_req *scan_req;730	struct wilc_conn_info *conn_info;731	int result;732	u16 dummy_reason_code = 0;733 734	wid.id = WID_DISCONNECT;735	wid.type = WID_CHAR;736	wid.val = (s8 *)&dummy_reason_code;737	wid.size = sizeof(char);738 739	result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);740	if (result) {741		netdev_err(vif->ndev, "Failed to send disconnect\n");742		return result;743	}744 745	scan_req = &hif_drv->usr_scan_req;746	conn_info = &hif_drv->conn_info;747 748	if (scan_req->scan_result) {749		del_timer(&hif_drv->scan_timer);750		scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->priv);751		scan_req->scan_result = NULL;752	}753 754	if (conn_info->conn_result) {755		if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||756		    hif_drv->hif_state == HOST_IF_EXTERNAL_AUTH)757			del_timer(&hif_drv->connect_timer);758 759		conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,760				       conn_info->priv);761	} else {762		netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);763	}764 765	hif_drv->hif_state = HOST_IF_IDLE;766 767	eth_zero_addr(hif_drv->assoc_bssid);768 769	conn_info->req_ies_len = 0;770	kfree(conn_info->req_ies);771	conn_info->req_ies = NULL;772 773	return 0;774}775 776int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats)777{778	struct wid wid_list[5];779	u32 wid_cnt = 0, result;780 781	wid_list[wid_cnt].id = WID_LINKSPEED;782	wid_list[wid_cnt].type = WID_CHAR;783	wid_list[wid_cnt].size = sizeof(char);784	wid_list[wid_cnt].val = (s8 *)&stats->link_speed;785	wid_cnt++;786 787	wid_list[wid_cnt].id = WID_RSSI;788	wid_list[wid_cnt].type = WID_CHAR;789	wid_list[wid_cnt].size = sizeof(char);790	wid_list[wid_cnt].val = (s8 *)&stats->rssi;791	wid_cnt++;792 793	wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT;794	wid_list[wid_cnt].type = WID_INT;795	wid_list[wid_cnt].size = sizeof(u32);796	wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt;797	wid_cnt++;798 799	wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT;800	wid_list[wid_cnt].type = WID_INT;801	wid_list[wid_cnt].size = sizeof(u32);802	wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt;803	wid_cnt++;804 805	wid_list[wid_cnt].id = WID_FAILED_COUNT;806	wid_list[wid_cnt].type = WID_INT;807	wid_list[wid_cnt].size = sizeof(u32);808	wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt;809	wid_cnt++;810 811	result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list, wid_cnt);812	if (result) {813		netdev_err(vif->ndev, "Failed to send scan parameters\n");814		return result;815	}816 817	if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH &&818	    stats->link_speed != DEFAULT_LINK_SPEED)819		wilc_enable_tcp_ack_filter(vif, true);820	else if (stats->link_speed != DEFAULT_LINK_SPEED)821		wilc_enable_tcp_ack_filter(vif, false);822 823	return result;824}825 826static void handle_get_statistics(struct work_struct *work)827{828	struct host_if_msg *msg = container_of(work, struct host_if_msg, work);829	struct wilc_vif *vif = msg->vif;830	struct rf_info *stats = (struct rf_info *)msg->body.data;831 832	wilc_get_statistics(vif, stats);833 834	kfree(msg);835}836 837static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,838				    struct station_parameters *params)839{840	ether_addr_copy(cur_byte, mac);841	cur_byte += ETH_ALEN;842 843	put_unaligned_le16(params->aid, cur_byte);844	cur_byte += 2;845 846	*cur_byte++ = params->link_sta_params.supported_rates_len;847	if (params->link_sta_params.supported_rates_len > 0)848		memcpy(cur_byte, params->link_sta_params.supported_rates,849		       params->link_sta_params.supported_rates_len);850	cur_byte += params->link_sta_params.supported_rates_len;851 852	if (params->link_sta_params.ht_capa) {853		*cur_byte++ = true;854		memcpy(cur_byte, params->link_sta_params.ht_capa,855		       sizeof(struct ieee80211_ht_cap));856	} else {857		*cur_byte++ = false;858	}859	cur_byte += sizeof(struct ieee80211_ht_cap);860 861	put_unaligned_le16(params->sta_flags_mask, cur_byte);862	cur_byte += 2;863	put_unaligned_le16(params->sta_flags_set, cur_byte);864}865 866static int handle_remain_on_chan(struct wilc_vif *vif,867				 struct wilc_remain_ch *hif_remain_ch)868{869	int result;870	u8 remain_on_chan_flag;871	struct wid wid;872	struct host_if_drv *hif_drv = vif->hif_drv;873 874	if (hif_drv->usr_scan_req.scan_result)875		return -EBUSY;876 877	if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)878		return -EBUSY;879 880	if (vif->connecting)881		return -EBUSY;882 883	remain_on_chan_flag = true;884	wid.id = WID_REMAIN_ON_CHAN;885	wid.type = WID_STR;886	wid.size = 2;887	wid.val = kmalloc(wid.size, GFP_KERNEL);888	if (!wid.val)889		return -ENOMEM;890 891	wid.val[0] = remain_on_chan_flag;892	wid.val[1] = (s8)hif_remain_ch->ch;893 894	result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);895	kfree(wid.val);896	if (result)897		return -EBUSY;898 899	hif_drv->remain_on_ch.vif = hif_remain_ch->vif;900	hif_drv->remain_on_ch.expired = hif_remain_ch->expired;901	hif_drv->remain_on_ch.ch = hif_remain_ch->ch;902	hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie;903	hif_drv->remain_on_ch_timer_vif = vif;904 905	return 0;906}907 908static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)909{910	u8 remain_on_chan_flag;911	struct wid wid;912	int result;913	struct host_if_drv *hif_drv = vif->hif_drv;914 915	if (vif->priv.p2p_listen_state) {916		remain_on_chan_flag = false;917		wid.id = WID_REMAIN_ON_CHAN;918		wid.type = WID_STR;919		wid.size = 2;920 921		wid.val = kmalloc(wid.size, GFP_KERNEL);922		if (!wid.val)923			return -ENOMEM;924 925		wid.val[0] = remain_on_chan_flag;926		wid.val[1] = WILC_FALSE_FRMWR_CHANNEL;927 928		result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);929		kfree(wid.val);930		if (result != 0) {931			netdev_err(vif->ndev, "Failed to set remain channel\n");932			return -EINVAL;933		}934 935		if (hif_drv->remain_on_ch.expired) {936			hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.vif,937						      cookie);938		}939	} else {940		netdev_dbg(vif->ndev, "Not in listen state\n");941	}942 943	return 0;944}945 946static void wilc_handle_listen_state_expired(struct work_struct *work)947{948	struct host_if_msg *msg = container_of(work, struct host_if_msg, work);949 950	wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie);951	kfree(msg);952}953 954static void listen_timer_cb(struct timer_list *t)955{956	struct host_if_drv *hif_drv = from_timer(hif_drv, t,957						      remain_on_ch_timer);958	struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif;959	int result;960	struct host_if_msg *msg;961 962	del_timer(&vif->hif_drv->remain_on_ch_timer);963 964	msg = wilc_alloc_work(vif, wilc_handle_listen_state_expired, false);965	if (IS_ERR(msg))966		return;967 968	msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie;969 970	result = wilc_enqueue_work(msg);971	if (result) {972		netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);973		kfree(msg);974	}975}976 977static void handle_set_mcast_filter(struct work_struct *work)978{979	struct host_if_msg *msg = container_of(work, struct host_if_msg, work);980	struct wilc_vif *vif = msg->vif;981	struct wilc_set_multicast *set_mc = &msg->body.mc_info;982	int result;983	struct wid wid;984	u8 *cur_byte;985 986	wid.id = WID_SETUP_MULTICAST_FILTER;987	wid.type = WID_BIN;988	wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN);989	wid.val = kmalloc(wid.size, GFP_KERNEL);990	if (!wid.val)991		goto error;992 993	cur_byte = wid.val;994	put_unaligned_le32(set_mc->enabled, cur_byte);995	cur_byte += 4;996 997	put_unaligned_le32(set_mc->cnt, cur_byte);998	cur_byte += 4;999 1000	if (set_mc->cnt > 0 && set_mc->mc_list)1001		memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN);1002 1003	result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1004	if (result)1005		netdev_err(vif->ndev, "Failed to send setup multicast\n");1006 1007error:1008	kfree(set_mc->mc_list);1009	kfree(wid.val);1010	kfree(msg);1011}1012 1013void wilc_set_wowlan_trigger(struct wilc_vif *vif, bool enabled)1014{1015	int ret;1016	struct wid wid;1017	u8 wowlan_trigger = 0;1018 1019	if (enabled)1020		wowlan_trigger = 1;1021 1022	wid.id = WID_WOWLAN_TRIGGER;1023	wid.type = WID_CHAR;1024	wid.val = &wowlan_trigger;1025	wid.size = sizeof(char);1026 1027	ret = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1028	if (ret)1029		pr_err("Failed to send wowlan trigger config packet\n");1030}1031 1032int wilc_set_external_auth_param(struct wilc_vif *vif,1033				 struct cfg80211_external_auth_params *auth)1034{1035	int ret;1036	struct wid wid;1037	struct wilc_external_auth_param *param;1038 1039	wid.id = WID_EXTERNAL_AUTH_PARAM;1040	wid.type = WID_BIN_DATA;1041	wid.size = sizeof(*param);1042	param = kzalloc(sizeof(*param), GFP_KERNEL);1043	if (!param)1044		return -EINVAL;1045 1046	wid.val = (u8 *)param;1047	param->action = auth->action;1048	ether_addr_copy(param->bssid, auth->bssid);1049	memcpy(param->ssid, auth->ssid.ssid, auth->ssid.ssid_len);1050	param->ssid_len = auth->ssid.ssid_len;1051	ret = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1052 1053	kfree(param);1054	return ret;1055}1056 1057static void handle_scan_timer(struct work_struct *work)1058{1059	struct host_if_msg *msg = container_of(work, struct host_if_msg, work);1060 1061	handle_scan_done(msg->vif, SCAN_EVENT_ABORTED);1062	kfree(msg);1063}1064 1065static void handle_scan_complete(struct work_struct *work)1066{1067	struct host_if_msg *msg = container_of(work, struct host_if_msg, work);1068 1069	del_timer(&msg->vif->hif_drv->scan_timer);1070 1071	handle_scan_done(msg->vif, SCAN_EVENT_DONE);1072 1073	kfree(msg);1074}1075 1076static void timer_scan_cb(struct timer_list *t)1077{1078	struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer);1079	struct wilc_vif *vif = hif_drv->scan_timer_vif;1080	struct host_if_msg *msg;1081	int result;1082 1083	msg = wilc_alloc_work(vif, handle_scan_timer, false);1084	if (IS_ERR(msg))1085		return;1086 1087	result = wilc_enqueue_work(msg);1088	if (result)1089		kfree(msg);1090}1091 1092static void timer_connect_cb(struct timer_list *t)1093{1094	struct host_if_drv *hif_drv = from_timer(hif_drv, t,1095						      connect_timer);1096	struct wilc_vif *vif = hif_drv->connect_timer_vif;1097	struct host_if_msg *msg;1098	int result;1099 1100	msg = wilc_alloc_work(vif, handle_connect_timeout, false);1101	if (IS_ERR(msg))1102		return;1103 1104	result = wilc_enqueue_work(msg);1105	if (result)1106		kfree(msg);1107}1108 1109int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,1110		 const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,1111		 u8 mode, u8 cipher_mode, u8 index)1112{1113	int result = 0;1114	u8 t_key_len  = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;1115 1116	if (mode == WILC_AP_MODE) {1117		struct wid wid_list[2];1118		struct wilc_ap_wpa_ptk *key_buf;1119 1120		wid_list[0].id = WID_11I_MODE;1121		wid_list[0].type = WID_CHAR;1122		wid_list[0].size = sizeof(char);1123		wid_list[0].val = (s8 *)&cipher_mode;1124 1125		key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);1126		if (!key_buf)1127			return -ENOMEM;1128 1129		ether_addr_copy(key_buf->mac_addr, mac_addr);1130		key_buf->index = index;1131		key_buf->key_len = t_key_len;1132		memcpy(&key_buf->key[0], ptk, ptk_key_len);1133 1134		if (rx_mic)1135			memcpy(&key_buf->key[ptk_key_len], rx_mic,1136			       WILC_RX_MIC_KEY_LEN);1137 1138		if (tx_mic)1139			memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],1140			       tx_mic, WILC_TX_MIC_KEY_LEN);1141 1142		wid_list[1].id = WID_ADD_PTK;1143		wid_list[1].type = WID_STR;1144		wid_list[1].size = sizeof(*key_buf) + t_key_len;1145		wid_list[1].val = (u8 *)key_buf;1146		result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,1147					      ARRAY_SIZE(wid_list));1148		kfree(key_buf);1149	} else if (mode == WILC_STATION_MODE) {1150		struct wid wid;1151		struct wilc_sta_wpa_ptk *key_buf;1152 1153		key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);1154		if (!key_buf)1155			return -ENOMEM;1156 1157		ether_addr_copy(key_buf->mac_addr, mac_addr);1158		key_buf->key_len = t_key_len;1159		memcpy(&key_buf->key[0], ptk, ptk_key_len);1160 1161		if (rx_mic)1162			memcpy(&key_buf->key[ptk_key_len], rx_mic,1163			       WILC_RX_MIC_KEY_LEN);1164 1165		if (tx_mic)1166			memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN],1167			       tx_mic, WILC_TX_MIC_KEY_LEN);1168 1169		wid.id = WID_ADD_PTK;1170		wid.type = WID_STR;1171		wid.size = sizeof(*key_buf) + t_key_len;1172		wid.val = (s8 *)key_buf;1173		result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1174		kfree(key_buf);1175	}1176 1177	return result;1178}1179 1180int wilc_add_igtk(struct wilc_vif *vif, const u8 *igtk, u8 igtk_key_len,1181		  const u8 *pn, u8 pn_len, const u8 *mac_addr, u8 mode, u8 index)1182{1183	int result = 0;1184	u8 t_key_len = igtk_key_len;1185	struct wid wid;1186	struct wilc_wpa_igtk *key_buf;1187 1188	key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);1189	if (!key_buf)1190		return -ENOMEM;1191 1192	key_buf->index = index;1193 1194	memcpy(&key_buf->pn[0], pn, pn_len);1195	key_buf->pn_len = pn_len;1196 1197	memcpy(&key_buf->key[0], igtk, igtk_key_len);1198	key_buf->key_len = t_key_len;1199 1200	wid.id = WID_ADD_IGTK;1201	wid.type = WID_STR;1202	wid.size = sizeof(*key_buf) + t_key_len;1203	wid.val = (s8 *)key_buf;1204	result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1205	kfree(key_buf);1206 1207	return result;1208}1209 1210int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,1211		    u8 index, u32 key_rsc_len, const u8 *key_rsc,1212		    const u8 *rx_mic, const u8 *tx_mic, u8 mode,1213		    u8 cipher_mode)1214{1215	int result = 0;1216	struct wilc_gtk_key *gtk_key;1217	int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN;1218 1219	gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL);1220	if (!gtk_key)1221		return -ENOMEM;1222 1223	/* fill bssid value only in station mode */1224	if (mode == WILC_STATION_MODE &&1225	    vif->hif_drv->hif_state == HOST_IF_CONNECTED)1226		memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN);1227 1228	if (key_rsc)1229		memcpy(gtk_key->rsc, key_rsc, 8);1230	gtk_key->index = index;1231	gtk_key->key_len = t_key_len;1232	memcpy(&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	else1865		ether_addr_copy(wid.val, mac_addr);1866 1867	result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1868	if (result)1869		netdev_err(vif->ndev, "Failed to del station\n");1870 1871	kfree(wid.val);1872 1873	return result;1874}1875 1876int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN])1877{1878	struct wid wid;1879	int result;1880	int i;1881	u8 assoc_sta = 0;1882	struct wilc_del_all_sta del_sta;1883 1884	memset(&del_sta, 0x0, sizeof(del_sta));1885	for (i = 0; i < WILC_MAX_NUM_STA; i++) {1886		if (!is_zero_ether_addr(mac_addr[i])) {1887			assoc_sta++;1888			ether_addr_copy(del_sta.mac[i], mac_addr[i]);1889		}1890	}1891 1892	if (!assoc_sta)1893		return 0;1894 1895	del_sta.assoc_sta = assoc_sta;1896 1897	wid.id = WID_DEL_ALL_STA;1898	wid.type = WID_STR;1899	wid.size = (assoc_sta * ETH_ALEN) + 1;1900	wid.val = (u8 *)&del_sta;1901 1902	result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1903	if (result)1904		netdev_err(vif->ndev, "Failed to send delete all station\n");1905 1906	return result;1907}1908 1909int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,1910		      struct station_parameters *params)1911{1912	struct wid wid;1913	int result;1914	u8 *cur_byte;1915 1916	wid.id = WID_EDIT_STA;1917	wid.type = WID_BIN;1918	wid.size = WILC_ADD_STA_LENGTH +1919		   params->link_sta_params.supported_rates_len;1920	wid.val = kmalloc(wid.size, GFP_KERNEL);1921	if (!wid.val)1922		return -ENOMEM;1923 1924	cur_byte = wid.val;1925	wilc_hif_pack_sta_param(cur_byte, mac, params);1926 1927	result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1928	if (result)1929		netdev_err(vif->ndev, "Failed to send edit station\n");1930 1931	kfree(wid.val);1932	return result;1933}1934 1935int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout)1936{1937	struct wilc *wilc = vif->wilc;1938	struct wid wid;1939	int result;1940	s8 power_mode;1941 1942	if (enabled)1943		power_mode = WILC_FW_MIN_FAST_PS;1944	else1945		power_mode = WILC_FW_NO_POWERSAVE;1946 1947	wid.id = WID_POWER_MANAGEMENT;1948	wid.val = &power_mode;1949	wid.size = sizeof(char);1950	result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1951	if (result)1952		netdev_err(vif->ndev, "Failed to send power management\n");1953	else1954		wilc->power_save_mode = enabled;1955 1956	return result;1957}1958 1959int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,1960				u8 *mc_list)1961{1962	int result;1963	struct host_if_msg *msg;1964 1965	msg = wilc_alloc_work(vif, handle_set_mcast_filter, false);1966	if (IS_ERR(msg))1967		return PTR_ERR(msg);1968 1969	msg->body.mc_info.enabled = enabled;1970	msg->body.mc_info.cnt = count;1971	msg->body.mc_info.mc_list = mc_list;1972 1973	result = wilc_enqueue_work(msg);1974	if (result) {1975		netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__);1976		kfree(msg);1977	}1978	return result;1979}1980 1981int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power)1982{1983	struct wid wid;1984 1985	wid.id = WID_TX_POWER;1986	wid.type = WID_CHAR;1987	wid.val = &tx_power;1988	wid.size = sizeof(char);1989 1990	return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);1991}1992 1993int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)1994{1995	struct wid wid;1996 1997	wid.id = WID_TX_POWER;1998	wid.type = WID_CHAR;1999	wid.val = tx_power;2000	wid.size = sizeof(char);2001 2002	return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);2003}2004 2005int wilc_set_default_mgmt_key_index(struct wilc_vif *vif, u8 index)2006{2007        struct wid wid;2008        int result;2009 2010        wid.id = WID_DEFAULT_MGMT_KEY_ID;2011        wid.type = WID_CHAR;2012        wid.size = sizeof(char);2013        wid.val = &index;2014        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);2015        if (result)2016                netdev_err(vif->ndev,2017                           "Failed to send default mgmt key index\n");2018 2019        return result;2020}2021