brintos

brintos / linux-shallow public Read only

0
0
Text · 108.0 KiB · 3787b9f Raw
4161 lines · c
1/*2 * Copyright (c) 2004-2011 Atheros Communications Inc.3 * Copyright (c) 2011-2012 Qualcomm Atheros, Inc.4 *5 * Permission to use, copy, modify, and/or distribute this software for any6 * purpose with or without fee is hereby granted, provided that the above7 * copyright notice and this permission notice appear in all copies.8 *9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.16 */17 18#include <linux/ip.h>19#include <linux/in.h>20#include "core.h"21#include "debug.h"22#include "testmode.h"23#include "trace.h"24#include "../regd.h"25#include "../regd_common.h"26 27static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx);28 29static const s32 wmi_rate_tbl[][2] = {30	/* {W/O SGI, with SGI} */31	{1000, 1000},32	{2000, 2000},33	{5500, 5500},34	{11000, 11000},35	{6000, 6000},36	{9000, 9000},37	{12000, 12000},38	{18000, 18000},39	{24000, 24000},40	{36000, 36000},41	{48000, 48000},42	{54000, 54000},43	{6500, 7200},44	{13000, 14400},45	{19500, 21700},46	{26000, 28900},47	{39000, 43300},48	{52000, 57800},49	{58500, 65000},50	{65000, 72200},51	{13500, 15000},52	{27000, 30000},53	{40500, 45000},54	{54000, 60000},55	{81000, 90000},56	{108000, 120000},57	{121500, 135000},58	{135000, 150000},59	{0, 0}60};61 62static const s32 wmi_rate_tbl_mcs15[][2] = {63	/* {W/O SGI, with SGI} */64	{1000, 1000},65	{2000, 2000},66	{5500, 5500},67	{11000, 11000},68	{6000, 6000},69	{9000, 9000},70	{12000, 12000},71	{18000, 18000},72	{24000, 24000},73	{36000, 36000},74	{48000, 48000},75	{54000, 54000},76	{6500, 7200},     /* HT 20, MCS 0 */77	{13000, 14400},78	{19500, 21700},79	{26000, 28900},80	{39000, 43300},81	{52000, 57800},82	{58500, 65000},83	{65000, 72200},84	{13000, 14400},   /* HT 20, MCS 8 */85	{26000, 28900},86	{39000, 43300},87	{52000, 57800},88	{78000, 86700},89	{104000, 115600},90	{117000, 130000},91	{130000, 144400}, /* HT 20, MCS 15 */92	{13500, 15000},   /*HT 40, MCS 0 */93	{27000, 30000},94	{40500, 45000},95	{54000, 60000},96	{81000, 90000},97	{108000, 120000},98	{121500, 135000},99	{135000, 150000},100	{27000, 30000},   /*HT 40, MCS 8 */101	{54000, 60000},102	{81000, 90000},103	{108000, 120000},104	{162000, 180000},105	{216000, 240000},106	{243000, 270000},107	{270000, 300000}, /*HT 40, MCS 15 */108	{0, 0}109};110 111/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */112static const u8 up_to_ac[] = {113	WMM_AC_BE,114	WMM_AC_BK,115	WMM_AC_BK,116	WMM_AC_BE,117	WMM_AC_VI,118	WMM_AC_VI,119	WMM_AC_VO,120	WMM_AC_VO,121};122 123void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id)124{125	if (WARN_ON(ep_id == ENDPOINT_UNUSED || ep_id >= ENDPOINT_MAX))126		return;127 128	wmi->ep_id = ep_id;129}130 131enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi)132{133	return wmi->ep_id;134}135 136struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)137{138	struct ath6kl_vif *vif, *found = NULL;139 140	if (WARN_ON(if_idx > (ar->vif_max - 1)))141		return NULL;142 143	/* FIXME: Locking */144	spin_lock_bh(&ar->list_lock);145	list_for_each_entry(vif, &ar->vif_list, list) {146		if (vif->fw_vif_idx == if_idx) {147			found = vif;148			break;149		}150	}151	spin_unlock_bh(&ar->list_lock);152 153	return found;154}155 156/*  Performs DIX to 802.3 encapsulation for transmit packets.157 *  Assumes the entire DIX header is contiguous and that there is158 *  enough room in the buffer for a 802.3 mac header and LLC+SNAP headers.159 */160int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb)161{162	struct ath6kl_llc_snap_hdr *llc_hdr;163	struct ethhdr *eth_hdr;164	size_t new_len;165	__be16 type;166	u8 *datap;167	u16 size;168 169	if (WARN_ON(skb == NULL))170		return -EINVAL;171 172	size = sizeof(struct ath6kl_llc_snap_hdr) + sizeof(struct wmi_data_hdr);173	if (skb_headroom(skb) < size)174		return -ENOMEM;175 176	eth_hdr = (struct ethhdr *) skb->data;177	type = eth_hdr->h_proto;178 179	if (!is_ethertype(be16_to_cpu(type))) {180		ath6kl_dbg(ATH6KL_DBG_WMI,181			   "%s: pkt is already in 802.3 format\n", __func__);182		return 0;183	}184 185	new_len = skb->len - sizeof(*eth_hdr) + sizeof(*llc_hdr);186 187	skb_push(skb, sizeof(struct ath6kl_llc_snap_hdr));188	datap = skb->data;189 190	eth_hdr->h_proto = cpu_to_be16(new_len);191 192	memcpy(datap, eth_hdr, sizeof(*eth_hdr));193 194	llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + sizeof(*eth_hdr));195	llc_hdr->dsap = 0xAA;196	llc_hdr->ssap = 0xAA;197	llc_hdr->cntl = 0x03;198	llc_hdr->org_code[0] = 0x0;199	llc_hdr->org_code[1] = 0x0;200	llc_hdr->org_code[2] = 0x0;201	llc_hdr->eth_type = type;202 203	return 0;204}205 206static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb,207			       u8 *version, void *tx_meta_info)208{209	struct wmi_tx_meta_v1 *v1;210	struct wmi_tx_meta_v2 *v2;211 212	if (WARN_ON(skb == NULL || version == NULL))213		return -EINVAL;214 215	switch (*version) {216	case WMI_META_VERSION_1:217		skb_push(skb, WMI_MAX_TX_META_SZ);218		v1 = (struct wmi_tx_meta_v1 *) skb->data;219		v1->pkt_id = 0;220		v1->rate_plcy_id = 0;221		*version = WMI_META_VERSION_1;222		break;223	case WMI_META_VERSION_2:224		skb_push(skb, WMI_MAX_TX_META_SZ);225		v2 = (struct wmi_tx_meta_v2 *) skb->data;226		memcpy(v2, (struct wmi_tx_meta_v2 *) tx_meta_info,227		       sizeof(struct wmi_tx_meta_v2));228		break;229	}230 231	return 0;232}233 234int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,235			    u8 msg_type, u32 flags,236			    enum wmi_data_hdr_data_type data_type,237			    u8 meta_ver, void *tx_meta_info, u8 if_idx)238{239	struct wmi_data_hdr *data_hdr;240	int ret;241 242	if (WARN_ON(skb == NULL || (if_idx > wmi->parent_dev->vif_max - 1)))243		return -EINVAL;244 245	if (tx_meta_info) {246		ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info);247		if (ret)248			return ret;249	}250 251	skb_push(skb, sizeof(struct wmi_data_hdr));252 253	data_hdr = (struct wmi_data_hdr *)skb->data;254	memset(data_hdr, 0, sizeof(struct wmi_data_hdr));255 256	data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT;257	data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT;258 259	if (flags & WMI_DATA_HDR_FLAGS_MORE)260		data_hdr->info |= WMI_DATA_HDR_MORE;261 262	if (flags & WMI_DATA_HDR_FLAGS_EOSP)263		data_hdr->info3 |= cpu_to_le16(WMI_DATA_HDR_EOSP);264 265	data_hdr->info2 |= cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT);266	data_hdr->info3 |= cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);267 268	return 0;269}270 271u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri)272{273	struct iphdr *ip_hdr = (struct iphdr *) pkt;274	u8 ip_pri;275 276	/*277	 * Determine IPTOS priority278	 *279	 * IP-TOS - 8bits280	 *          : DSCP(6-bits) ECN(2-bits)281	 *          : DSCP - P2 P1 P0 X X X282	 * where (P2 P1 P0) form 802.1D283	 */284	ip_pri = ip_hdr->tos >> 5;285	ip_pri &= 0x7;286 287	if ((layer2_pri & 0x7) > ip_pri)288		return (u8) layer2_pri & 0x7;289	else290		return ip_pri;291}292 293u8 ath6kl_wmi_get_traffic_class(u8 user_priority)294{295	return  up_to_ac[user_priority & 0x7];296}297 298int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,299				       struct sk_buff *skb,300				       u32 layer2_priority, bool wmm_enabled,301				       u8 *ac)302{303	struct wmi_data_hdr *data_hdr;304	struct ath6kl_llc_snap_hdr *llc_hdr;305	struct wmi_create_pstream_cmd cmd;306	u32 meta_size, hdr_size;307	u16 ip_type = IP_ETHERTYPE;308	u8 stream_exist, usr_pri;309	u8 traffic_class = WMM_AC_BE;310	u8 *datap;311 312	if (WARN_ON(skb == NULL))313		return -EINVAL;314 315	datap = skb->data;316	data_hdr = (struct wmi_data_hdr *) datap;317 318	meta_size = ((le16_to_cpu(data_hdr->info2) >> WMI_DATA_HDR_META_SHIFT) &319		     WMI_DATA_HDR_META_MASK) ? WMI_MAX_TX_META_SZ : 0;320 321	if (!wmm_enabled) {322		/* If WMM is disabled all traffic goes as BE traffic */323		usr_pri = 0;324	} else {325		hdr_size = sizeof(struct ethhdr);326 327		llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap +328							 sizeof(struct329								wmi_data_hdr) +330							 meta_size + hdr_size);331 332		if (llc_hdr->eth_type == htons(ip_type)) {333			/*334			 * Extract the endpoint info from the TOS field335			 * in the IP header.336			 */337			usr_pri =338			   ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) +339					sizeof(struct ath6kl_llc_snap_hdr),340					layer2_priority);341		} else {342			usr_pri = layer2_priority & 0x7;343		}344 345		/*346		 * Queue the EAPOL frames in the same WMM_AC_VO queue347		 * as that of management frames.348		 */349		if (skb->protocol == cpu_to_be16(ETH_P_PAE))350			usr_pri = WMI_VOICE_USER_PRIORITY;351	}352 353	/*354	 * workaround for WMM S5355	 *356	 * FIXME: wmi->traffic_class is always 100 so this test doesn't357	 * make sense358	 */359	if ((wmi->traffic_class == WMM_AC_VI) &&360	    ((usr_pri == 5) || (usr_pri == 4)))361		usr_pri = 1;362 363	/* Convert user priority to traffic class */364	traffic_class = up_to_ac[usr_pri & 0x7];365 366	wmi_data_hdr_set_up(data_hdr, usr_pri);367 368	spin_lock_bh(&wmi->lock);369	stream_exist = wmi->fat_pipe_exist;370	spin_unlock_bh(&wmi->lock);371 372	if (!(stream_exist & (1 << traffic_class))) {373		memset(&cmd, 0, sizeof(cmd));374		cmd.traffic_class = traffic_class;375		cmd.user_pri = usr_pri;376		cmd.inactivity_int =377			cpu_to_le32(WMI_IMPLICIT_PSTREAM_INACTIVITY_INT);378		/* Implicit streams are created with TSID 0xFF */379		cmd.tsid = WMI_IMPLICIT_PSTREAM;380		ath6kl_wmi_create_pstream_cmd(wmi, if_idx, &cmd);381	}382 383	*ac = traffic_class;384 385	return 0;386}387 388int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb)389{390	struct ieee80211_hdr_3addr *pwh, wh;391	struct ath6kl_llc_snap_hdr *llc_hdr;392	struct ethhdr eth_hdr;393	u32 hdr_size;394	u8 *datap;395	__le16 sub_type;396 397	if (WARN_ON(skb == NULL))398		return -EINVAL;399 400	datap = skb->data;401	pwh = (struct ieee80211_hdr_3addr *) datap;402 403	sub_type = pwh->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);404 405	memcpy((u8 *) &wh, datap, sizeof(struct ieee80211_hdr_3addr));406 407	/* Strip off the 802.11 header */408	if (sub_type == cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {409		hdr_size = roundup(sizeof(struct ieee80211_qos_hdr),410				   sizeof(u32));411		skb_pull(skb, hdr_size);412	} else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) {413		skb_pull(skb, sizeof(struct ieee80211_hdr_3addr));414	}415 416	datap = skb->data;417	llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap);418 419	memset(&eth_hdr, 0, sizeof(eth_hdr));420	eth_hdr.h_proto = llc_hdr->eth_type;421 422	switch ((le16_to_cpu(wh.frame_control)) &423		(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {424	case IEEE80211_FCTL_TODS:425		memcpy(eth_hdr.h_dest, wh.addr3, ETH_ALEN);426		memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);427		break;428	case IEEE80211_FCTL_FROMDS:429		memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);430		memcpy(eth_hdr.h_source, wh.addr3, ETH_ALEN);431		break;432	case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:433		break;434	default:435		memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN);436		memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN);437		break;438	}439 440	skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));441	skb_push(skb, sizeof(eth_hdr));442 443	datap = skb->data;444 445	memcpy(datap, &eth_hdr, sizeof(eth_hdr));446 447	return 0;448}449 450/*451 * Performs 802.3 to DIX encapsulation for received packets.452 * Assumes the entire 802.3 header is contiguous.453 */454int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb)455{456	struct ath6kl_llc_snap_hdr *llc_hdr;457	struct ethhdr eth_hdr;458	u8 *datap;459 460	if (WARN_ON(skb == NULL))461		return -EINVAL;462 463	datap = skb->data;464 465	memcpy(&eth_hdr, datap, sizeof(eth_hdr));466 467	llc_hdr = (struct ath6kl_llc_snap_hdr *) (datap + sizeof(eth_hdr));468	eth_hdr.h_proto = llc_hdr->eth_type;469 470	skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr));471	datap = skb->data;472 473	memcpy(datap, &eth_hdr, sizeof(eth_hdr));474 475	return 0;476}477 478static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)479{480	struct tx_complete_msg_v1 *msg_v1;481	struct wmi_tx_complete_event *evt;482	int index;483	u16 size;484 485	evt = (struct wmi_tx_complete_event *) datap;486 487	ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",488		   evt->num_msg, evt->msg_len, evt->msg_type);489 490	for (index = 0; index < evt->num_msg; index++) {491		size = sizeof(struct wmi_tx_complete_event) +492		    (index * sizeof(struct tx_complete_msg_v1));493		msg_v1 = (struct tx_complete_msg_v1 *)(datap + size);494 495		ath6kl_dbg(ATH6KL_DBG_WMI, "msg: %d %d %d %d\n",496			   msg_v1->status, msg_v1->pkt_id,497			   msg_v1->rate_idx, msg_v1->ack_failures);498	}499 500	return 0;501}502 503static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,504					      int len, struct ath6kl_vif *vif)505{506	struct wmi_remain_on_chnl_event *ev;507	u32 freq;508	u32 dur;509	struct ieee80211_channel *chan;510	struct ath6kl *ar = wmi->parent_dev;511	u32 id;512 513	if (len < sizeof(*ev))514		return -EINVAL;515 516	ev = (struct wmi_remain_on_chnl_event *) datap;517	freq = le32_to_cpu(ev->freq);518	dur = le32_to_cpu(ev->duration);519	ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n",520		   freq, dur);521	chan = ieee80211_get_channel(ar->wiphy, freq);522	if (!chan) {523		ath6kl_dbg(ATH6KL_DBG_WMI,524			   "remain_on_chnl: Unknown channel (freq=%u)\n",525			   freq);526		return -EINVAL;527	}528	id = vif->last_roc_id;529	cfg80211_ready_on_channel(&vif->wdev, id, chan,530				  dur, GFP_ATOMIC);531 532	return 0;533}534 535static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,536						     u8 *datap, int len,537						     struct ath6kl_vif *vif)538{539	struct wmi_cancel_remain_on_chnl_event *ev;540	u32 freq;541	u32 dur;542	struct ieee80211_channel *chan;543	struct ath6kl *ar = wmi->parent_dev;544	u32 id;545 546	if (len < sizeof(*ev))547		return -EINVAL;548 549	ev = (struct wmi_cancel_remain_on_chnl_event *) datap;550	freq = le32_to_cpu(ev->freq);551	dur = le32_to_cpu(ev->duration);552	ath6kl_dbg(ATH6KL_DBG_WMI,553		   "cancel_remain_on_chnl: freq=%u dur=%u status=%u\n",554		   freq, dur, ev->status);555	chan = ieee80211_get_channel(ar->wiphy, freq);556	if (!chan) {557		ath6kl_dbg(ATH6KL_DBG_WMI,558			   "cancel_remain_on_chnl: Unknown channel (freq=%u)\n",559			   freq);560		return -EINVAL;561	}562	if (vif->last_cancel_roc_id &&563	    vif->last_cancel_roc_id + 1 == vif->last_roc_id)564		id = vif->last_cancel_roc_id; /* event for cancel command */565	else566		id = vif->last_roc_id; /* timeout on uncanceled r-o-c */567	vif->last_cancel_roc_id = 0;568	cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, GFP_ATOMIC);569 570	return 0;571}572 573static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len,574					 struct ath6kl_vif *vif)575{576	struct wmi_tx_status_event *ev;577	u32 id;578 579	if (len < sizeof(*ev))580		return -EINVAL;581 582	ev = (struct wmi_tx_status_event *) datap;583	id = le32_to_cpu(ev->id);584	ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n",585		   id, ev->ack_status);586	if (wmi->last_mgmt_tx_frame) {587		cfg80211_mgmt_tx_status(&vif->wdev, id,588					wmi->last_mgmt_tx_frame,589					wmi->last_mgmt_tx_frame_len,590					!!ev->ack_status, GFP_ATOMIC);591		kfree(wmi->last_mgmt_tx_frame);592		wmi->last_mgmt_tx_frame = NULL;593		wmi->last_mgmt_tx_frame_len = 0;594	}595 596	return 0;597}598 599static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,600					    struct ath6kl_vif *vif)601{602	struct wmi_p2p_rx_probe_req_event *ev;603	u32 freq;604	u16 dlen;605 606	if (len < sizeof(*ev))607		return -EINVAL;608 609	ev = (struct wmi_p2p_rx_probe_req_event *) datap;610	freq = le32_to_cpu(ev->freq);611	dlen = le16_to_cpu(ev->len);612	if (datap + len < ev->data + dlen) {613		ath6kl_err("invalid wmi_p2p_rx_probe_req_event: len=%d dlen=%u\n",614			   len, dlen);615		return -EINVAL;616	}617	ath6kl_dbg(ATH6KL_DBG_WMI,618		   "rx_probe_req: len=%u freq=%u probe_req_report=%d\n",619		   dlen, freq, vif->probe_req_report);620 621	if (vif->probe_req_report || vif->nw_type == AP_NETWORK)622		cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);623 624	return 0;625}626 627static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len)628{629	struct wmi_p2p_capabilities_event *ev;630	u16 dlen;631 632	if (len < sizeof(*ev))633		return -EINVAL;634 635	ev = (struct wmi_p2p_capabilities_event *) datap;636	dlen = le16_to_cpu(ev->len);637	ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_capab: len=%u\n", dlen);638 639	return 0;640}641 642static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,643					 struct ath6kl_vif *vif)644{645	struct wmi_rx_action_event *ev;646	u32 freq;647	u16 dlen;648 649	if (len < sizeof(*ev))650		return -EINVAL;651 652	ev = (struct wmi_rx_action_event *) datap;653	freq = le32_to_cpu(ev->freq);654	dlen = le16_to_cpu(ev->len);655	if (datap + len < ev->data + dlen) {656		ath6kl_err("invalid wmi_rx_action_event: len=%d dlen=%u\n",657			   len, dlen);658		return -EINVAL;659	}660	ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);661	cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);662 663	return 0;664}665 666static int ath6kl_wmi_p2p_info_event_rx(u8 *datap, int len)667{668	struct wmi_p2p_info_event *ev;669	u32 flags;670	u16 dlen;671 672	if (len < sizeof(*ev))673		return -EINVAL;674 675	ev = (struct wmi_p2p_info_event *) datap;676	flags = le32_to_cpu(ev->info_req_flags);677	dlen = le16_to_cpu(ev->len);678	ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: flags=%x len=%d\n", flags, dlen);679 680	if (flags & P2P_FLAG_CAPABILITIES_REQ) {681		struct wmi_p2p_capabilities *cap;682		if (dlen < sizeof(*cap))683			return -EINVAL;684		cap = (struct wmi_p2p_capabilities *) ev->data;685		ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: GO Power Save = %d\n",686			   cap->go_power_save);687	}688 689	if (flags & P2P_FLAG_MACADDR_REQ) {690		struct wmi_p2p_macaddr *mac;691		if (dlen < sizeof(*mac))692			return -EINVAL;693		mac = (struct wmi_p2p_macaddr *) ev->data;694		ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: MAC Address = %pM\n",695			   mac->mac_addr);696	}697 698	if (flags & P2P_FLAG_HMODEL_REQ) {699		struct wmi_p2p_hmodel *mod;700		if (dlen < sizeof(*mod))701			return -EINVAL;702		mod = (struct wmi_p2p_hmodel *) ev->data;703		ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: P2P Model = %d (%s)\n",704			   mod->p2p_model,705			   mod->p2p_model ? "host" : "firmware");706	}707	return 0;708}709 710static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size)711{712	struct sk_buff *skb;713 714	skb = ath6kl_buf_alloc(size);715	if (!skb)716		return NULL;717 718	skb_put(skb, size);719	if (size)720		memset(skb->data, 0, size);721 722	return skb;723}724 725/* Send a "simple" wmi command -- one with no arguments */726static int ath6kl_wmi_simple_cmd(struct wmi *wmi, u8 if_idx,727				 enum wmi_cmd_id cmd_id)728{729	struct sk_buff *skb;730	int ret;731 732	skb = ath6kl_wmi_get_new_buf(0);733	if (!skb)734		return -ENOMEM;735 736	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, cmd_id, NO_SYNC_WMIFLAG);737 738	return ret;739}740 741static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)742{743	struct wmi_ready_event_2 *ev = (struct wmi_ready_event_2 *) datap;744 745	if (len < sizeof(struct wmi_ready_event_2))746		return -EINVAL;747 748	ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,749			   le32_to_cpu(ev->sw_version),750			   le32_to_cpu(ev->abi_version), ev->phy_cap);751 752	return 0;753}754 755/*756 * Mechanism to modify the roaming behavior in the firmware. The lower rssi757 * at which the station has to roam can be passed with758 * WMI_SET_LRSSI_SCAN_PARAMS. Subtract 96 from RSSI to get the signal level759 * in dBm.760 */761int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi)762{763	struct sk_buff *skb;764	struct roam_ctrl_cmd *cmd;765 766	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));767	if (!skb)768		return -ENOMEM;769 770	cmd = (struct roam_ctrl_cmd *) skb->data;771 772	cmd->info.params.lrssi_scan_period = cpu_to_le16(DEF_LRSSI_SCAN_PERIOD);773	cmd->info.params.lrssi_scan_threshold = a_cpu_to_sle16(lrssi +774						       DEF_SCAN_FOR_ROAM_INTVL);775	cmd->info.params.lrssi_roam_threshold = a_cpu_to_sle16(lrssi);776	cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR;777	cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS;778 779	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,780			    NO_SYNC_WMIFLAG);781}782 783int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid)784{785	struct sk_buff *skb;786	struct roam_ctrl_cmd *cmd;787 788	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));789	if (!skb)790		return -ENOMEM;791 792	cmd = (struct roam_ctrl_cmd *) skb->data;793 794	memcpy(cmd->info.bssid, bssid, ETH_ALEN);795	cmd->roam_ctrl = WMI_FORCE_ROAM;796 797	ath6kl_dbg(ATH6KL_DBG_WMI, "force roam to %pM\n", bssid);798	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,799				   NO_SYNC_WMIFLAG);800}801 802int ath6kl_wmi_ap_set_beacon_intvl_cmd(struct wmi *wmi, u8 if_idx,803				       u32 beacon_intvl)804{805	struct sk_buff *skb;806	struct set_beacon_int_cmd *cmd;807 808	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));809	if (!skb)810		return -ENOMEM;811 812	cmd = (struct set_beacon_int_cmd *) skb->data;813 814	cmd->beacon_intvl = cpu_to_le32(beacon_intvl);815	return ath6kl_wmi_cmd_send(wmi, if_idx, skb,816				   WMI_SET_BEACON_INT_CMDID, NO_SYNC_WMIFLAG);817}818 819int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period)820{821	struct sk_buff *skb;822	struct set_dtim_cmd *cmd;823 824	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));825	if (!skb)826		return -ENOMEM;827 828	cmd = (struct set_dtim_cmd *) skb->data;829 830	cmd->dtim_period = cpu_to_le32(dtim_period);831	return ath6kl_wmi_cmd_send(wmi, if_idx, skb,832				   WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG);833}834 835int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode)836{837	struct sk_buff *skb;838	struct roam_ctrl_cmd *cmd;839 840	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));841	if (!skb)842		return -ENOMEM;843 844	cmd = (struct roam_ctrl_cmd *) skb->data;845 846	cmd->info.roam_mode = mode;847	cmd->roam_ctrl = WMI_SET_ROAM_MODE;848 849	ath6kl_dbg(ATH6KL_DBG_WMI, "set roam mode %d\n", mode);850	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_ROAM_CTRL_CMDID,851				   NO_SYNC_WMIFLAG);852}853 854static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,855				       struct ath6kl_vif *vif)856{857	struct wmi_connect_event *ev;858	u8 *pie, *peie;859 860	if (len < sizeof(struct wmi_connect_event))861		return -EINVAL;862 863	ev = (struct wmi_connect_event *) datap;864 865	if (vif->nw_type == AP_NETWORK) {866		/* AP mode start/STA connected event */867		struct net_device *dev = vif->ndev;868		if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) {869			ath6kl_dbg(ATH6KL_DBG_WMI,870				   "%s: freq %d bssid %pM (AP started)\n",871				   __func__, le16_to_cpu(ev->u.ap_bss.ch),872				   ev->u.ap_bss.bssid);873			ath6kl_connect_ap_mode_bss(874				vif, le16_to_cpu(ev->u.ap_bss.ch));875		} else {876			ath6kl_dbg(ATH6KL_DBG_WMI,877				   "%s: aid %u mac_addr %pM auth=%u keymgmt=%u cipher=%u apsd_info=%u (STA connected)\n",878				   __func__, ev->u.ap_sta.aid,879				   ev->u.ap_sta.mac_addr,880				   ev->u.ap_sta.auth,881				   ev->u.ap_sta.keymgmt,882				   le16_to_cpu(ev->u.ap_sta.cipher),883				   ev->u.ap_sta.apsd_info);884 885			ath6kl_connect_ap_mode_sta(886				vif, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr,887				ev->u.ap_sta.keymgmt,888				le16_to_cpu(ev->u.ap_sta.cipher),889				ev->u.ap_sta.auth, ev->assoc_req_len,890				ev->assoc_info + ev->beacon_ie_len,891				ev->u.ap_sta.apsd_info);892		}893		return 0;894	}895 896	/* STA/IBSS mode connection event */897 898	ath6kl_dbg(ATH6KL_DBG_WMI,899		   "wmi event connect freq %d bssid %pM listen_intvl %d beacon_intvl %d type %d\n",900		   le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid,901		   le16_to_cpu(ev->u.sta.listen_intvl),902		   le16_to_cpu(ev->u.sta.beacon_intvl),903		   le32_to_cpu(ev->u.sta.nw_type));904 905	/* Start of assoc rsp IEs */906	pie = ev->assoc_info + ev->beacon_ie_len +907	      ev->assoc_req_len + (sizeof(u16) * 3); /* capinfo, status, aid */908 909	/* End of assoc rsp IEs */910	peie = ev->assoc_info + ev->beacon_ie_len + ev->assoc_req_len +911	    ev->assoc_resp_len;912 913	while (pie < peie) {914		switch (*pie) {915		case WLAN_EID_VENDOR_SPECIFIC:916			if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 &&917			    pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) {918				/* WMM OUT (00:50:F2) */919				if (pie[1] > 5 &&920				    pie[6] == WMM_PARAM_OUI_SUBTYPE)921					wmi->is_wmm_enabled = true;922			}923			break;924		}925 926		if (wmi->is_wmm_enabled)927			break;928 929		pie += pie[1] + 2;930	}931 932	ath6kl_connect_event(vif, le16_to_cpu(ev->u.sta.ch),933			     ev->u.sta.bssid,934			     le16_to_cpu(ev->u.sta.listen_intvl),935			     le16_to_cpu(ev->u.sta.beacon_intvl),936			     le32_to_cpu(ev->u.sta.nw_type),937			     ev->beacon_ie_len, ev->assoc_req_len,938			     ev->assoc_resp_len, ev->assoc_info);939 940	return 0;941}942 943static struct country_code_to_enum_rd *944ath6kl_regd_find_country(u16 countryCode)945{946	int i;947 948	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {949		if (allCountries[i].countryCode == countryCode)950			return &allCountries[i];951	}952 953	return NULL;954}955 956static struct reg_dmn_pair_mapping *957ath6kl_get_regpair(u16 regdmn)958{959	int i;960 961	if (regdmn == NO_ENUMRD)962		return NULL;963 964	for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {965		if (regDomainPairs[i].reg_domain == regdmn)966			return &regDomainPairs[i];967	}968 969	return NULL;970}971 972static struct country_code_to_enum_rd *973ath6kl_regd_find_country_by_rd(u16 regdmn)974{975	int i;976 977	for (i = 0; i < ARRAY_SIZE(allCountries); i++) {978		if (allCountries[i].regDmnEnum == regdmn)979			return &allCountries[i];980	}981 982	return NULL;983}984 985static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)986{987	struct ath6kl_wmi_regdomain *ev;988	struct country_code_to_enum_rd *country = NULL;989	struct reg_dmn_pair_mapping *regpair = NULL;990	char alpha2[2];991	u32 reg_code;992 993	ev = (struct ath6kl_wmi_regdomain *) datap;994	reg_code = le32_to_cpu(ev->reg_code);995 996	if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) {997		country = ath6kl_regd_find_country((u16) reg_code);998	} else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) {999		regpair = ath6kl_get_regpair((u16) reg_code);1000		country = ath6kl_regd_find_country_by_rd((u16) reg_code);1001		if (regpair)1002			ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",1003				   regpair->reg_domain);1004		else1005			ath6kl_warn("Regpair not found reg_code 0x%0x\n",1006				    reg_code);1007	}1008 1009	if (country && wmi->parent_dev->wiphy_registered) {1010		alpha2[0] = country->isoName[0];1011		alpha2[1] = country->isoName[1];1012 1013		regulatory_hint(wmi->parent_dev->wiphy, alpha2);1014 1015		ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n",1016			   alpha2[0], alpha2[1]);1017	}1018}1019 1020static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len,1021					  struct ath6kl_vif *vif)1022{1023	struct wmi_disconnect_event *ev;1024	wmi->traffic_class = 100;1025 1026	if (len < sizeof(struct wmi_disconnect_event))1027		return -EINVAL;1028 1029	ev = (struct wmi_disconnect_event *) datap;1030 1031	ath6kl_dbg(ATH6KL_DBG_WMI,1032		   "wmi event disconnect proto_reason %d bssid %pM wmi_reason %d assoc_resp_len %d\n",1033		   le16_to_cpu(ev->proto_reason_status), ev->bssid,1034		   ev->disconn_reason, ev->assoc_resp_len);1035 1036	wmi->is_wmm_enabled = false;1037 1038	ath6kl_disconnect_event(vif, ev->disconn_reason,1039				ev->bssid, ev->assoc_resp_len, ev->assoc_info,1040				le16_to_cpu(ev->proto_reason_status));1041 1042	return 0;1043}1044 1045static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len)1046{1047	struct wmi_peer_node_event *ev;1048 1049	if (len < sizeof(struct wmi_peer_node_event))1050		return -EINVAL;1051 1052	ev = (struct wmi_peer_node_event *) datap;1053 1054	if (ev->event_code == PEER_NODE_JOIN_EVENT)1055		ath6kl_dbg(ATH6KL_DBG_WMI, "joined node with mac addr: %pM\n",1056			   ev->peer_mac_addr);1057	else if (ev->event_code == PEER_NODE_LEAVE_EVENT)1058		ath6kl_dbg(ATH6KL_DBG_WMI, "left node with mac addr: %pM\n",1059			   ev->peer_mac_addr);1060 1061	return 0;1062}1063 1064static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len,1065					   struct ath6kl_vif *vif)1066{1067	struct wmi_tkip_micerr_event *ev;1068 1069	if (len < sizeof(struct wmi_tkip_micerr_event))1070		return -EINVAL;1071 1072	ev = (struct wmi_tkip_micerr_event *) datap;1073 1074	ath6kl_tkip_micerr_event(vif, ev->key_id, ev->is_mcast);1075 1076	return 0;1077}1078 1079void ath6kl_wmi_sscan_timer(struct timer_list *t)1080{1081	struct ath6kl_vif *vif = from_timer(vif, t, sched_scan_timer);1082 1083	cfg80211_sched_scan_results(vif->ar->wiphy, 0);1084}1085 1086static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,1087				       struct ath6kl_vif *vif)1088{1089	struct wmi_bss_info_hdr2 *bih;1090	u8 *buf;1091	struct ieee80211_channel *channel;1092	struct ath6kl *ar = wmi->parent_dev;1093	struct cfg80211_bss *bss;1094 1095	if (len <= sizeof(struct wmi_bss_info_hdr2))1096		return -EINVAL;1097 1098	bih = (struct wmi_bss_info_hdr2 *) datap;1099	buf = datap + sizeof(struct wmi_bss_info_hdr2);1100	len -= sizeof(struct wmi_bss_info_hdr2);1101 1102	ath6kl_dbg(ATH6KL_DBG_WMI,1103		   "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" "1104		   "frame_type=%d\n",1105		   bih->ch, bih->snr, bih->snr - 95, bih->bssid,1106		   bih->frame_type);1107 1108	if (bih->frame_type != BEACON_FTYPE &&1109	    bih->frame_type != PROBERESP_FTYPE)1110		return 0; /* Only update BSS table for now */1111 1112	if (bih->frame_type == BEACON_FTYPE &&1113	    test_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags)) {1114		clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);1115		ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,1116					 NONE_BSS_FILTER, 0);1117	}1118 1119	channel = ieee80211_get_channel(ar->wiphy, le16_to_cpu(bih->ch));1120	if (channel == NULL)1121		return -EINVAL;1122 1123	if (len < 8 + 2 + 2)1124		return -EINVAL;1125 1126	if (bih->frame_type == BEACON_FTYPE &&1127	    test_bit(CONNECTED, &vif->flags) &&1128	    memcmp(bih->bssid, vif->bssid, ETH_ALEN) == 0) {1129		const u8 *tim;1130		tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2,1131				       len - 8 - 2 - 2);1132		if (tim && tim[1] >= 2) {1133			vif->assoc_bss_dtim_period = tim[3];1134			set_bit(DTIM_PERIOD_AVAIL, &vif->flags);1135		}1136	}1137 1138	bss = cfg80211_inform_bss(ar->wiphy, channel,1139				  bih->frame_type == BEACON_FTYPE ?1140					CFG80211_BSS_FTYPE_BEACON :1141					CFG80211_BSS_FTYPE_PRESP,1142				  bih->bssid, get_unaligned_le64((__le64 *)buf),1143				  get_unaligned_le16(((__le16 *)buf) + 5),1144				  get_unaligned_le16(((__le16 *)buf) + 4),1145				  buf + 8 + 2 + 2, len - 8 - 2 - 2,1146				  (bih->snr - 95) * 100, GFP_ATOMIC);1147	if (bss == NULL)1148		return -ENOMEM;1149	cfg80211_put_bss(ar->wiphy, bss);1150 1151	/*1152	 * Firmware doesn't return any event when scheduled scan has1153	 * finished, so we need to use a timer to find out when there are1154	 * no more results.1155	 *1156	 * The timer is started from the first bss info received, otherwise1157	 * the timer would not ever fire if the scan interval is short1158	 * enough.1159	 */1160	if (test_bit(SCHED_SCANNING, &vif->flags) &&1161	    !timer_pending(&vif->sched_scan_timer)) {1162		mod_timer(&vif->sched_scan_timer, jiffies +1163			  msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));1164	}1165 1166	return 0;1167}1168 1169/* Inactivity timeout of a fatpipe(pstream) at the target */1170static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap,1171					       int len)1172{1173	struct wmi_pstream_timeout_event *ev;1174 1175	if (len < sizeof(struct wmi_pstream_timeout_event))1176		return -EINVAL;1177 1178	ev = (struct wmi_pstream_timeout_event *) datap;1179	if (ev->traffic_class >= WMM_NUM_AC) {1180		ath6kl_err("invalid traffic class: %d\n", ev->traffic_class);1181		return -EINVAL;1182	}1183 1184	/*1185	 * When the pstream (fat pipe == AC) timesout, it means there were1186	 * no thinStreams within this pstream & it got implicitly created1187	 * due to data flow on this AC. We start the inactivity timer only1188	 * for implicitly created pstream. Just reset the host state.1189	 */1190	spin_lock_bh(&wmi->lock);1191	wmi->stream_exist_for_ac[ev->traffic_class] = 0;1192	wmi->fat_pipe_exist &= ~(1 << ev->traffic_class);1193	spin_unlock_bh(&wmi->lock);1194 1195	/* Indicate inactivity to driver layer for this fatpipe (pstream) */1196	ath6kl_indicate_tx_activity(wmi->parent_dev, ev->traffic_class, false);1197 1198	return 0;1199}1200 1201static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)1202{1203	struct wmi_bit_rate_reply *reply;1204	u32 index;1205 1206	if (len < sizeof(struct wmi_bit_rate_reply))1207		return -EINVAL;1208 1209	reply = (struct wmi_bit_rate_reply *) datap;1210 1211	ath6kl_dbg(ATH6KL_DBG_WMI, "rateindex %d\n", reply->rate_index);1212 1213	if (reply->rate_index != (s8) RATE_AUTO) {1214		index = reply->rate_index & 0x7f;1215		if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1)))1216			return -EINVAL;1217	}1218 1219	ath6kl_wakeup_event(wmi->parent_dev);1220 1221	return 0;1222}1223 1224static int ath6kl_wmi_test_rx(struct wmi *wmi, u8 *datap, int len)1225{1226	ath6kl_tm_rx_event(wmi->parent_dev, datap, len);1227 1228	return 0;1229}1230 1231static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len)1232{1233	if (len < sizeof(struct wmi_fix_rates_reply))1234		return -EINVAL;1235 1236	ath6kl_wakeup_event(wmi->parent_dev);1237 1238	return 0;1239}1240 1241static int ath6kl_wmi_ch_list_reply_rx(struct wmi *wmi, u8 *datap, int len)1242{1243	if (len < sizeof(struct wmi_channel_list_reply))1244		return -EINVAL;1245 1246	ath6kl_wakeup_event(wmi->parent_dev);1247 1248	return 0;1249}1250 1251static int ath6kl_wmi_tx_pwr_reply_rx(struct wmi *wmi, u8 *datap, int len)1252{1253	struct wmi_tx_pwr_reply *reply;1254 1255	if (len < sizeof(struct wmi_tx_pwr_reply))1256		return -EINVAL;1257 1258	reply = (struct wmi_tx_pwr_reply *) datap;1259	ath6kl_txpwr_rx_evt(wmi->parent_dev, reply->dbM);1260 1261	return 0;1262}1263 1264static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len)1265{1266	if (len < sizeof(struct wmi_get_keepalive_cmd))1267		return -EINVAL;1268 1269	ath6kl_wakeup_event(wmi->parent_dev);1270 1271	return 0;1272}1273 1274static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len,1275				       struct ath6kl_vif *vif)1276{1277	struct wmi_scan_complete_event *ev;1278 1279	ev = (struct wmi_scan_complete_event *) datap;1280 1281	ath6kl_scan_complete_evt(vif, a_sle32_to_cpu(ev->status));1282	wmi->is_probe_ssid = false;1283 1284	return 0;1285}1286 1287static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,1288					       int len, struct ath6kl_vif *vif)1289{1290	struct wmi_neighbor_report_event *ev;1291	u8 i;1292 1293	if (len < sizeof(*ev))1294		return -EINVAL;1295	ev = (struct wmi_neighbor_report_event *) datap;1296	if (struct_size(ev, neighbor, ev->num_neighbors) > len) {1297		ath6kl_dbg(ATH6KL_DBG_WMI,1298			   "truncated neighbor event (num=%d len=%d)\n",1299			   ev->num_neighbors, len);1300		return -EINVAL;1301	}1302	for (i = 0; i < ev->num_neighbors; i++) {1303		ath6kl_dbg(ATH6KL_DBG_WMI, "neighbor %d/%d - %pM 0x%x\n",1304			   i + 1, ev->num_neighbors, ev->neighbor[i].bssid,1305			   ev->neighbor[i].bss_flags);1306		cfg80211_pmksa_candidate_notify(vif->ndev, i,1307						ev->neighbor[i].bssid,1308						!!(ev->neighbor[i].bss_flags &1309						   WMI_PREAUTH_CAPABLE_BSS),1310						GFP_ATOMIC);1311	}1312 1313	return 0;1314}1315 1316/*1317 * Target is reporting a programming error.  This is for1318 * developer aid only.  Target only checks a few common violations1319 * and it is responsibility of host to do all error checking.1320 * Behavior of target after wmi error event is undefined.1321 * A reset is recommended.1322 */1323static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len)1324{1325	const char *type = "unknown error";1326	struct wmi_cmd_error_event *ev;1327	ev = (struct wmi_cmd_error_event *) datap;1328 1329	switch (ev->err_code) {1330	case INVALID_PARAM:1331		type = "invalid parameter";1332		break;1333	case ILLEGAL_STATE:1334		type = "invalid state";1335		break;1336	case INTERNAL_ERROR:1337		type = "internal error";1338		break;1339	}1340 1341	ath6kl_dbg(ATH6KL_DBG_WMI, "programming error, cmd=%d %s\n",1342		   ev->cmd_id, type);1343 1344	return 0;1345}1346 1347static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len,1348				     struct ath6kl_vif *vif)1349{1350	ath6kl_tgt_stats_event(vif, datap, len);1351 1352	return 0;1353}1354 1355static u8 ath6kl_wmi_get_upper_threshold(s16 rssi,1356					 struct sq_threshold_params *sq_thresh,1357					 u32 size)1358{1359	u32 index;1360	u8 threshold = (u8) sq_thresh->upper_threshold[size - 1];1361 1362	/* The list is already in sorted order. Get the next lower value */1363	for (index = 0; index < size; index++) {1364		if (rssi < sq_thresh->upper_threshold[index]) {1365			threshold = (u8) sq_thresh->upper_threshold[index];1366			break;1367		}1368	}1369 1370	return threshold;1371}1372 1373static u8 ath6kl_wmi_get_lower_threshold(s16 rssi,1374					 struct sq_threshold_params *sq_thresh,1375					 u32 size)1376{1377	u32 index;1378	u8 threshold = (u8) sq_thresh->lower_threshold[size - 1];1379 1380	/* The list is already in sorted order. Get the next lower value */1381	for (index = 0; index < size; index++) {1382		if (rssi > sq_thresh->lower_threshold[index]) {1383			threshold = (u8) sq_thresh->lower_threshold[index];1384			break;1385		}1386	}1387 1388	return threshold;1389}1390 1391static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi,1392			struct wmi_rssi_threshold_params_cmd *rssi_cmd)1393{1394	struct sk_buff *skb;1395	struct wmi_rssi_threshold_params_cmd *cmd;1396 1397	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));1398	if (!skb)1399		return -ENOMEM;1400 1401	cmd = (struct wmi_rssi_threshold_params_cmd *) skb->data;1402	memcpy(cmd, rssi_cmd, sizeof(struct wmi_rssi_threshold_params_cmd));1403 1404	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_RSSI_THRESHOLD_PARAMS_CMDID,1405				   NO_SYNC_WMIFLAG);1406}1407 1408static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap,1409					      int len)1410{1411	struct wmi_rssi_threshold_event *reply;1412	struct wmi_rssi_threshold_params_cmd cmd;1413	struct sq_threshold_params *sq_thresh;1414	enum wmi_rssi_threshold_val new_threshold;1415	u8 upper_rssi_threshold, lower_rssi_threshold;1416	s16 rssi;1417	int ret;1418 1419	if (len < sizeof(struct wmi_rssi_threshold_event))1420		return -EINVAL;1421 1422	reply = (struct wmi_rssi_threshold_event *) datap;1423	new_threshold = (enum wmi_rssi_threshold_val) reply->range;1424	rssi = a_sle16_to_cpu(reply->rssi);1425 1426	sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_RSSI];1427 1428	/*1429	 * Identify the threshold breached and communicate that to the app.1430	 * After that install a new set of thresholds based on the signal1431	 * quality reported by the target1432	 */1433	if (new_threshold) {1434		/* Upper threshold breached */1435		if (rssi < sq_thresh->upper_threshold[0]) {1436			ath6kl_dbg(ATH6KL_DBG_WMI,1437				   "spurious upper rssi threshold event: %d\n",1438				   rssi);1439		} else if ((rssi < sq_thresh->upper_threshold[1]) &&1440			   (rssi >= sq_thresh->upper_threshold[0])) {1441			new_threshold = WMI_RSSI_THRESHOLD1_ABOVE;1442		} else if ((rssi < sq_thresh->upper_threshold[2]) &&1443			   (rssi >= sq_thresh->upper_threshold[1])) {1444			new_threshold = WMI_RSSI_THRESHOLD2_ABOVE;1445		} else if ((rssi < sq_thresh->upper_threshold[3]) &&1446			   (rssi >= sq_thresh->upper_threshold[2])) {1447			new_threshold = WMI_RSSI_THRESHOLD3_ABOVE;1448		} else if ((rssi < sq_thresh->upper_threshold[4]) &&1449			   (rssi >= sq_thresh->upper_threshold[3])) {1450			new_threshold = WMI_RSSI_THRESHOLD4_ABOVE;1451		} else if ((rssi < sq_thresh->upper_threshold[5]) &&1452			   (rssi >= sq_thresh->upper_threshold[4])) {1453			new_threshold = WMI_RSSI_THRESHOLD5_ABOVE;1454		} else if (rssi >= sq_thresh->upper_threshold[5]) {1455			new_threshold = WMI_RSSI_THRESHOLD6_ABOVE;1456		}1457	} else {1458		/* Lower threshold breached */1459		if (rssi > sq_thresh->lower_threshold[0]) {1460			ath6kl_dbg(ATH6KL_DBG_WMI,1461				   "spurious lower rssi threshold event: %d %d\n",1462				rssi, sq_thresh->lower_threshold[0]);1463		} else if ((rssi > sq_thresh->lower_threshold[1]) &&1464			   (rssi <= sq_thresh->lower_threshold[0])) {1465			new_threshold = WMI_RSSI_THRESHOLD6_BELOW;1466		} else if ((rssi > sq_thresh->lower_threshold[2]) &&1467			   (rssi <= sq_thresh->lower_threshold[1])) {1468			new_threshold = WMI_RSSI_THRESHOLD5_BELOW;1469		} else if ((rssi > sq_thresh->lower_threshold[3]) &&1470			   (rssi <= sq_thresh->lower_threshold[2])) {1471			new_threshold = WMI_RSSI_THRESHOLD4_BELOW;1472		} else if ((rssi > sq_thresh->lower_threshold[4]) &&1473			   (rssi <= sq_thresh->lower_threshold[3])) {1474			new_threshold = WMI_RSSI_THRESHOLD3_BELOW;1475		} else if ((rssi > sq_thresh->lower_threshold[5]) &&1476			   (rssi <= sq_thresh->lower_threshold[4])) {1477			new_threshold = WMI_RSSI_THRESHOLD2_BELOW;1478		} else if (rssi <= sq_thresh->lower_threshold[5]) {1479			new_threshold = WMI_RSSI_THRESHOLD1_BELOW;1480		}1481	}1482 1483	/* Calculate and install the next set of thresholds */1484	lower_rssi_threshold = ath6kl_wmi_get_lower_threshold(rssi, sq_thresh,1485				       sq_thresh->lower_threshold_valid_count);1486	upper_rssi_threshold = ath6kl_wmi_get_upper_threshold(rssi, sq_thresh,1487				       sq_thresh->upper_threshold_valid_count);1488 1489	/* Issue a wmi command to install the thresholds */1490	cmd.thresh_above1_val = a_cpu_to_sle16(upper_rssi_threshold);1491	cmd.thresh_below1_val = a_cpu_to_sle16(lower_rssi_threshold);1492	cmd.weight = sq_thresh->weight;1493	cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);1494 1495	ret = ath6kl_wmi_send_rssi_threshold_params(wmi, &cmd);1496	if (ret) {1497		ath6kl_err("unable to configure rssi thresholds\n");1498		return -EIO;1499	}1500 1501	return 0;1502}1503 1504static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,1505				   struct ath6kl_vif *vif)1506{1507	struct wmi_cac_event *reply;1508	struct ieee80211_tspec_ie *ts;1509	u16 active_tsids, tsinfo;1510	u8 tsid, index;1511	u8 ts_id;1512 1513	if (len < sizeof(struct wmi_cac_event))1514		return -EINVAL;1515 1516	reply = (struct wmi_cac_event *) datap;1517	if (reply->ac >= WMM_NUM_AC) {1518		ath6kl_err("invalid AC: %d\n", reply->ac);1519		return -EINVAL;1520	}1521 1522	if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&1523	    (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {1524		ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);1525		tsinfo = le16_to_cpu(ts->tsinfo);1526		tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &1527			IEEE80211_WMM_IE_TSPEC_TID_MASK;1528 1529		ath6kl_wmi_delete_pstream_cmd(wmi, vif->fw_vif_idx,1530					      reply->ac, tsid);1531	} else if (reply->cac_indication == CAC_INDICATION_NO_RESP) {1532		/*1533		 * Following assumes that there is only one outstanding1534		 * ADDTS request when this event is received1535		 */1536		spin_lock_bh(&wmi->lock);1537		active_tsids = wmi->stream_exist_for_ac[reply->ac];1538		spin_unlock_bh(&wmi->lock);1539 1540		for (index = 0; index < sizeof(active_tsids) * 8; index++) {1541			if ((active_tsids >> index) & 1)1542				break;1543		}1544		if (index < (sizeof(active_tsids) * 8))1545			ath6kl_wmi_delete_pstream_cmd(wmi, vif->fw_vif_idx,1546						      reply->ac, index);1547	}1548 1549	/*1550	 * Clear active tsids and Add missing handling1551	 * for delete qos stream from AP1552	 */1553	else if (reply->cac_indication == CAC_INDICATION_DELETE) {1554		ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion);1555		tsinfo = le16_to_cpu(ts->tsinfo);1556		ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) &1557			 IEEE80211_WMM_IE_TSPEC_TID_MASK);1558 1559		spin_lock_bh(&wmi->lock);1560		wmi->stream_exist_for_ac[reply->ac] &= ~(1 << ts_id);1561		active_tsids = wmi->stream_exist_for_ac[reply->ac];1562		spin_unlock_bh(&wmi->lock);1563 1564		/* Indicate stream inactivity to driver layer only if all tsids1565		 * within this AC are deleted.1566		 */1567		if (!active_tsids) {1568			ath6kl_indicate_tx_activity(wmi->parent_dev, reply->ac,1569						    false);1570			wmi->fat_pipe_exist &= ~(1 << reply->ac);1571		}1572	}1573 1574	return 0;1575}1576 1577static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len,1578					  struct ath6kl_vif *vif)1579{1580	struct wmi_txe_notify_event *ev;1581	u32 rate, pkts;1582 1583	if (len < sizeof(*ev))1584		return -EINVAL;1585 1586	if (vif->nw_type != INFRA_NETWORK ||1587	    !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY,1588		      vif->ar->fw_capabilities))1589		return -EOPNOTSUPP;1590 1591	if (vif->sme_state != SME_CONNECTED)1592		return -ENOTCONN;1593 1594	ev = (struct wmi_txe_notify_event *) datap;1595	rate = le32_to_cpu(ev->rate);1596	pkts = le32_to_cpu(ev->pkts);1597 1598	ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d%% pkts %d intvl %ds\n",1599		   vif->bssid, rate, pkts, vif->txe_intvl);1600 1601	cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts,1602				rate, vif->txe_intvl, GFP_KERNEL);1603 1604	return 0;1605}1606 1607int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,1608			      u32 rate, u32 pkts, u32 intvl)1609{1610	struct sk_buff *skb;1611	struct wmi_txe_notify_cmd *cmd;1612 1613	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));1614	if (!skb)1615		return -ENOMEM;1616 1617	cmd = (struct wmi_txe_notify_cmd *) skb->data;1618	cmd->rate = cpu_to_le32(rate);1619	cmd->pkts = cpu_to_le32(pkts);1620	cmd->intvl = cpu_to_le32(intvl);1621 1622	return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID,1623				   NO_SYNC_WMIFLAG);1624}1625 1626int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi)1627{1628	struct sk_buff *skb;1629	struct wmi_set_rssi_filter_cmd *cmd;1630	int ret;1631 1632	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));1633	if (!skb)1634		return -ENOMEM;1635 1636	cmd = (struct wmi_set_rssi_filter_cmd *) skb->data;1637	cmd->rssi = rssi;1638 1639	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID,1640				  NO_SYNC_WMIFLAG);1641	return ret;1642}1643 1644static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,1645			struct wmi_snr_threshold_params_cmd *snr_cmd)1646{1647	struct sk_buff *skb;1648	struct wmi_snr_threshold_params_cmd *cmd;1649 1650	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));1651	if (!skb)1652		return -ENOMEM;1653 1654	cmd = (struct wmi_snr_threshold_params_cmd *) skb->data;1655	memcpy(cmd, snr_cmd, sizeof(struct wmi_snr_threshold_params_cmd));1656 1657	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SNR_THRESHOLD_PARAMS_CMDID,1658				   NO_SYNC_WMIFLAG);1659}1660 1661static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap,1662					     int len)1663{1664	struct wmi_snr_threshold_event *reply;1665	struct sq_threshold_params *sq_thresh;1666	struct wmi_snr_threshold_params_cmd cmd;1667	enum wmi_snr_threshold_val new_threshold;1668	u8 upper_snr_threshold, lower_snr_threshold;1669	s16 snr;1670	int ret;1671 1672	if (len < sizeof(struct wmi_snr_threshold_event))1673		return -EINVAL;1674 1675	reply = (struct wmi_snr_threshold_event *) datap;1676 1677	new_threshold = (enum wmi_snr_threshold_val) reply->range;1678	snr = reply->snr;1679 1680	sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_SNR];1681 1682	/*1683	 * Identify the threshold breached and communicate that to the app.1684	 * After that install a new set of thresholds based on the signal1685	 * quality reported by the target.1686	 */1687	if (new_threshold) {1688		/* Upper threshold breached */1689		if (snr < sq_thresh->upper_threshold[0]) {1690			ath6kl_dbg(ATH6KL_DBG_WMI,1691				   "spurious upper snr threshold event: %d\n",1692				   snr);1693		} else if ((snr < sq_thresh->upper_threshold[1]) &&1694			   (snr >= sq_thresh->upper_threshold[0])) {1695			new_threshold = WMI_SNR_THRESHOLD1_ABOVE;1696		} else if ((snr < sq_thresh->upper_threshold[2]) &&1697			   (snr >= sq_thresh->upper_threshold[1])) {1698			new_threshold = WMI_SNR_THRESHOLD2_ABOVE;1699		} else if ((snr < sq_thresh->upper_threshold[3]) &&1700			   (snr >= sq_thresh->upper_threshold[2])) {1701			new_threshold = WMI_SNR_THRESHOLD3_ABOVE;1702		} else if (snr >= sq_thresh->upper_threshold[3]) {1703			new_threshold = WMI_SNR_THRESHOLD4_ABOVE;1704		}1705	} else {1706		/* Lower threshold breached */1707		if (snr > sq_thresh->lower_threshold[0]) {1708			ath6kl_dbg(ATH6KL_DBG_WMI,1709				   "spurious lower snr threshold event: %d\n",1710				   sq_thresh->lower_threshold[0]);1711		} else if ((snr > sq_thresh->lower_threshold[1]) &&1712			   (snr <= sq_thresh->lower_threshold[0])) {1713			new_threshold = WMI_SNR_THRESHOLD4_BELOW;1714		} else if ((snr > sq_thresh->lower_threshold[2]) &&1715			   (snr <= sq_thresh->lower_threshold[1])) {1716			new_threshold = WMI_SNR_THRESHOLD3_BELOW;1717		} else if ((snr > sq_thresh->lower_threshold[3]) &&1718			   (snr <= sq_thresh->lower_threshold[2])) {1719			new_threshold = WMI_SNR_THRESHOLD2_BELOW;1720		} else if (snr <= sq_thresh->lower_threshold[3]) {1721			new_threshold = WMI_SNR_THRESHOLD1_BELOW;1722		}1723	}1724 1725	/* Calculate and install the next set of thresholds */1726	lower_snr_threshold = ath6kl_wmi_get_lower_threshold(snr, sq_thresh,1727				       sq_thresh->lower_threshold_valid_count);1728	upper_snr_threshold = ath6kl_wmi_get_upper_threshold(snr, sq_thresh,1729				       sq_thresh->upper_threshold_valid_count);1730 1731	/* Issue a wmi command to install the thresholds */1732	cmd.thresh_above1_val = upper_snr_threshold;1733	cmd.thresh_below1_val = lower_snr_threshold;1734	cmd.weight = sq_thresh->weight;1735	cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval);1736 1737	ath6kl_dbg(ATH6KL_DBG_WMI,1738		   "snr: %d, threshold: %d, lower: %d, upper: %d\n",1739		   snr, new_threshold,1740		   lower_snr_threshold, upper_snr_threshold);1741 1742	ret = ath6kl_wmi_send_snr_threshold_params(wmi, &cmd);1743	if (ret) {1744		ath6kl_err("unable to configure snr threshold\n");1745		return -EIO;1746	}1747 1748	return 0;1749}1750 1751static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len)1752{1753	struct wmi_aplist_event *ev = (struct wmi_aplist_event *) datap;1754	struct wmi_ap_info_v1 *ap_info_v1;1755	u8 index;1756 1757	if (len < sizeof(struct wmi_aplist_event) ||1758	    ev->ap_list_ver != APLIST_VER1)1759		return -EINVAL;1760 1761	ap_info_v1 = (struct wmi_ap_info_v1 *) ev->ap_list;1762 1763	ath6kl_dbg(ATH6KL_DBG_WMI,1764		   "number of APs in aplist event: %d\n", ev->num_ap);1765 1766	if (len < struct_size(ev, ap_list, ev->num_ap))1767		return -EINVAL;1768 1769	/* AP list version 1 contents */1770	for (index = 0; index < ev->num_ap; index++) {1771		ath6kl_dbg(ATH6KL_DBG_WMI, "AP#%d BSSID %pM Channel %d\n",1772			   index, ap_info_v1->bssid, ap_info_v1->channel);1773		ap_info_v1++;1774	}1775 1776	return 0;1777}1778 1779int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,1780			enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag)1781{1782	struct wmi_cmd_hdr *cmd_hdr;1783	enum htc_endpoint_id ep_id = wmi->ep_id;1784	int ret;1785	u16 info1;1786 1787	if (WARN_ON(skb == NULL ||1788		    (if_idx > (wmi->parent_dev->vif_max - 1)))) {1789		dev_kfree_skb(skb);1790		return -EINVAL;1791	}1792 1793	ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",1794		   cmd_id, skb->len, sync_flag);1795	ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi tx ",1796			skb->data, skb->len);1797 1798	if (sync_flag >= END_WMIFLAG) {1799		dev_kfree_skb(skb);1800		return -EINVAL;1801	}1802 1803	if ((sync_flag == SYNC_BEFORE_WMIFLAG) ||1804	    (sync_flag == SYNC_BOTH_WMIFLAG)) {1805		/*1806		 * Make sure all data currently queued is transmitted before1807		 * the cmd execution.  Establish a new sync point.1808		 */1809		ath6kl_wmi_sync_point(wmi, if_idx);1810	}1811 1812	skb_push(skb, sizeof(struct wmi_cmd_hdr));1813 1814	cmd_hdr = (struct wmi_cmd_hdr *) skb->data;1815	cmd_hdr->cmd_id = cpu_to_le16(cmd_id);1816	info1 = if_idx & WMI_CMD_HDR_IF_ID_MASK;1817	cmd_hdr->info1 = cpu_to_le16(info1);1818 1819	/* Only for OPT_TX_CMD, use BE endpoint. */1820	if (cmd_id == WMI_OPT_TX_FRAME_CMDID) {1821		ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE, false,1822				WMI_DATA_HDR_DATA_TYPE_802_3, 0, NULL, if_idx);1823		if (ret) {1824			dev_kfree_skb(skb);1825			return ret;1826		}1827		ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, WMM_AC_BE);1828	}1829 1830	ath6kl_control_tx(wmi->parent_dev, skb, ep_id);1831 1832	if ((sync_flag == SYNC_AFTER_WMIFLAG) ||1833	    (sync_flag == SYNC_BOTH_WMIFLAG)) {1834		/*1835		 * Make sure all new data queued waits for the command to1836		 * execute. Establish a new sync point.1837		 */1838		ath6kl_wmi_sync_point(wmi, if_idx);1839	}1840 1841	return 0;1842}1843 1844int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,1845			   enum network_type nw_type,1846			   enum dot11_auth_mode dot11_auth_mode,1847			   enum auth_mode auth_mode,1848			   enum ath6kl_crypto_type pairwise_crypto,1849			   u8 pairwise_crypto_len,1850			   enum ath6kl_crypto_type group_crypto,1851			   u8 group_crypto_len, int ssid_len, u8 *ssid,1852			   u8 *bssid, u16 channel, u32 ctrl_flags,1853			   u8 nw_subtype)1854{1855	struct sk_buff *skb;1856	struct wmi_connect_cmd *cc;1857	int ret;1858 1859	ath6kl_dbg(ATH6KL_DBG_WMI,1860		   "wmi connect bssid %pM freq %d flags 0x%x ssid_len %d "1861		   "type %d dot11_auth %d auth %d pairwise %d group %d\n",1862		   bssid, channel, ctrl_flags, ssid_len, nw_type,1863		   dot11_auth_mode, auth_mode, pairwise_crypto, group_crypto);1864	ath6kl_dbg_dump(ATH6KL_DBG_WMI, NULL, "ssid ", ssid, ssid_len);1865 1866	wmi->traffic_class = 100;1867 1868	if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT))1869		return -EINVAL;1870 1871	if ((pairwise_crypto != NONE_CRYPT) && (group_crypto == NONE_CRYPT))1872		return -EINVAL;1873 1874	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_connect_cmd));1875	if (!skb)1876		return -ENOMEM;1877 1878	cc = (struct wmi_connect_cmd *) skb->data;1879 1880	if (ssid_len)1881		memcpy(cc->ssid, ssid, ssid_len);1882 1883	cc->ssid_len = ssid_len;1884	cc->nw_type = nw_type;1885	cc->dot11_auth_mode = dot11_auth_mode;1886	cc->auth_mode = auth_mode;1887	cc->prwise_crypto_type = pairwise_crypto;1888	cc->prwise_crypto_len = pairwise_crypto_len;1889	cc->grp_crypto_type = group_crypto;1890	cc->grp_crypto_len = group_crypto_len;1891	cc->ch = cpu_to_le16(channel);1892	cc->ctrl_flags = cpu_to_le32(ctrl_flags);1893	cc->nw_subtype = nw_subtype;1894 1895	if (bssid != NULL)1896		memcpy(cc->bssid, bssid, ETH_ALEN);1897 1898	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_CONNECT_CMDID,1899				  NO_SYNC_WMIFLAG);1900 1901	return ret;1902}1903 1904int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,1905			     u16 channel)1906{1907	struct sk_buff *skb;1908	struct wmi_reconnect_cmd *cc;1909	int ret;1910 1911	ath6kl_dbg(ATH6KL_DBG_WMI, "wmi reconnect bssid %pM freq %d\n",1912		   bssid, channel);1913 1914	wmi->traffic_class = 100;1915 1916	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd));1917	if (!skb)1918		return -ENOMEM;1919 1920	cc = (struct wmi_reconnect_cmd *) skb->data;1921	cc->channel = cpu_to_le16(channel);1922 1923	if (bssid != NULL)1924		memcpy(cc->bssid, bssid, ETH_ALEN);1925 1926	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_RECONNECT_CMDID,1927				  NO_SYNC_WMIFLAG);1928 1929	return ret;1930}1931 1932int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)1933{1934	int ret;1935 1936	ath6kl_dbg(ATH6KL_DBG_WMI, "wmi disconnect\n");1937 1938	wmi->traffic_class = 100;1939 1940	/* Disconnect command does not need to do a SYNC before. */1941	ret = ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_DISCONNECT_CMDID);1942 1943	return ret;1944}1945 1946/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use1947 * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P1948 * mgmt operations using station interface.1949 */1950static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,1951				    enum wmi_scan_type scan_type,1952				    u32 force_fgscan, u32 is_legacy,1953				    u32 home_dwell_time,1954				    u32 force_scan_interval,1955				    s8 num_chan, u16 *ch_list)1956{1957	struct sk_buff *skb;1958	struct wmi_start_scan_cmd *sc;1959	int i, ret;1960 1961	if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))1962		return -EINVAL;1963 1964	if (num_chan > WMI_MAX_CHANNELS)1965		return -EINVAL;1966 1967	skb = ath6kl_wmi_get_new_buf(struct_size(sc, ch_list, num_chan));1968	if (!skb)1969		return -ENOMEM;1970 1971	sc = (struct wmi_start_scan_cmd *) skb->data;1972	sc->scan_type = scan_type;1973	sc->force_fg_scan = cpu_to_le32(force_fgscan);1974	sc->is_legacy = cpu_to_le32(is_legacy);1975	sc->home_dwell_time = cpu_to_le32(home_dwell_time);1976	sc->force_scan_intvl = cpu_to_le32(force_scan_interval);1977	sc->num_ch = num_chan;1978 1979	for (i = 0; i < num_chan; i++)1980		sc->ch_list[i] = cpu_to_le16(ch_list[i]);1981 1982	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID,1983				  NO_SYNC_WMIFLAG);1984 1985	return ret;1986}1987 1988/*1989 * beginscan supports (compared to old startscan) P2P mgmt operations using1990 * station interface, send additional information like supported rates to1991 * advertise and xmit rates for probe requests1992 */1993int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,1994			     enum wmi_scan_type scan_type,1995			     u32 force_fgscan, u32 is_legacy,1996			     u32 home_dwell_time, u32 force_scan_interval,1997			     s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)1998{1999	struct ieee80211_supported_band *sband;2000	struct sk_buff *skb;2001	struct wmi_begin_scan_cmd *sc;2002	s8 *supp_rates;2003	int i, band, ret;2004	struct ath6kl *ar = wmi->parent_dev;2005	int num_rates;2006	u32 ratemask;2007 2008	if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,2009		      ar->fw_capabilities)) {2010		return ath6kl_wmi_startscan_cmd(wmi, if_idx,2011						scan_type, force_fgscan,2012						is_legacy, home_dwell_time,2013						force_scan_interval,2014						num_chan, ch_list);2015	}2016 2017	if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))2018		return -EINVAL;2019 2020	if (num_chan > WMI_MAX_CHANNELS)2021		return -EINVAL;2022 2023	skb = ath6kl_wmi_get_new_buf(struct_size(sc, ch_list, num_chan));2024	if (!skb)2025		return -ENOMEM;2026 2027	sc = (struct wmi_begin_scan_cmd *) skb->data;2028	sc->scan_type = scan_type;2029	sc->force_fg_scan = cpu_to_le32(force_fgscan);2030	sc->is_legacy = cpu_to_le32(is_legacy);2031	sc->home_dwell_time = cpu_to_le32(home_dwell_time);2032	sc->force_scan_intvl = cpu_to_le32(force_scan_interval);2033	sc->no_cck = cpu_to_le32(no_cck);2034	sc->num_ch = num_chan;2035 2036	for (band = 0; band < NUM_NL80211_BANDS; band++) {2037		sband = ar->wiphy->bands[band];2038 2039		if (!sband)2040			continue;2041 2042		if (WARN_ON(band >= ATH6KL_NUM_BANDS))2043			break;2044 2045		ratemask = rates[band];2046		supp_rates = sc->supp_rates[band].rates;2047		num_rates = 0;2048 2049		for (i = 0; i < sband->n_bitrates; i++) {2050			if ((BIT(i) & ratemask) == 0)2051				continue; /* skip rate */2052			supp_rates[num_rates++] =2053			    (u8) (sband->bitrates[i].bitrate / 5);2054		}2055		sc->supp_rates[band].nrates = num_rates;2056	}2057 2058	for (i = 0; i < num_chan; i++)2059		sc->ch_list[i] = cpu_to_le16(ch_list[i]);2060 2061	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_BEGIN_SCAN_CMDID,2062				  NO_SYNC_WMIFLAG);2063 2064	return ret;2065}2066 2067int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable)2068{2069	struct sk_buff *skb;2070	struct wmi_enable_sched_scan_cmd *sc;2071	int ret;2072 2073	skb = ath6kl_wmi_get_new_buf(sizeof(*sc));2074	if (!skb)2075		return -ENOMEM;2076 2077	ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n",2078		   enable ? "enabling" : "disabling", if_idx);2079	sc = (struct wmi_enable_sched_scan_cmd *) skb->data;2080	sc->enable = enable ? 1 : 0;2081 2082	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,2083				  WMI_ENABLE_SCHED_SCAN_CMDID,2084				  NO_SYNC_WMIFLAG);2085	return ret;2086}2087 2088int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx,2089			      u16 fg_start_sec,2090			      u16 fg_end_sec, u16 bg_sec,2091			      u16 minact_chdw_msec, u16 maxact_chdw_msec,2092			      u16 pas_chdw_msec, u8 short_scan_ratio,2093			      u8 scan_ctrl_flag, u32 max_dfsch_act_time,2094			      u16 maxact_scan_per_ssid)2095{2096	struct sk_buff *skb;2097	struct wmi_scan_params_cmd *sc;2098	int ret;2099 2100	skb = ath6kl_wmi_get_new_buf(sizeof(*sc));2101	if (!skb)2102		return -ENOMEM;2103 2104	sc = (struct wmi_scan_params_cmd *) skb->data;2105	sc->fg_start_period = cpu_to_le16(fg_start_sec);2106	sc->fg_end_period = cpu_to_le16(fg_end_sec);2107	sc->bg_period = cpu_to_le16(bg_sec);2108	sc->minact_chdwell_time = cpu_to_le16(minact_chdw_msec);2109	sc->maxact_chdwell_time = cpu_to_le16(maxact_chdw_msec);2110	sc->pas_chdwell_time = cpu_to_le16(pas_chdw_msec);2111	sc->short_scan_ratio = short_scan_ratio;2112	sc->scan_ctrl_flags = scan_ctrl_flag;2113	sc->max_dfsch_act_time = cpu_to_le32(max_dfsch_act_time);2114	sc->maxact_scan_per_ssid = cpu_to_le16(maxact_scan_per_ssid);2115 2116	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_SCAN_PARAMS_CMDID,2117				  NO_SYNC_WMIFLAG);2118	return ret;2119}2120 2121int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 if_idx, u8 filter, u32 ie_mask)2122{2123	struct sk_buff *skb;2124	struct wmi_bss_filter_cmd *cmd;2125	int ret;2126 2127	if (filter >= LAST_BSS_FILTER)2128		return -EINVAL;2129 2130	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2131	if (!skb)2132		return -ENOMEM;2133 2134	cmd = (struct wmi_bss_filter_cmd *) skb->data;2135	cmd->bss_filter = filter;2136	cmd->ie_mask = cpu_to_le32(ie_mask);2137 2138	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BSS_FILTER_CMDID,2139				  NO_SYNC_WMIFLAG);2140	return ret;2141}2142 2143int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag,2144			      u8 ssid_len, u8 *ssid)2145{2146	struct sk_buff *skb;2147	struct wmi_probed_ssid_cmd *cmd;2148	int ret;2149 2150	if (index >= MAX_PROBED_SSIDS)2151		return -EINVAL;2152 2153	if (ssid_len > sizeof(cmd->ssid))2154		return -EINVAL;2155 2156	if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssid_len > 0))2157		return -EINVAL;2158 2159	if ((flag & SPECIFIC_SSID_FLAG) && !ssid_len)2160		return -EINVAL;2161 2162	if (flag & SPECIFIC_SSID_FLAG)2163		wmi->is_probe_ssid = true;2164 2165	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2166	if (!skb)2167		return -ENOMEM;2168 2169	cmd = (struct wmi_probed_ssid_cmd *) skb->data;2170	cmd->entry_index = index;2171	cmd->flag = flag;2172	cmd->ssid_len = ssid_len;2173	memcpy(cmd->ssid, ssid, ssid_len);2174 2175	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_PROBED_SSID_CMDID,2176				  NO_SYNC_WMIFLAG);2177	return ret;2178}2179 2180int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u8 if_idx,2181				  u16 listen_interval,2182				  u16 listen_beacons)2183{2184	struct sk_buff *skb;2185	struct wmi_listen_int_cmd *cmd;2186	int ret;2187 2188	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2189	if (!skb)2190		return -ENOMEM;2191 2192	cmd = (struct wmi_listen_int_cmd *) skb->data;2193	cmd->listen_intvl = cpu_to_le16(listen_interval);2194	cmd->num_beacons = cpu_to_le16(listen_beacons);2195 2196	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_LISTEN_INT_CMDID,2197				  NO_SYNC_WMIFLAG);2198	return ret;2199}2200 2201int ath6kl_wmi_bmisstime_cmd(struct wmi *wmi, u8 if_idx,2202			     u16 bmiss_time, u16 num_beacons)2203{2204	struct sk_buff *skb;2205	struct wmi_bmiss_time_cmd *cmd;2206	int ret;2207 2208	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2209	if (!skb)2210		return -ENOMEM;2211 2212	cmd = (struct wmi_bmiss_time_cmd *) skb->data;2213	cmd->bmiss_time = cpu_to_le16(bmiss_time);2214	cmd->num_beacons = cpu_to_le16(num_beacons);2215 2216	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_BMISS_TIME_CMDID,2217				  NO_SYNC_WMIFLAG);2218	return ret;2219}2220 2221int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 if_idx, u8 pwr_mode)2222{2223	struct sk_buff *skb;2224	struct wmi_power_mode_cmd *cmd;2225	int ret;2226 2227	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2228	if (!skb)2229		return -ENOMEM;2230 2231	cmd = (struct wmi_power_mode_cmd *) skb->data;2232	cmd->pwr_mode = pwr_mode;2233	wmi->pwr_mode = pwr_mode;2234 2235	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_POWER_MODE_CMDID,2236				  NO_SYNC_WMIFLAG);2237	return ret;2238}2239 2240int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u8 if_idx, u16 idle_period,2241			    u16 ps_poll_num, u16 dtim_policy,2242			    u16 tx_wakeup_policy, u16 num_tx_to_wakeup,2243			    u16 ps_fail_event_policy)2244{2245	struct sk_buff *skb;2246	struct wmi_power_params_cmd *pm;2247	int ret;2248 2249	skb = ath6kl_wmi_get_new_buf(sizeof(*pm));2250	if (!skb)2251		return -ENOMEM;2252 2253	pm = (struct wmi_power_params_cmd *)skb->data;2254	pm->idle_period = cpu_to_le16(idle_period);2255	pm->pspoll_number = cpu_to_le16(ps_poll_num);2256	pm->dtim_policy = cpu_to_le16(dtim_policy);2257	pm->tx_wakeup_policy = cpu_to_le16(tx_wakeup_policy);2258	pm->num_tx_to_wakeup = cpu_to_le16(num_tx_to_wakeup);2259	pm->ps_fail_event_policy = cpu_to_le16(ps_fail_event_policy);2260 2261	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_POWER_PARAMS_CMDID,2262				  NO_SYNC_WMIFLAG);2263	return ret;2264}2265 2266int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 if_idx, u8 timeout)2267{2268	struct sk_buff *skb;2269	struct wmi_disc_timeout_cmd *cmd;2270	int ret;2271 2272	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2273	if (!skb)2274		return -ENOMEM;2275 2276	cmd = (struct wmi_disc_timeout_cmd *) skb->data;2277	cmd->discon_timeout = timeout;2278 2279	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_DISC_TIMEOUT_CMDID,2280				  NO_SYNC_WMIFLAG);2281 2282	if (ret == 0)2283		ath6kl_debug_set_disconnect_timeout(wmi->parent_dev, timeout);2284 2285	return ret;2286}2287 2288int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,2289			  enum ath6kl_crypto_type key_type,2290			  u8 key_usage, u8 key_len,2291			  u8 *key_rsc, unsigned int key_rsc_len,2292			  u8 *key_material,2293			  u8 key_op_ctrl, u8 *mac_addr,2294			  enum wmi_sync_flag sync_flag)2295{2296	struct sk_buff *skb;2297	struct wmi_add_cipher_key_cmd *cmd;2298	int ret;2299 2300	ath6kl_dbg(ATH6KL_DBG_WMI,2301		   "addkey cmd: key_index=%u key_type=%d key_usage=%d key_len=%d key_op_ctrl=%d\n",2302		   key_index, key_type, key_usage, key_len, key_op_ctrl);2303 2304	if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||2305	    (key_material == NULL) || key_rsc_len > 8)2306		return -EINVAL;2307 2308	if ((WEP_CRYPT != key_type) && (NULL == key_rsc))2309		return -EINVAL;2310 2311	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2312	if (!skb)2313		return -ENOMEM;2314 2315	cmd = (struct wmi_add_cipher_key_cmd *) skb->data;2316	cmd->key_index = key_index;2317	cmd->key_type = key_type;2318	cmd->key_usage = key_usage;2319	cmd->key_len = key_len;2320	memcpy(cmd->key, key_material, key_len);2321 2322	if (key_rsc != NULL)2323		memcpy(cmd->key_rsc, key_rsc, key_rsc_len);2324 2325	cmd->key_op_ctrl = key_op_ctrl;2326 2327	if (mac_addr)2328		memcpy(cmd->key_mac_addr, mac_addr, ETH_ALEN);2329 2330	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_CIPHER_KEY_CMDID,2331				  sync_flag);2332 2333	return ret;2334}2335 2336int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 if_idx, const u8 *krk)2337{2338	struct sk_buff *skb;2339	struct wmi_add_krk_cmd *cmd;2340	int ret;2341 2342	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2343	if (!skb)2344		return -ENOMEM;2345 2346	cmd = (struct wmi_add_krk_cmd *) skb->data;2347	memcpy(cmd->krk, krk, WMI_KRK_LEN);2348 2349	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_KRK_CMDID,2350				  NO_SYNC_WMIFLAG);2351 2352	return ret;2353}2354 2355int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index)2356{2357	struct sk_buff *skb;2358	struct wmi_delete_cipher_key_cmd *cmd;2359	int ret;2360 2361	if (key_index > WMI_MAX_KEY_INDEX)2362		return -EINVAL;2363 2364	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2365	if (!skb)2366		return -ENOMEM;2367 2368	cmd = (struct wmi_delete_cipher_key_cmd *) skb->data;2369	cmd->key_index = key_index;2370 2371	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DELETE_CIPHER_KEY_CMDID,2372				  NO_SYNC_WMIFLAG);2373 2374	return ret;2375}2376 2377int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, u8 if_idx, const u8 *bssid,2378			    const u8 *pmkid, bool set)2379{2380	struct sk_buff *skb;2381	struct wmi_setpmkid_cmd *cmd;2382	int ret;2383 2384	if (bssid == NULL)2385		return -EINVAL;2386 2387	if (set && pmkid == NULL)2388		return -EINVAL;2389 2390	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2391	if (!skb)2392		return -ENOMEM;2393 2394	cmd = (struct wmi_setpmkid_cmd *) skb->data;2395	memcpy(cmd->bssid, bssid, ETH_ALEN);2396	if (set) {2397		memcpy(cmd->pmkid, pmkid, sizeof(cmd->pmkid));2398		cmd->enable = PMKID_ENABLE;2399	} else {2400		memset(cmd->pmkid, 0, sizeof(cmd->pmkid));2401		cmd->enable = PMKID_DISABLE;2402	}2403 2404	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_PMKID_CMDID,2405				  NO_SYNC_WMIFLAG);2406 2407	return ret;2408}2409 2410static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,2411			      enum htc_endpoint_id ep_id, u8 if_idx)2412{2413	struct wmi_data_hdr *data_hdr;2414	int ret;2415 2416	if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) {2417		dev_kfree_skb(skb);2418		return -EINVAL;2419	}2420 2421	skb_push(skb, sizeof(struct wmi_data_hdr));2422 2423	data_hdr = (struct wmi_data_hdr *) skb->data;2424	data_hdr->info = SYNC_MSGTYPE << WMI_DATA_HDR_MSG_TYPE_SHIFT;2425	data_hdr->info3 = cpu_to_le16(if_idx & WMI_DATA_HDR_IF_IDX_MASK);2426 2427	ret = ath6kl_control_tx(wmi->parent_dev, skb, ep_id);2428 2429	return ret;2430}2431 2432static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)2433{2434	struct sk_buff *skb;2435	struct wmi_sync_cmd *cmd;2436	struct wmi_data_sync_bufs data_sync_bufs[WMM_NUM_AC];2437	enum htc_endpoint_id ep_id;2438	u8 index, num_pri_streams = 0;2439	int ret = 0;2440 2441	memset(data_sync_bufs, 0, sizeof(data_sync_bufs));2442 2443	spin_lock_bh(&wmi->lock);2444 2445	for (index = 0; index < WMM_NUM_AC; index++) {2446		if (wmi->fat_pipe_exist & (1 << index)) {2447			num_pri_streams++;2448			data_sync_bufs[num_pri_streams - 1].traffic_class =2449			    index;2450		}2451	}2452 2453	spin_unlock_bh(&wmi->lock);2454 2455	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2456	if (!skb)2457		return -ENOMEM;2458 2459	cmd = (struct wmi_sync_cmd *) skb->data;2460 2461	/*2462	 * In the SYNC cmd sent on the control Ep, send a bitmap2463	 * of the data eps on which the Data Sync will be sent2464	 */2465	cmd->data_sync_map = wmi->fat_pipe_exist;2466 2467	for (index = 0; index < num_pri_streams; index++) {2468		data_sync_bufs[index].skb = ath6kl_buf_alloc(0);2469		if (data_sync_bufs[index].skb == NULL) {2470			ret = -ENOMEM;2471			break;2472		}2473	}2474 2475	/*2476	 * If buffer allocation for any of the dataSync fails,2477	 * then do not send the Synchronize cmd on the control ep2478	 */2479	if (ret)2480		goto free_cmd_skb;2481 2482	/*2483	 * Send sync cmd followed by sync data messages on all2484	 * endpoints being used2485	 */2486	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SYNCHRONIZE_CMDID,2487				  NO_SYNC_WMIFLAG);2488 2489	if (ret)2490		goto free_data_skb;2491 2492	for (index = 0; index < num_pri_streams; index++) {2493		if (WARN_ON(!data_sync_bufs[index].skb)) {2494			ret = -ENOMEM;2495			goto free_data_skb;2496		}2497 2498		ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,2499					       data_sync_bufs[index].2500					       traffic_class);2501		ret =2502		    ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,2503					      ep_id, if_idx);2504 2505		data_sync_bufs[index].skb = NULL;2506 2507		if (ret)2508			goto free_data_skb;2509	}2510 2511	return 0;2512 2513free_cmd_skb:2514	/* free up any resources left over (possibly due to an error) */2515	dev_kfree_skb(skb);2516 2517free_data_skb:2518	for (index = 0; index < num_pri_streams; index++)2519		dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].skb);2520 2521	return ret;2522}2523 2524int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, u8 if_idx,2525				  struct wmi_create_pstream_cmd *params)2526{2527	struct sk_buff *skb;2528	struct wmi_create_pstream_cmd *cmd;2529	u8 fatpipe_exist_for_ac = 0;2530	s32 min_phy = 0;2531	s32 nominal_phy = 0;2532	int ret;2533 2534	if (!((params->user_pri <= 0x7) &&2535	      (up_to_ac[params->user_pri & 0x7] == params->traffic_class) &&2536	      (params->traffic_direc == UPLINK_TRAFFIC ||2537	       params->traffic_direc == DNLINK_TRAFFIC ||2538	       params->traffic_direc == BIDIR_TRAFFIC) &&2539	      (params->traffic_type == TRAFFIC_TYPE_APERIODIC ||2540	       params->traffic_type == TRAFFIC_TYPE_PERIODIC) &&2541	      (params->voice_psc_cap == DISABLE_FOR_THIS_AC ||2542	       params->voice_psc_cap == ENABLE_FOR_THIS_AC ||2543	       params->voice_psc_cap == ENABLE_FOR_ALL_AC) &&2544	      (params->tsid == WMI_IMPLICIT_PSTREAM ||2545	       params->tsid <= WMI_MAX_THINSTREAM))) {2546		return -EINVAL;2547	}2548 2549	/*2550	 * Check nominal PHY rate is >= minimalPHY,2551	 * so that DUT can allow TSRS IE2552	 */2553 2554	/* Get the physical rate (units of bps) */2555	min_phy = ((le32_to_cpu(params->min_phy_rate) / 1000) / 1000);2556 2557	/* Check minimal phy < nominal phy rate */2558	if (params->nominal_phy >= min_phy) {2559		/* unit of 500 kbps */2560		nominal_phy = (params->nominal_phy * 1000) / 500;2561		ath6kl_dbg(ATH6KL_DBG_WMI,2562			   "TSRS IE enabled::MinPhy %x->NominalPhy ===> %x\n",2563			   min_phy, nominal_phy);2564 2565		params->nominal_phy = nominal_phy;2566	} else {2567		params->nominal_phy = 0;2568	}2569 2570	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2571	if (!skb)2572		return -ENOMEM;2573 2574	ath6kl_dbg(ATH6KL_DBG_WMI,2575		   "sending create_pstream_cmd: ac=%d  tsid:%d\n",2576		   params->traffic_class, params->tsid);2577 2578	cmd = (struct wmi_create_pstream_cmd *) skb->data;2579	memcpy(cmd, params, sizeof(*cmd));2580 2581	/* This is an implicitly created Fat pipe */2582	if ((u32) params->tsid == (u32) WMI_IMPLICIT_PSTREAM) {2583		spin_lock_bh(&wmi->lock);2584		fatpipe_exist_for_ac = (wmi->fat_pipe_exist &2585					(1 << params->traffic_class));2586		wmi->fat_pipe_exist |= (1 << params->traffic_class);2587		spin_unlock_bh(&wmi->lock);2588	} else {2589		/* explicitly created thin stream within a fat pipe */2590		spin_lock_bh(&wmi->lock);2591		fatpipe_exist_for_ac = (wmi->fat_pipe_exist &2592					(1 << params->traffic_class));2593		wmi->stream_exist_for_ac[params->traffic_class] |=2594		    (1 << params->tsid);2595		/*2596		 * If a thinstream becomes active, the fat pipe automatically2597		 * becomes active2598		 */2599		wmi->fat_pipe_exist |= (1 << params->traffic_class);2600		spin_unlock_bh(&wmi->lock);2601	}2602 2603	/*2604	 * Indicate activty change to driver layer only if this is the2605	 * first TSID to get created in this AC explicitly or an implicit2606	 * fat pipe is getting created.2607	 */2608	if (!fatpipe_exist_for_ac)2609		ath6kl_indicate_tx_activity(wmi->parent_dev,2610					    params->traffic_class, true);2611 2612	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_CREATE_PSTREAM_CMDID,2613				  NO_SYNC_WMIFLAG);2614	return ret;2615}2616 2617int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class,2618				  u8 tsid)2619{2620	struct sk_buff *skb;2621	struct wmi_delete_pstream_cmd *cmd;2622	u16 active_tsids = 0;2623	int ret;2624 2625	if (traffic_class >= WMM_NUM_AC) {2626		ath6kl_err("invalid traffic class: %d\n", traffic_class);2627		return -EINVAL;2628	}2629 2630	if (tsid >= 16) {2631		ath6kl_err("invalid tsid: %d\n", tsid);2632		return -EINVAL;2633	}2634 2635	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2636	if (!skb)2637		return -ENOMEM;2638 2639	cmd = (struct wmi_delete_pstream_cmd *) skb->data;2640	cmd->traffic_class = traffic_class;2641	cmd->tsid = tsid;2642 2643	spin_lock_bh(&wmi->lock);2644	active_tsids = wmi->stream_exist_for_ac[traffic_class];2645	spin_unlock_bh(&wmi->lock);2646 2647	if (!(active_tsids & (1 << tsid))) {2648		dev_kfree_skb(skb);2649		ath6kl_dbg(ATH6KL_DBG_WMI,2650			   "TSID %d doesn't exist for traffic class: %d\n",2651			   tsid, traffic_class);2652		return -ENODATA;2653	}2654 2655	ath6kl_dbg(ATH6KL_DBG_WMI,2656		   "sending delete_pstream_cmd: traffic class: %d tsid=%d\n",2657		   traffic_class, tsid);2658 2659	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DELETE_PSTREAM_CMDID,2660				  SYNC_BEFORE_WMIFLAG);2661 2662	spin_lock_bh(&wmi->lock);2663	wmi->stream_exist_for_ac[traffic_class] &= ~(1 << tsid);2664	active_tsids = wmi->stream_exist_for_ac[traffic_class];2665	spin_unlock_bh(&wmi->lock);2666 2667	/*2668	 * Indicate stream inactivity to driver layer only if all tsids2669	 * within this AC are deleted.2670	 */2671	if (!active_tsids) {2672		ath6kl_indicate_tx_activity(wmi->parent_dev,2673					    traffic_class, false);2674		wmi->fat_pipe_exist &= ~(1 << traffic_class);2675	}2676 2677	return ret;2678}2679 2680int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx,2681			  __be32 ips0, __be32 ips1)2682{2683	struct sk_buff *skb;2684	struct wmi_set_ip_cmd *cmd;2685	int ret;2686 2687	/* Multicast address are not valid */2688	if (ipv4_is_multicast(ips0) ||2689	    ipv4_is_multicast(ips1))2690		return -EINVAL;2691 2692	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd));2693	if (!skb)2694		return -ENOMEM;2695 2696	cmd = (struct wmi_set_ip_cmd *) skb->data;2697	cmd->ips[0] = ips0;2698	cmd->ips[1] = ips1;2699 2700	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IP_CMDID,2701				  NO_SYNC_WMIFLAG);2702	return ret;2703}2704 2705static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi)2706{2707	u16 active_tsids;2708	u8 stream_exist;2709	int i;2710 2711	/*2712	 * Relinquish credits from all implicitly created pstreams2713	 * since when we go to sleep. If user created explicit2714	 * thinstreams exists with in a fatpipe leave them intact2715	 * for the user to delete.2716	 */2717	spin_lock_bh(&wmi->lock);2718	stream_exist = wmi->fat_pipe_exist;2719	spin_unlock_bh(&wmi->lock);2720 2721	for (i = 0; i < WMM_NUM_AC; i++) {2722		if (stream_exist & (1 << i)) {2723			/*2724			 * FIXME: Is this lock & unlock inside2725			 * for loop correct? may need rework.2726			 */2727			spin_lock_bh(&wmi->lock);2728			active_tsids = wmi->stream_exist_for_ac[i];2729			spin_unlock_bh(&wmi->lock);2730 2731			/*2732			 * If there are no user created thin streams2733			 * delete the fatpipe2734			 */2735			if (!active_tsids) {2736				stream_exist &= ~(1 << i);2737				/*2738				 * Indicate inactivity to driver layer for2739				 * this fatpipe (pstream)2740				 */2741				ath6kl_indicate_tx_activity(wmi->parent_dev,2742							    i, false);2743			}2744		}2745	}2746 2747	/* FIXME: Can we do this assignment without locking ? */2748	spin_lock_bh(&wmi->lock);2749	wmi->fat_pipe_exist = stream_exist;2750	spin_unlock_bh(&wmi->lock);2751}2752 2753static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,2754				     const struct cfg80211_bitrate_mask *mask)2755{2756	struct sk_buff *skb;2757	int ret, mode, band;2758	u64 mcsrate, ratemask[ATH6KL_NUM_BANDS];2759	struct wmi_set_tx_select_rates64_cmd *cmd;2760 2761	memset(&ratemask, 0, sizeof(ratemask));2762 2763	/* only check 2.4 and 5 GHz bands, skip the rest */2764	for (band = 0; band <= NL80211_BAND_5GHZ; band++) {2765		/* copy legacy rate mask */2766		ratemask[band] = mask->control[band].legacy;2767		if (band == NL80211_BAND_5GHZ)2768			ratemask[band] =2769				mask->control[band].legacy << 4;2770 2771		/* copy mcs rate mask */2772		mcsrate = mask->control[band].ht_mcs[1];2773		mcsrate <<= 8;2774		mcsrate |= mask->control[band].ht_mcs[0];2775		ratemask[band] |= mcsrate << 12;2776		ratemask[band] |= mcsrate << 28;2777	}2778 2779	ath6kl_dbg(ATH6KL_DBG_WMI,2780		   "Ratemask 64 bit: 2.4:%llx 5:%llx\n",2781		   ratemask[0], ratemask[1]);2782 2783	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);2784	if (!skb)2785		return -ENOMEM;2786 2787	cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data;2788	for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {2789		/* A mode operate in 5GHZ band */2790		if (mode == WMI_RATES_MODE_11A ||2791		    mode == WMI_RATES_MODE_11A_HT20 ||2792		    mode == WMI_RATES_MODE_11A_HT40)2793			band = NL80211_BAND_5GHZ;2794		else2795			band = NL80211_BAND_2GHZ;2796		cmd->ratemask[mode] = cpu_to_le64(ratemask[band]);2797	}2798 2799	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,2800				  WMI_SET_TX_SELECT_RATES_CMDID,2801				  NO_SYNC_WMIFLAG);2802	return ret;2803}2804 2805static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,2806				     const struct cfg80211_bitrate_mask *mask)2807{2808	struct sk_buff *skb;2809	int ret, mode, band;2810	u32 mcsrate, ratemask[ATH6KL_NUM_BANDS];2811	struct wmi_set_tx_select_rates32_cmd *cmd;2812 2813	memset(&ratemask, 0, sizeof(ratemask));2814 2815	/* only check 2.4 and 5 GHz bands, skip the rest */2816	for (band = 0; band <= NL80211_BAND_5GHZ; band++) {2817		/* copy legacy rate mask */2818		ratemask[band] = mask->control[band].legacy;2819		if (band == NL80211_BAND_5GHZ)2820			ratemask[band] =2821				mask->control[band].legacy << 4;2822 2823		/* copy mcs rate mask */2824		mcsrate = mask->control[band].ht_mcs[0];2825		ratemask[band] |= mcsrate << 12;2826		ratemask[band] |= mcsrate << 20;2827	}2828 2829	ath6kl_dbg(ATH6KL_DBG_WMI,2830		   "Ratemask 32 bit: 2.4:%x 5:%x\n",2831		   ratemask[0], ratemask[1]);2832 2833	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX);2834	if (!skb)2835		return -ENOMEM;2836 2837	cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data;2838	for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) {2839		/* A mode operate in 5GHZ band */2840		if (mode == WMI_RATES_MODE_11A ||2841		    mode == WMI_RATES_MODE_11A_HT20 ||2842		    mode == WMI_RATES_MODE_11A_HT40)2843			band = NL80211_BAND_5GHZ;2844		else2845			band = NL80211_BAND_2GHZ;2846		cmd->ratemask[mode] = cpu_to_le32(ratemask[band]);2847	}2848 2849	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,2850				  WMI_SET_TX_SELECT_RATES_CMDID,2851				  NO_SYNC_WMIFLAG);2852	return ret;2853}2854 2855int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,2856				const struct cfg80211_bitrate_mask *mask)2857{2858	struct ath6kl *ar = wmi->parent_dev;2859 2860	if (test_bit(ATH6KL_FW_CAPABILITY_64BIT_RATES,2861		     ar->fw_capabilities))2862		return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);2863	else2864		return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);2865}2866 2867int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx,2868				       enum ath6kl_host_mode host_mode)2869{2870	struct sk_buff *skb;2871	struct wmi_set_host_sleep_mode_cmd *cmd;2872	int ret;2873 2874	if ((host_mode != ATH6KL_HOST_MODE_ASLEEP) &&2875	    (host_mode != ATH6KL_HOST_MODE_AWAKE)) {2876		ath6kl_err("invalid host sleep mode: %d\n", host_mode);2877		return -EINVAL;2878	}2879 2880	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2881	if (!skb)2882		return -ENOMEM;2883 2884	cmd = (struct wmi_set_host_sleep_mode_cmd *) skb->data;2885 2886	if (host_mode == ATH6KL_HOST_MODE_ASLEEP) {2887		ath6kl_wmi_relinquish_implicit_pstream_credits(wmi);2888		cmd->asleep = cpu_to_le32(1);2889	} else {2890		cmd->awake = cpu_to_le32(1);2891	}2892 2893	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,2894				  WMI_SET_HOST_SLEEP_MODE_CMDID,2895				  NO_SYNC_WMIFLAG);2896	return ret;2897}2898 2899/* This command has zero length payload */2900static int ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(struct wmi *wmi,2901						      struct ath6kl_vif *vif)2902{2903	struct ath6kl *ar = wmi->parent_dev;2904 2905	set_bit(HOST_SLEEP_MODE_CMD_PROCESSED, &vif->flags);2906	wake_up(&ar->event_wq);2907 2908	return 0;2909}2910 2911int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx,2912				enum ath6kl_wow_mode wow_mode,2913				u32 filter, u16 host_req_delay)2914{2915	struct sk_buff *skb;2916	struct wmi_set_wow_mode_cmd *cmd;2917	int ret;2918 2919	if ((wow_mode != ATH6KL_WOW_MODE_ENABLE) &&2920	    wow_mode != ATH6KL_WOW_MODE_DISABLE) {2921		ath6kl_err("invalid wow mode: %d\n", wow_mode);2922		return -EINVAL;2923	}2924 2925	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2926	if (!skb)2927		return -ENOMEM;2928 2929	cmd = (struct wmi_set_wow_mode_cmd *) skb->data;2930	cmd->enable_wow = cpu_to_le32(wow_mode);2931	cmd->filter = cpu_to_le32(filter);2932	cmd->host_req_delay = cpu_to_le16(host_req_delay);2933 2934	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_WOW_MODE_CMDID,2935				  NO_SYNC_WMIFLAG);2936	return ret;2937}2938 2939int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,2940				   u8 list_id, u8 filter_size,2941				   u8 filter_offset, const u8 *filter,2942				   const u8 *mask)2943{2944	struct sk_buff *skb;2945	struct wmi_add_wow_pattern_cmd *cmd;2946	u16 size;2947	u8 *filter_mask;2948	int ret;2949 2950	/*2951	 * Allocate additional memory in the buffer to hold2952	 * filter and mask value, which is twice of filter_size.2953	 */2954	size = sizeof(*cmd) + (2 * filter_size);2955 2956	skb = ath6kl_wmi_get_new_buf(size);2957	if (!skb)2958		return -ENOMEM;2959 2960	cmd = (struct wmi_add_wow_pattern_cmd *) skb->data;2961	cmd->filter_list_id = list_id;2962	cmd->filter_size = filter_size;2963	cmd->filter_offset = filter_offset;2964 2965	memcpy(cmd->filter, filter, filter_size);2966 2967	filter_mask = (u8 *) (cmd->filter + filter_size);2968	memcpy(filter_mask, mask, filter_size);2969 2970	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_ADD_WOW_PATTERN_CMDID,2971				  NO_SYNC_WMIFLAG);2972 2973	return ret;2974}2975 2976int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,2977				   u16 list_id, u16 filter_id)2978{2979	struct sk_buff *skb;2980	struct wmi_del_wow_pattern_cmd *cmd;2981	int ret;2982 2983	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));2984	if (!skb)2985		return -ENOMEM;2986 2987	cmd = (struct wmi_del_wow_pattern_cmd *) skb->data;2988	cmd->filter_list_id = cpu_to_le16(list_id);2989	cmd->filter_id = cpu_to_le16(filter_id);2990 2991	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_DEL_WOW_PATTERN_CMDID,2992				  NO_SYNC_WMIFLAG);2993	return ret;2994}2995 2996static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb,2997				    enum wmix_command_id cmd_id,2998				    enum wmi_sync_flag sync_flag)2999{3000	struct wmix_cmd_hdr *cmd_hdr;3001	int ret;3002 3003	skb_push(skb, sizeof(struct wmix_cmd_hdr));3004 3005	cmd_hdr = (struct wmix_cmd_hdr *) skb->data;3006	cmd_hdr->cmd_id = cpu_to_le32(cmd_id);3007 3008	ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_EXTENSION_CMDID, sync_flag);3009 3010	return ret;3011}3012 3013int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source)3014{3015	struct sk_buff *skb;3016	struct wmix_hb_challenge_resp_cmd *cmd;3017	int ret;3018 3019	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3020	if (!skb)3021		return -ENOMEM;3022 3023	cmd = (struct wmix_hb_challenge_resp_cmd *) skb->data;3024	cmd->cookie = cpu_to_le32(cookie);3025	cmd->source = cpu_to_le32(source);3026 3027	ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_HB_CHALLENGE_RESP_CMDID,3028				       NO_SYNC_WMIFLAG);3029	return ret;3030}3031 3032int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config)3033{3034	struct ath6kl_wmix_dbglog_cfg_module_cmd *cmd;3035	struct sk_buff *skb;3036	int ret;3037 3038	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3039	if (!skb)3040		return -ENOMEM;3041 3042	cmd = (struct ath6kl_wmix_dbglog_cfg_module_cmd *) skb->data;3043	cmd->valid = cpu_to_le32(valid);3044	cmd->config = cpu_to_le32(config);3045 3046	ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_DBGLOG_CFG_MODULE_CMDID,3047				       NO_SYNC_WMIFLAG);3048	return ret;3049}3050 3051int ath6kl_wmi_get_stats_cmd(struct wmi *wmi, u8 if_idx)3052{3053	return ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_GET_STATISTICS_CMDID);3054}3055 3056int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 if_idx, u8 dbM)3057{3058	struct sk_buff *skb;3059	struct wmi_set_tx_pwr_cmd *cmd;3060	int ret;3061 3062	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_tx_pwr_cmd));3063	if (!skb)3064		return -ENOMEM;3065 3066	cmd = (struct wmi_set_tx_pwr_cmd *) skb->data;3067	cmd->dbM = dbM;3068 3069	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_TX_PWR_CMDID,3070				  NO_SYNC_WMIFLAG);3071 3072	return ret;3073}3074 3075int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi, u8 if_idx)3076{3077	return ath6kl_wmi_simple_cmd(wmi, if_idx, WMI_GET_TX_PWR_CMDID);3078}3079 3080int ath6kl_wmi_get_roam_tbl_cmd(struct wmi *wmi)3081{3082	return ath6kl_wmi_simple_cmd(wmi, 0, WMI_GET_ROAM_TBL_CMDID);3083}3084 3085int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 if_idx, u8 status,3086				 u8 preamble_policy)3087{3088	struct sk_buff *skb;3089	struct wmi_set_lpreamble_cmd *cmd;3090	int ret;3091 3092	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_lpreamble_cmd));3093	if (!skb)3094		return -ENOMEM;3095 3096	cmd = (struct wmi_set_lpreamble_cmd *) skb->data;3097	cmd->status = status;3098	cmd->preamble_policy = preamble_policy;3099 3100	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_LPREAMBLE_CMDID,3101				  NO_SYNC_WMIFLAG);3102	return ret;3103}3104 3105int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold)3106{3107	struct sk_buff *skb;3108	struct wmi_set_rts_cmd *cmd;3109	int ret;3110 3111	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_rts_cmd));3112	if (!skb)3113		return -ENOMEM;3114 3115	cmd = (struct wmi_set_rts_cmd *) skb->data;3116	cmd->threshold = cpu_to_le16(threshold);3117 3118	ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_RTS_CMDID,3119				  NO_SYNC_WMIFLAG);3120	return ret;3121}3122 3123int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, u8 if_idx, enum wmi_txop_cfg cfg)3124{3125	struct sk_buff *skb;3126	struct wmi_set_wmm_txop_cmd *cmd;3127	int ret;3128 3129	if (!((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED)))3130		return -EINVAL;3131 3132	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_wmm_txop_cmd));3133	if (!skb)3134		return -ENOMEM;3135 3136	cmd = (struct wmi_set_wmm_txop_cmd *) skb->data;3137	cmd->txop_enable = cfg;3138 3139	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_WMM_TXOP_CMDID,3140				  NO_SYNC_WMIFLAG);3141	return ret;3142}3143 3144int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 if_idx,3145				 u8 keep_alive_intvl)3146{3147	struct sk_buff *skb;3148	struct wmi_set_keepalive_cmd *cmd;3149	int ret;3150 3151	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3152	if (!skb)3153		return -ENOMEM;3154 3155	cmd = (struct wmi_set_keepalive_cmd *) skb->data;3156	cmd->keep_alive_intvl = keep_alive_intvl;3157 3158	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_KEEPALIVE_CMDID,3159				  NO_SYNC_WMIFLAG);3160 3161	if (ret == 0)3162		ath6kl_debug_set_keepalive(wmi->parent_dev, keep_alive_intvl);3163 3164	return ret;3165}3166 3167int ath6kl_wmi_set_htcap_cmd(struct wmi *wmi, u8 if_idx,3168			     enum nl80211_band band,3169			     struct ath6kl_htcap *htcap)3170{3171	struct sk_buff *skb;3172	struct wmi_set_htcap_cmd *cmd;3173 3174	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3175	if (!skb)3176		return -ENOMEM;3177 3178	cmd = (struct wmi_set_htcap_cmd *) skb->data;3179 3180	/*3181	 * NOTE: Band in firmware matches enum nl80211_band, it is unlikely3182	 * this will be changed in firmware. If at all there is any change in3183	 * band value, the host needs to be fixed.3184	 */3185	cmd->band = band;3186	cmd->ht_enable = !!htcap->ht_enable;3187	cmd->ht20_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_20);3188	cmd->ht40_supported =3189		!!(htcap->cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40);3190	cmd->ht40_sgi = !!(htcap->cap_info & IEEE80211_HT_CAP_SGI_40);3191	cmd->intolerant_40mhz =3192		!!(htcap->cap_info & IEEE80211_HT_CAP_40MHZ_INTOLERANT);3193	cmd->max_ampdu_len_exp = htcap->ampdu_factor;3194 3195	ath6kl_dbg(ATH6KL_DBG_WMI,3196		   "Set htcap: band:%d ht_enable:%d 40mhz:%d sgi_20mhz:%d sgi_40mhz:%d 40mhz_intolerant:%d ampdu_len_exp:%d\n",3197		   cmd->band, cmd->ht_enable, cmd->ht40_supported,3198		   cmd->ht20_sgi, cmd->ht40_sgi, cmd->intolerant_40mhz,3199		   cmd->max_ampdu_len_exp);3200	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_HT_CAP_CMDID,3201				   NO_SYNC_WMIFLAG);3202}3203 3204int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len)3205{3206	struct sk_buff *skb;3207	int ret;3208 3209	skb = ath6kl_wmi_get_new_buf(len);3210	if (!skb)3211		return -ENOMEM;3212 3213	memcpy(skb->data, buf, len);3214 3215	ret = ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_TEST_CMDID, NO_SYNC_WMIFLAG);3216 3217	return ret;3218}3219 3220int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on)3221{3222	struct sk_buff *skb;3223	struct wmi_mcast_filter_cmd *cmd;3224	int ret;3225 3226	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3227	if (!skb)3228		return -ENOMEM;3229 3230	cmd = (struct wmi_mcast_filter_cmd *) skb->data;3231	cmd->mcast_all_enable = mc_all_on;3232 3233	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_MCAST_FILTER_CMDID,3234				  NO_SYNC_WMIFLAG);3235	return ret;3236}3237 3238int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,3239					u8 *filter, bool add_filter)3240{3241	struct sk_buff *skb;3242	struct wmi_mcast_filter_add_del_cmd *cmd;3243	int ret;3244 3245	if ((filter[0] != 0x33 || filter[1] != 0x33) &&3246	    (filter[0] != 0x01 || filter[1] != 0x00 ||3247	    filter[2] != 0x5e || filter[3] > 0x7f)) {3248		ath6kl_warn("invalid multicast filter address\n");3249		return -EINVAL;3250	}3251 3252	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3253	if (!skb)3254		return -ENOMEM;3255 3256	cmd = (struct wmi_mcast_filter_add_del_cmd *) skb->data;3257	memcpy(cmd->mcast_mac, filter, ATH6KL_MCAST_FILTER_MAC_ADDR_SIZE);3258	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,3259				  add_filter ? WMI_SET_MCAST_FILTER_CMDID :3260				  WMI_DEL_MCAST_FILTER_CMDID,3261				  NO_SYNC_WMIFLAG);3262 3263	return ret;3264}3265 3266int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)3267{3268	struct sk_buff *skb;3269	struct wmi_sta_bmiss_enhance_cmd *cmd;3270	int ret;3271 3272	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3273	if (!skb)3274		return -ENOMEM;3275 3276	cmd = (struct wmi_sta_bmiss_enhance_cmd *) skb->data;3277	cmd->enable = enhance ? 1 : 0;3278 3279	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,3280				  WMI_STA_BMISS_ENHANCE_CMDID,3281				  NO_SYNC_WMIFLAG);3282	return ret;3283}3284 3285int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2)3286{3287	struct sk_buff *skb;3288	struct wmi_set_regdomain_cmd *cmd;3289 3290	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3291	if (!skb)3292		return -ENOMEM;3293 3294	cmd = (struct wmi_set_regdomain_cmd *) skb->data;3295	memcpy(cmd->iso_name, alpha2, 2);3296 3297	return ath6kl_wmi_cmd_send(wmi, 0, skb,3298				   WMI_SET_REGDOMAIN_CMDID,3299				   NO_SYNC_WMIFLAG);3300}3301 3302s32 ath6kl_wmi_get_rate(struct wmi *wmi, s8 rate_index)3303{3304	struct ath6kl *ar = wmi->parent_dev;3305	u8 sgi = 0;3306	s32 ret;3307 3308	if (rate_index == RATE_AUTO)3309		return 0;3310 3311	/* SGI is stored as the MSB of the rate_index */3312	if (rate_index & RATE_INDEX_MSB) {3313		rate_index &= RATE_INDEX_WITHOUT_SGI_MASK;3314		sgi = 1;3315	}3316 3317	if (test_bit(ATH6KL_FW_CAPABILITY_RATETABLE_MCS15,3318		     ar->fw_capabilities)) {3319		if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl_mcs15)))3320			return 0;3321 3322		ret = wmi_rate_tbl_mcs15[(u32) rate_index][sgi];3323	} else {3324		if (WARN_ON(rate_index >= ARRAY_SIZE(wmi_rate_tbl)))3325			return 0;3326 3327		ret = wmi_rate_tbl[(u32) rate_index][sgi];3328	}3329 3330	return ret;3331}3332 3333static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,3334					      u32 len)3335{3336	struct wmi_pmkid_list_reply *reply;3337	u32 expected_len;3338 3339	if (len < sizeof(struct wmi_pmkid_list_reply))3340		return -EINVAL;3341 3342	reply = (struct wmi_pmkid_list_reply *)datap;3343	expected_len = sizeof(reply->num_pmkid) +3344		le32_to_cpu(reply->num_pmkid) * WMI_PMKID_LEN;3345 3346	if (len < expected_len)3347		return -EINVAL;3348 3349	return 0;3350}3351 3352static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len,3353					 struct ath6kl_vif *vif)3354{3355	struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap;3356 3357	aggr_recv_addba_req_evt(vif, cmd->tid,3358				le16_to_cpu(cmd->st_seq_no), cmd->win_sz);3359 3360	return 0;3361}3362 3363static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len,3364					 struct ath6kl_vif *vif)3365{3366	struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap;3367 3368	aggr_recv_delba_req_evt(vif, cmd->tid);3369 3370	return 0;3371}3372 3373/*  AP mode functions */3374 3375int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx,3376				 struct wmi_connect_cmd *p)3377{3378	struct sk_buff *skb;3379	struct wmi_connect_cmd *cm;3380	int res;3381 3382	skb = ath6kl_wmi_get_new_buf(sizeof(*cm));3383	if (!skb)3384		return -ENOMEM;3385 3386	cm = (struct wmi_connect_cmd *) skb->data;3387	memcpy(cm, p, sizeof(*cm));3388 3389	res = ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_CONFIG_COMMIT_CMDID,3390				  NO_SYNC_WMIFLAG);3391	ath6kl_dbg(ATH6KL_DBG_WMI,3392		   "%s: nw_type=%u auth_mode=%u ch=%u ctrl_flags=0x%x-> res=%d\n",3393		   __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch),3394		   le32_to_cpu(p->ctrl_flags), res);3395	return res;3396}3397 3398int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 if_idx, u8 cmd, const u8 *mac,3399			   u16 reason)3400{3401	struct sk_buff *skb;3402	struct wmi_ap_set_mlme_cmd *cm;3403 3404	skb = ath6kl_wmi_get_new_buf(sizeof(*cm));3405	if (!skb)3406		return -ENOMEM;3407 3408	cm = (struct wmi_ap_set_mlme_cmd *) skb->data;3409	memcpy(cm->mac, mac, ETH_ALEN);3410	cm->reason = cpu_to_le16(reason);3411	cm->cmd = cmd;3412 3413	ath6kl_dbg(ATH6KL_DBG_WMI, "ap_set_mlme: cmd=%d reason=%d\n", cm->cmd,3414		   cm->reason);3415 3416	return ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_SET_MLME_CMDID,3417				   NO_SYNC_WMIFLAG);3418}3419 3420int ath6kl_wmi_ap_hidden_ssid(struct wmi *wmi, u8 if_idx, bool enable)3421{3422	struct sk_buff *skb;3423	struct wmi_ap_hidden_ssid_cmd *cmd;3424 3425	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3426	if (!skb)3427		return -ENOMEM;3428 3429	cmd = (struct wmi_ap_hidden_ssid_cmd *) skb->data;3430	cmd->hidden_ssid = enable ? 1 : 0;3431 3432	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_HIDDEN_SSID_CMDID,3433				   NO_SYNC_WMIFLAG);3434}3435 3436/* This command will be used to enable/disable AP uAPSD feature */3437int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable)3438{3439	struct wmi_ap_set_apsd_cmd *cmd;3440	struct sk_buff *skb;3441 3442	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3443	if (!skb)3444		return -ENOMEM;3445 3446	cmd = (struct wmi_ap_set_apsd_cmd *)skb->data;3447	cmd->enable = enable;3448 3449	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_APSD_CMDID,3450				   NO_SYNC_WMIFLAG);3451}3452 3453int ath6kl_wmi_set_apsd_bfrd_traf(struct wmi *wmi, u8 if_idx,3454					     u16 aid, u16 bitmap, u32 flags)3455{3456	struct wmi_ap_apsd_buffered_traffic_cmd *cmd;3457	struct sk_buff *skb;3458 3459	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3460	if (!skb)3461		return -ENOMEM;3462 3463	cmd = (struct wmi_ap_apsd_buffered_traffic_cmd *)skb->data;3464	cmd->aid = cpu_to_le16(aid);3465	cmd->bitmap = cpu_to_le16(bitmap);3466	cmd->flags = cpu_to_le32(flags);3467 3468	return ath6kl_wmi_cmd_send(wmi, if_idx, skb,3469				   WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID,3470				   NO_SYNC_WMIFLAG);3471}3472 3473static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len,3474				      struct ath6kl_vif *vif)3475{3476	struct wmi_pspoll_event *ev;3477 3478	if (len < sizeof(struct wmi_pspoll_event))3479		return -EINVAL;3480 3481	ev = (struct wmi_pspoll_event *) datap;3482 3483	ath6kl_pspoll_event(vif, le16_to_cpu(ev->aid));3484 3485	return 0;3486}3487 3488static int ath6kl_wmi_dtimexpiry_event_rx(struct wmi *wmi, u8 *datap, int len,3489					  struct ath6kl_vif *vif)3490{3491	ath6kl_dtimexpiry_event(vif);3492 3493	return 0;3494}3495 3496int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u8 if_idx, u16 aid,3497			   bool flag)3498{3499	struct sk_buff *skb;3500	struct wmi_ap_set_pvb_cmd *cmd;3501	int ret;3502 3503	skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_ap_set_pvb_cmd));3504	if (!skb)3505		return -ENOMEM;3506 3507	cmd = (struct wmi_ap_set_pvb_cmd *) skb->data;3508	cmd->aid = cpu_to_le16(aid);3509	cmd->rsvd = cpu_to_le16(0);3510	cmd->flag = cpu_to_le32(flag);3511 3512	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_SET_PVB_CMDID,3513				  NO_SYNC_WMIFLAG);3514 3515	return ret;3516}3517 3518int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx,3519				       u8 rx_meta_ver,3520				       bool rx_dot11_hdr, bool defrag_on_host)3521{3522	struct sk_buff *skb;3523	struct wmi_rx_frame_format_cmd *cmd;3524	int ret;3525 3526	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3527	if (!skb)3528		return -ENOMEM;3529 3530	cmd = (struct wmi_rx_frame_format_cmd *) skb->data;3531	cmd->dot11_hdr = rx_dot11_hdr ? 1 : 0;3532	cmd->defrag_on_host = defrag_on_host ? 1 : 0;3533	cmd->meta_ver = rx_meta_ver;3534 3535	/* Delete the local aggr state, on host */3536	ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_RX_FRAME_FORMAT_CMDID,3537				  NO_SYNC_WMIFLAG);3538 3539	return ret;3540}3541 3542int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,3543			     const u8 *ie, u8 ie_len)3544{3545	struct sk_buff *skb;3546	struct wmi_set_appie_cmd *p;3547 3548	skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);3549	if (!skb)3550		return -ENOMEM;3551 3552	ath6kl_dbg(ATH6KL_DBG_WMI,3553		   "set_appie_cmd: mgmt_frm_type=%u ie_len=%u\n",3554		   mgmt_frm_type, ie_len);3555	p = (struct wmi_set_appie_cmd *) skb->data;3556	p->mgmt_frm_type = mgmt_frm_type;3557	p->ie_len = ie_len;3558 3559	if (ie != NULL && ie_len > 0)3560		memcpy(p->ie_info, ie, ie_len);3561 3562	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID,3563				   NO_SYNC_WMIFLAG);3564}3565 3566int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field,3567			  const u8 *ie_info, u8 ie_len)3568{3569	struct sk_buff *skb;3570	struct wmi_set_ie_cmd *p;3571 3572	skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len);3573	if (!skb)3574		return -ENOMEM;3575 3576	ath6kl_dbg(ATH6KL_DBG_WMI, "set_ie_cmd: ie_id=%u ie_ie_field=%u ie_len=%u\n",3577		   ie_id, ie_field, ie_len);3578	p = (struct wmi_set_ie_cmd *) skb->data;3579	p->ie_id = ie_id;3580	p->ie_field = ie_field;3581	p->ie_len = ie_len;3582	if (ie_info && ie_len > 0)3583		memcpy(p->ie_info, ie_info, ie_len);3584 3585	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_IE_CMDID,3586				   NO_SYNC_WMIFLAG);3587}3588 3589int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable)3590{3591	struct sk_buff *skb;3592	struct wmi_disable_11b_rates_cmd *cmd;3593 3594	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3595	if (!skb)3596		return -ENOMEM;3597 3598	ath6kl_dbg(ATH6KL_DBG_WMI, "disable_11b_rates_cmd: disable=%u\n",3599		   disable);3600	cmd = (struct wmi_disable_11b_rates_cmd *) skb->data;3601	cmd->disable = disable ? 1 : 0;3602 3603	return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_DISABLE_11B_RATES_CMDID,3604				   NO_SYNC_WMIFLAG);3605}3606 3607int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)3608{3609	struct sk_buff *skb;3610	struct wmi_remain_on_chnl_cmd *p;3611 3612	skb = ath6kl_wmi_get_new_buf(sizeof(*p));3613	if (!skb)3614		return -ENOMEM;3615 3616	ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl_cmd: freq=%u dur=%u\n",3617		   freq, dur);3618	p = (struct wmi_remain_on_chnl_cmd *) skb->data;3619	p->freq = cpu_to_le32(freq);3620	p->duration = cpu_to_le32(dur);3621	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_REMAIN_ON_CHNL_CMDID,3622				   NO_SYNC_WMIFLAG);3623}3624 3625/* ath6kl_wmi_send_action_cmd is to be deprecated. Use3626 * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P3627 * mgmt operations using station interface.3628 */3629static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id,3630				      u32 freq, u32 wait, const u8 *data,3631				      u16 data_len)3632{3633	struct sk_buff *skb;3634	struct wmi_send_action_cmd *p;3635	u8 *buf;3636 3637	if (wait)3638		return -EINVAL; /* Offload for wait not supported */3639 3640	buf = kmemdup(data, data_len, GFP_KERNEL);3641	if (!buf)3642		return -ENOMEM;3643 3644	skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);3645	if (!skb) {3646		kfree(buf);3647		return -ENOMEM;3648	}3649 3650	kfree(wmi->last_mgmt_tx_frame);3651	wmi->last_mgmt_tx_frame = buf;3652	wmi->last_mgmt_tx_frame_len = data_len;3653 3654	ath6kl_dbg(ATH6KL_DBG_WMI,3655		   "send_action_cmd: id=%u freq=%u wait=%u len=%u\n",3656		   id, freq, wait, data_len);3657	p = (struct wmi_send_action_cmd *) skb->data;3658	p->id = cpu_to_le32(id);3659	p->freq = cpu_to_le32(freq);3660	p->wait = cpu_to_le32(wait);3661	p->len = cpu_to_le16(data_len);3662	memcpy(p->data, data, data_len);3663	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_ACTION_CMDID,3664				   NO_SYNC_WMIFLAG);3665}3666 3667static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id,3668				      u32 freq, u32 wait, const u8 *data,3669				      u16 data_len, u32 no_cck)3670{3671	struct sk_buff *skb;3672	struct wmi_send_mgmt_cmd *p;3673	u8 *buf;3674 3675	if (wait)3676		return -EINVAL; /* Offload for wait not supported */3677 3678	buf = kmemdup(data, data_len, GFP_KERNEL);3679	if (!buf)3680		return -ENOMEM;3681 3682	skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);3683	if (!skb) {3684		kfree(buf);3685		return -ENOMEM;3686	}3687 3688	kfree(wmi->last_mgmt_tx_frame);3689	wmi->last_mgmt_tx_frame = buf;3690	wmi->last_mgmt_tx_frame_len = data_len;3691 3692	ath6kl_dbg(ATH6KL_DBG_WMI,3693		   "send_action_cmd: id=%u freq=%u wait=%u len=%u\n",3694		   id, freq, wait, data_len);3695	p = (struct wmi_send_mgmt_cmd *) skb->data;3696	p->id = cpu_to_le32(id);3697	p->freq = cpu_to_le32(freq);3698	p->wait = cpu_to_le32(wait);3699	p->no_cck = cpu_to_le32(no_cck);3700	p->len = cpu_to_le16(data_len);3701	memcpy(p->data, data, data_len);3702	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_MGMT_CMDID,3703				   NO_SYNC_WMIFLAG);3704}3705 3706int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,3707				u32 wait, const u8 *data, u16 data_len,3708				u32 no_cck)3709{3710	int status;3711	struct ath6kl *ar = wmi->parent_dev;3712 3713	if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,3714		     ar->fw_capabilities)) {3715		/*3716		 * If capable of doing P2P mgmt operations using3717		 * station interface, send additional information like3718		 * supported rates to advertise and xmit rates for3719		 * probe requests3720		 */3721		status = __ath6kl_wmi_send_mgmt_cmd(ar->wmi, if_idx, id, freq,3722						    wait, data, data_len,3723						    no_cck);3724	} else {3725		status = ath6kl_wmi_send_action_cmd(ar->wmi, if_idx, id, freq,3726						    wait, data, data_len);3727	}3728 3729	return status;3730}3731 3732int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,3733				       const u8 *dst, const u8 *data,3734				       u16 data_len)3735{3736	struct sk_buff *skb;3737	struct wmi_p2p_probe_response_cmd *p;3738	size_t cmd_len = sizeof(*p) + data_len;3739 3740	if (data_len == 0)3741		cmd_len++; /* work around target minimum length requirement */3742 3743	skb = ath6kl_wmi_get_new_buf(cmd_len);3744	if (!skb)3745		return -ENOMEM;3746 3747	ath6kl_dbg(ATH6KL_DBG_WMI,3748		   "send_probe_response_cmd: freq=%u dst=%pM len=%u\n",3749		   freq, dst, data_len);3750	p = (struct wmi_p2p_probe_response_cmd *) skb->data;3751	p->freq = cpu_to_le32(freq);3752	memcpy(p->destination_addr, dst, ETH_ALEN);3753	p->len = cpu_to_le16(data_len);3754	memcpy(p->data, data, data_len);3755	return ath6kl_wmi_cmd_send(wmi, if_idx, skb,3756				   WMI_SEND_PROBE_RESPONSE_CMDID,3757				   NO_SYNC_WMIFLAG);3758}3759 3760int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, u8 if_idx, bool enable)3761{3762	struct sk_buff *skb;3763	struct wmi_probe_req_report_cmd *p;3764 3765	skb = ath6kl_wmi_get_new_buf(sizeof(*p));3766	if (!skb)3767		return -ENOMEM;3768 3769	ath6kl_dbg(ATH6KL_DBG_WMI, "probe_report_req_cmd: enable=%u\n",3770		   enable);3771	p = (struct wmi_probe_req_report_cmd *) skb->data;3772	p->enable = enable ? 1 : 0;3773	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_PROBE_REQ_REPORT_CMDID,3774				   NO_SYNC_WMIFLAG);3775}3776 3777int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u8 if_idx, u32 info_req_flags)3778{3779	struct sk_buff *skb;3780	struct wmi_get_p2p_info *p;3781 3782	skb = ath6kl_wmi_get_new_buf(sizeof(*p));3783	if (!skb)3784		return -ENOMEM;3785 3786	ath6kl_dbg(ATH6KL_DBG_WMI, "info_req_cmd: flags=%x\n",3787		   info_req_flags);3788	p = (struct wmi_get_p2p_info *) skb->data;3789	p->info_req_flags = cpu_to_le32(info_req_flags);3790	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_GET_P2P_INFO_CMDID,3791				   NO_SYNC_WMIFLAG);3792}3793 3794int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx)3795{3796	ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl_cmd\n");3797	return ath6kl_wmi_simple_cmd(wmi, if_idx,3798				     WMI_CANCEL_REMAIN_ON_CHNL_CMDID);3799}3800 3801int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout)3802{3803	struct sk_buff *skb;3804	struct wmi_set_inact_period_cmd *cmd;3805 3806	skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));3807	if (!skb)3808		return -ENOMEM;3809 3810	cmd = (struct wmi_set_inact_period_cmd *) skb->data;3811	cmd->inact_period = cpu_to_le32(inact_timeout);3812	cmd->num_null_func = 0;3813 3814	return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_AP_CONN_INACT_CMDID,3815				   NO_SYNC_WMIFLAG);3816}3817 3818static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap,3819					       int len)3820{3821	struct wmix_hb_challenge_resp_cmd *cmd;3822 3823	if (len < sizeof(struct wmix_hb_challenge_resp_cmd))3824		return;3825 3826	cmd = (struct wmix_hb_challenge_resp_cmd *) datap;3827	ath6kl_recovery_hb_event(wmi->parent_dev,3828				 le32_to_cpu(cmd->cookie));3829}3830 3831static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)3832{3833	struct wmix_cmd_hdr *cmd;3834	u32 len;3835	u16 id;3836	u8 *datap;3837	int ret = 0;3838 3839	if (skb->len < sizeof(struct wmix_cmd_hdr)) {3840		ath6kl_err("bad packet 1\n");3841		return -EINVAL;3842	}3843 3844	cmd = (struct wmix_cmd_hdr *) skb->data;3845	id = le32_to_cpu(cmd->cmd_id);3846 3847	skb_pull(skb, sizeof(struct wmix_cmd_hdr));3848 3849	datap = skb->data;3850	len = skb->len;3851 3852	switch (id) {3853	case WMIX_HB_CHALLENGE_RESP_EVENTID:3854		ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n");3855		ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len);3856		break;3857	case WMIX_DBGLOG_EVENTID:3858		ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len);3859		ath6kl_debug_fwlog_event(wmi->parent_dev, datap, len);3860		break;3861	default:3862		ath6kl_warn("unknown cmd id 0x%x\n", id);3863		ret = -EINVAL;3864		break;3865	}3866 3867	return ret;3868}3869 3870static int ath6kl_wmi_roam_tbl_event_rx(struct wmi *wmi, u8 *datap, int len)3871{3872	return ath6kl_debug_roam_tbl_event(wmi->parent_dev, datap, len);3873}3874 3875/* Process interface specific wmi events, caller would free the datap */3876static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,3877					u8 *datap, u32 len)3878{3879	struct ath6kl_vif *vif;3880 3881	vif = ath6kl_get_vif_by_index(wmi->parent_dev, if_idx);3882	if (!vif) {3883		ath6kl_dbg(ATH6KL_DBG_WMI,3884			   "Wmi event for unavailable vif, vif_index:%d\n",3885			    if_idx);3886		return -EINVAL;3887	}3888 3889	switch (cmd_id) {3890	case WMI_CONNECT_EVENTID:3891		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n");3892		return ath6kl_wmi_connect_event_rx(wmi, datap, len, vif);3893	case WMI_DISCONNECT_EVENTID:3894		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n");3895		return ath6kl_wmi_disconnect_event_rx(wmi, datap, len, vif);3896	case WMI_TKIP_MICERR_EVENTID:3897		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n");3898		return ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len, vif);3899	case WMI_BSSINFO_EVENTID:3900		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n");3901		return ath6kl_wmi_bssinfo_event_rx(wmi, datap, len, vif);3902	case WMI_NEIGHBOR_REPORT_EVENTID:3903		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n");3904		return ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len,3905							   vif);3906	case WMI_SCAN_COMPLETE_EVENTID:3907		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n");3908		return ath6kl_wmi_scan_complete_rx(wmi, datap, len, vif);3909	case WMI_REPORT_STATISTICS_EVENTID:3910		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n");3911		return ath6kl_wmi_stats_event_rx(wmi, datap, len, vif);3912	case WMI_CAC_EVENTID:3913		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n");3914		return ath6kl_wmi_cac_event_rx(wmi, datap, len, vif);3915	case WMI_PSPOLL_EVENTID:3916		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n");3917		return ath6kl_wmi_pspoll_event_rx(wmi, datap, len, vif);3918	case WMI_DTIMEXPIRY_EVENTID:3919		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n");3920		return ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len, vif);3921	case WMI_ADDBA_REQ_EVENTID:3922		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n");3923		return ath6kl_wmi_addba_req_event_rx(wmi, datap, len, vif);3924	case WMI_DELBA_REQ_EVENTID:3925		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n");3926		return ath6kl_wmi_delba_req_event_rx(wmi, datap, len, vif);3927	case WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID:3928		ath6kl_dbg(ATH6KL_DBG_WMI,3929			   "WMI_SET_HOST_SLEEP_MODE_CMD_PROCESSED_EVENTID");3930		return ath6kl_wmi_host_sleep_mode_cmd_prcd_evt_rx(wmi, vif);3931	case WMI_REMAIN_ON_CHNL_EVENTID:3932		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n");3933		return ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len, vif);3934	case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID:3935		ath6kl_dbg(ATH6KL_DBG_WMI,3936			   "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n");3937		return ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap,3938								 len, vif);3939	case WMI_TX_STATUS_EVENTID:3940		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n");3941		return ath6kl_wmi_tx_status_event_rx(wmi, datap, len, vif);3942	case WMI_RX_PROBE_REQ_EVENTID:3943		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n");3944		return ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len, vif);3945	case WMI_RX_ACTION_EVENTID:3946		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");3947		return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);3948	case WMI_TXE_NOTIFY_EVENTID:3949		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n");3950		return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif);3951	default:3952		ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);3953		return -EINVAL;3954	}3955 3956	return 0;3957}3958 3959static int ath6kl_wmi_proc_events(struct wmi *wmi, struct sk_buff *skb)3960{3961	struct wmi_cmd_hdr *cmd;3962	int ret = 0;3963	u32 len;3964	u16 id;3965	u8 if_idx;3966	u8 *datap;3967 3968	cmd = (struct wmi_cmd_hdr *) skb->data;3969	id = le16_to_cpu(cmd->cmd_id);3970	if_idx = le16_to_cpu(cmd->info1) & WMI_CMD_HDR_IF_ID_MASK;3971 3972	skb_pull(skb, sizeof(struct wmi_cmd_hdr));3973	datap = skb->data;3974	len = skb->len;3975 3976	ath6kl_dbg(ATH6KL_DBG_WMI, "wmi rx id %d len %d\n", id, len);3977	ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ",3978			datap, len);3979 3980	switch (id) {3981	case WMI_GET_BITRATE_CMDID:3982		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n");3983		ret = ath6kl_wmi_bitrate_reply_rx(wmi, datap, len);3984		break;3985	case WMI_GET_CHANNEL_LIST_CMDID:3986		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_CHANNEL_LIST_CMDID\n");3987		ret = ath6kl_wmi_ch_list_reply_rx(wmi, datap, len);3988		break;3989	case WMI_GET_TX_PWR_CMDID:3990		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_TX_PWR_CMDID\n");3991		ret = ath6kl_wmi_tx_pwr_reply_rx(wmi, datap, len);3992		break;3993	case WMI_READY_EVENTID:3994		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n");3995		ret = ath6kl_wmi_ready_event_rx(wmi, datap, len);3996		break;3997	case WMI_PEER_NODE_EVENTID:3998		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n");3999		ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len);4000		break;4001	case WMI_REGDOMAIN_EVENTID:4002		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n");4003		ath6kl_wmi_regdomain_event(wmi, datap, len);4004		break;4005	case WMI_PSTREAM_TIMEOUT_EVENTID:4006		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n");4007		ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len);4008		break;4009	case WMI_CMDERROR_EVENTID:4010		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n");4011		ret = ath6kl_wmi_error_event_rx(wmi, datap, len);4012		break;4013	case WMI_RSSI_THRESHOLD_EVENTID:4014		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n");4015		ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len);4016		break;4017	case WMI_ERROR_REPORT_EVENTID:4018		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ERROR_REPORT_EVENTID\n");4019		break;4020	case WMI_OPT_RX_FRAME_EVENTID:4021		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n");4022		/* this event has been deprecated */4023		break;4024	case WMI_REPORT_ROAM_TBL_EVENTID:4025		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n");4026		ret = ath6kl_wmi_roam_tbl_event_rx(wmi, datap, len);4027		break;4028	case WMI_EXTENSION_EVENTID:4029		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n");4030		ret = ath6kl_wmi_control_rx_xtnd(wmi, skb);4031		break;4032	case WMI_CHANNEL_CHANGE_EVENTID:4033		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n");4034		break;4035	case WMI_REPORT_ROAM_DATA_EVENTID:4036		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n");4037		break;4038	case WMI_TEST_EVENTID:4039		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n");4040		ret = ath6kl_wmi_test_rx(wmi, datap, len);4041		break;4042	case WMI_GET_FIXRATES_CMDID:4043		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n");4044		ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len);4045		break;4046	case WMI_TX_RETRY_ERR_EVENTID:4047		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_RETRY_ERR_EVENTID\n");4048		break;4049	case WMI_SNR_THRESHOLD_EVENTID:4050		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SNR_THRESHOLD_EVENTID\n");4051		ret = ath6kl_wmi_snr_threshold_event_rx(wmi, datap, len);4052		break;4053	case WMI_LQ_THRESHOLD_EVENTID:4054		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_LQ_THRESHOLD_EVENTID\n");4055		break;4056	case WMI_APLIST_EVENTID:4057		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_APLIST_EVENTID\n");4058		ret = ath6kl_wmi_aplist_event_rx(wmi, datap, len);4059		break;4060	case WMI_GET_KEEPALIVE_CMDID:4061		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_KEEPALIVE_CMDID\n");4062		ret = ath6kl_wmi_keepalive_reply_rx(wmi, datap, len);4063		break;4064	case WMI_GET_WOW_LIST_EVENTID:4065		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_WOW_LIST_EVENTID\n");4066		break;4067	case WMI_GET_PMKID_LIST_EVENTID:4068		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n");4069		ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len);4070		break;4071	case WMI_SET_PARAMS_REPLY_EVENTID:4072		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n");4073		break;4074	case WMI_ADDBA_RESP_EVENTID:4075		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n");4076		break;4077	case WMI_REPORT_BTCOEX_CONFIG_EVENTID:4078		ath6kl_dbg(ATH6KL_DBG_WMI,4079			   "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n");4080		break;4081	case WMI_REPORT_BTCOEX_STATS_EVENTID:4082		ath6kl_dbg(ATH6KL_DBG_WMI,4083			   "WMI_REPORT_BTCOEX_STATS_EVENTID\n");4084		break;4085	case WMI_TX_COMPLETE_EVENTID:4086		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n");4087		ret = ath6kl_wmi_tx_complete_event_rx(datap, len);4088		break;4089	case WMI_P2P_CAPABILITIES_EVENTID:4090		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n");4091		ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len);4092		break;4093	case WMI_P2P_INFO_EVENTID:4094		ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n");4095		ret = ath6kl_wmi_p2p_info_event_rx(datap, len);4096		break;4097	default:4098		/* may be the event is interface specific */4099		ret = ath6kl_wmi_proc_events_vif(wmi, if_idx, id, datap, len);4100		break;4101	}4102 4103	dev_kfree_skb(skb);4104	return ret;4105}4106 4107/* Control Path */4108int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)4109{4110	if (WARN_ON(skb == NULL))4111		return -EINVAL;4112 4113	if (skb->len < sizeof(struct wmi_cmd_hdr)) {4114		ath6kl_err("bad packet 1\n");4115		dev_kfree_skb(skb);4116		return -EINVAL;4117	}4118 4119	trace_ath6kl_wmi_event(skb->data, skb->len);4120 4121	return ath6kl_wmi_proc_events(wmi, skb);4122}4123 4124void ath6kl_wmi_reset(struct wmi *wmi)4125{4126	spin_lock_bh(&wmi->lock);4127 4128	wmi->fat_pipe_exist = 0;4129	memset(wmi->stream_exist_for_ac, 0, sizeof(wmi->stream_exist_for_ac));4130 4131	spin_unlock_bh(&wmi->lock);4132}4133 4134void *ath6kl_wmi_init(struct ath6kl *dev)4135{4136	struct wmi *wmi;4137 4138	wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL);4139	if (!wmi)4140		return NULL;4141 4142	spin_lock_init(&wmi->lock);4143 4144	wmi->parent_dev = dev;4145 4146	wmi->pwr_mode = REC_POWER;4147 4148	ath6kl_wmi_reset(wmi);4149 4150	return wmi;4151}4152 4153void ath6kl_wmi_shutdown(struct wmi *wmi)4154{4155	if (!wmi)4156		return;4157 4158	kfree(wmi->last_mgmt_tx_frame);4159	kfree(wmi);4160}4161