xref: /linux/drivers/net/wireless/marvell/mwifiex/util.c (revision e5c86679d5e864947a52fb31e45a425dea3e7fa9)
1 /*
2  * Marvell Wireless LAN device driver: utility functions
3  *
4  * Copyright (C) 2011-2014, Marvell International Ltd.
5  *
6  * This software file (the "File") is distributed by Marvell International
7  * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8  * (the "License").  You may use, redistribute and/or modify this File in
9  * accordance with the terms and conditions of the License, a copy of which
10  * is available by writing to the Free Software Foundation, Inc.,
11  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13  *
14  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
17  * this warranty disclaimer.
18  */
19 
20 #include "decl.h"
21 #include "ioctl.h"
22 #include "util.h"
23 #include "fw.h"
24 #include "main.h"
25 #include "wmm.h"
26 #include "11n.h"
27 
28 static struct mwifiex_debug_data items[] = {
29 	{"debug_mask", item_size(debug_mask),
30 	 item_addr(debug_mask), 1},
31 	{"int_counter", item_size(int_counter),
32 	 item_addr(int_counter), 1},
33 	{"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
34 	 item_addr(packets_out[WMM_AC_VO]), 1},
35 	{"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
36 	 item_addr(packets_out[WMM_AC_VI]), 1},
37 	{"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
38 	 item_addr(packets_out[WMM_AC_BE]), 1},
39 	{"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
40 	 item_addr(packets_out[WMM_AC_BK]), 1},
41 	{"tx_buf_size", item_size(tx_buf_size),
42 	 item_addr(tx_buf_size), 1},
43 	{"curr_tx_buf_size", item_size(curr_tx_buf_size),
44 	 item_addr(curr_tx_buf_size), 1},
45 	{"ps_mode", item_size(ps_mode),
46 	 item_addr(ps_mode), 1},
47 	{"ps_state", item_size(ps_state),
48 	 item_addr(ps_state), 1},
49 	{"is_deep_sleep", item_size(is_deep_sleep),
50 	 item_addr(is_deep_sleep), 1},
51 	{"wakeup_dev_req", item_size(pm_wakeup_card_req),
52 	 item_addr(pm_wakeup_card_req), 1},
53 	{"wakeup_tries", item_size(pm_wakeup_fw_try),
54 	 item_addr(pm_wakeup_fw_try), 1},
55 	{"hs_configured", item_size(is_hs_configured),
56 	 item_addr(is_hs_configured), 1},
57 	{"hs_activated", item_size(hs_activated),
58 	 item_addr(hs_activated), 1},
59 	{"num_tx_timeout", item_size(num_tx_timeout),
60 	 item_addr(num_tx_timeout), 1},
61 	{"is_cmd_timedout", item_size(is_cmd_timedout),
62 	 item_addr(is_cmd_timedout), 1},
63 	{"timeout_cmd_id", item_size(timeout_cmd_id),
64 	 item_addr(timeout_cmd_id), 1},
65 	{"timeout_cmd_act", item_size(timeout_cmd_act),
66 	 item_addr(timeout_cmd_act), 1},
67 	{"last_cmd_id", item_size(last_cmd_id),
68 	 item_addr(last_cmd_id), DBG_CMD_NUM},
69 	{"last_cmd_act", item_size(last_cmd_act),
70 	 item_addr(last_cmd_act), DBG_CMD_NUM},
71 	{"last_cmd_index", item_size(last_cmd_index),
72 	 item_addr(last_cmd_index), 1},
73 	{"last_cmd_resp_id", item_size(last_cmd_resp_id),
74 	 item_addr(last_cmd_resp_id), DBG_CMD_NUM},
75 	{"last_cmd_resp_index", item_size(last_cmd_resp_index),
76 	 item_addr(last_cmd_resp_index), 1},
77 	{"last_event", item_size(last_event),
78 	 item_addr(last_event), DBG_CMD_NUM},
79 	{"last_event_index", item_size(last_event_index),
80 	 item_addr(last_event_index), 1},
81 	{"last_mp_wr_bitmap", item_size(last_mp_wr_bitmap),
82 	 item_addr(last_mp_wr_bitmap), MWIFIEX_DBG_SDIO_MP_NUM},
83 	{"last_mp_wr_ports", item_size(last_mp_wr_ports),
84 	 item_addr(last_mp_wr_ports), MWIFIEX_DBG_SDIO_MP_NUM},
85 	{"last_mp_wr_len", item_size(last_mp_wr_len),
86 	 item_addr(last_mp_wr_len), MWIFIEX_DBG_SDIO_MP_NUM},
87 	{"last_mp_curr_wr_port", item_size(last_mp_curr_wr_port),
88 	 item_addr(last_mp_curr_wr_port), MWIFIEX_DBG_SDIO_MP_NUM},
89 	{"last_sdio_mp_index", item_size(last_sdio_mp_index),
90 	 item_addr(last_sdio_mp_index), 1},
91 	{"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
92 	 item_addr(num_cmd_host_to_card_failure), 1},
93 	{"num_cmd_sleep_cfm_fail",
94 	 item_size(num_cmd_sleep_cfm_host_to_card_failure),
95 	 item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
96 	{"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
97 	 item_addr(num_tx_host_to_card_failure), 1},
98 	{"num_evt_deauth", item_size(num_event_deauth),
99 	 item_addr(num_event_deauth), 1},
100 	{"num_evt_disassoc", item_size(num_event_disassoc),
101 	 item_addr(num_event_disassoc), 1},
102 	{"num_evt_link_lost", item_size(num_event_link_lost),
103 	 item_addr(num_event_link_lost), 1},
104 	{"num_cmd_deauth", item_size(num_cmd_deauth),
105 	 item_addr(num_cmd_deauth), 1},
106 	{"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
107 	 item_addr(num_cmd_assoc_success), 1},
108 	{"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
109 	 item_addr(num_cmd_assoc_failure), 1},
110 	{"cmd_sent", item_size(cmd_sent),
111 	 item_addr(cmd_sent), 1},
112 	{"data_sent", item_size(data_sent),
113 	 item_addr(data_sent), 1},
114 	{"cmd_resp_received", item_size(cmd_resp_received),
115 	 item_addr(cmd_resp_received), 1},
116 	{"event_received", item_size(event_received),
117 	 item_addr(event_received), 1},
118 
119 	/* variables defined in struct mwifiex_adapter */
120 	{"cmd_pending", adapter_item_size(cmd_pending),
121 	 adapter_item_addr(cmd_pending), 1},
122 	{"tx_pending", adapter_item_size(tx_pending),
123 	 adapter_item_addr(tx_pending), 1},
124 	{"rx_pending", adapter_item_size(rx_pending),
125 	 adapter_item_addr(rx_pending), 1},
126 };
127 
128 static int num_of_items = ARRAY_SIZE(items);
129 
130 /*
131  * Firmware initialization complete callback handler.
132  *
133  * This function wakes up the function waiting on the init
134  * wait queue for the firmware initialization to complete.
135  */
136 int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter)
137 {
138 
139 	if (adapter->hw_status == MWIFIEX_HW_STATUS_READY)
140 		if (adapter->if_ops.init_fw_port)
141 			adapter->if_ops.init_fw_port(adapter);
142 
143 	adapter->init_wait_q_woken = true;
144 	wake_up_interruptible(&adapter->init_wait_q);
145 	return 0;
146 }
147 
148 /*
149  * This function sends init/shutdown command
150  * to firmware.
151  */
152 int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
153 			     u32 func_init_shutdown)
154 {
155 	u16 cmd;
156 
157 	if (func_init_shutdown == MWIFIEX_FUNC_INIT) {
158 		cmd = HostCmd_CMD_FUNC_INIT;
159 	} else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
160 		cmd = HostCmd_CMD_FUNC_SHUTDOWN;
161 	} else {
162 		mwifiex_dbg(priv->adapter, ERROR,
163 			    "unsupported parameter\n");
164 		return -1;
165 	}
166 
167 	return mwifiex_send_cmd(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL, true);
168 }
169 EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw);
170 
171 /*
172  * IOCTL request handler to set/get debug information.
173  *
174  * This function collates/sets the information from/to different driver
175  * structures.
176  */
177 int mwifiex_get_debug_info(struct mwifiex_private *priv,
178 			   struct mwifiex_debug_info *info)
179 {
180 	struct mwifiex_adapter *adapter = priv->adapter;
181 
182 	if (info) {
183 		info->debug_mask = adapter->debug_mask;
184 		memcpy(info->packets_out,
185 		       priv->wmm.packets_out,
186 		       sizeof(priv->wmm.packets_out));
187 		info->curr_tx_buf_size = (u32) adapter->curr_tx_buf_size;
188 		info->tx_buf_size = (u32) adapter->tx_buf_size;
189 		info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(priv,
190 							      info->rx_tbl);
191 		info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(priv,
192 								info->tx_tbl);
193 		info->tdls_peer_num = mwifiex_get_tdls_list(priv,
194 							    info->tdls_list);
195 		info->ps_mode = adapter->ps_mode;
196 		info->ps_state = adapter->ps_state;
197 		info->is_deep_sleep = adapter->is_deep_sleep;
198 		info->pm_wakeup_card_req = adapter->pm_wakeup_card_req;
199 		info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
200 		info->is_hs_configured = adapter->is_hs_configured;
201 		info->hs_activated = adapter->hs_activated;
202 		info->is_cmd_timedout = adapter->is_cmd_timedout;
203 		info->num_cmd_host_to_card_failure
204 				= adapter->dbg.num_cmd_host_to_card_failure;
205 		info->num_cmd_sleep_cfm_host_to_card_failure
206 			= adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
207 		info->num_tx_host_to_card_failure
208 				= adapter->dbg.num_tx_host_to_card_failure;
209 		info->num_event_deauth = adapter->dbg.num_event_deauth;
210 		info->num_event_disassoc = adapter->dbg.num_event_disassoc;
211 		info->num_event_link_lost = adapter->dbg.num_event_link_lost;
212 		info->num_cmd_deauth = adapter->dbg.num_cmd_deauth;
213 		info->num_cmd_assoc_success =
214 					adapter->dbg.num_cmd_assoc_success;
215 		info->num_cmd_assoc_failure =
216 					adapter->dbg.num_cmd_assoc_failure;
217 		info->num_tx_timeout = adapter->dbg.num_tx_timeout;
218 		info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
219 		info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
220 		memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
221 		       sizeof(adapter->dbg.last_cmd_id));
222 		memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act,
223 		       sizeof(adapter->dbg.last_cmd_act));
224 		info->last_cmd_index = adapter->dbg.last_cmd_index;
225 		memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id,
226 		       sizeof(adapter->dbg.last_cmd_resp_id));
227 		info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index;
228 		memcpy(info->last_event, adapter->dbg.last_event,
229 		       sizeof(adapter->dbg.last_event));
230 		info->last_event_index = adapter->dbg.last_event_index;
231 		memcpy(info->last_mp_wr_bitmap, adapter->dbg.last_mp_wr_bitmap,
232 		       sizeof(adapter->dbg.last_mp_wr_bitmap));
233 		memcpy(info->last_mp_wr_ports, adapter->dbg.last_mp_wr_ports,
234 		       sizeof(adapter->dbg.last_mp_wr_ports));
235 		memcpy(info->last_mp_curr_wr_port,
236 		       adapter->dbg.last_mp_curr_wr_port,
237 		       sizeof(adapter->dbg.last_mp_curr_wr_port));
238 		memcpy(info->last_mp_wr_len, adapter->dbg.last_mp_wr_len,
239 		       sizeof(adapter->dbg.last_mp_wr_len));
240 		info->last_sdio_mp_index = adapter->dbg.last_sdio_mp_index;
241 		info->data_sent = adapter->data_sent;
242 		info->cmd_sent = adapter->cmd_sent;
243 		info->cmd_resp_received = adapter->cmd_resp_received;
244 	}
245 
246 	return 0;
247 }
248 
249 int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf,
250 				 struct mwifiex_debug_info *info)
251 {
252 	char *p = buf;
253 	struct mwifiex_debug_data *d = &items[0];
254 	size_t size, addr;
255 	long val;
256 	int i, j;
257 
258 	if (!info)
259 		return 0;
260 
261 	for (i = 0; i < num_of_items; i++) {
262 		p += sprintf(p, "%s=", d[i].name);
263 
264 		size = d[i].size / d[i].num;
265 
266 		if (i < (num_of_items - 3))
267 			addr = d[i].addr + (size_t)info;
268 		else /* The last 3 items are struct mwifiex_adapter variables */
269 			addr = d[i].addr + (size_t)priv->adapter;
270 
271 		for (j = 0; j < d[i].num; j++) {
272 			switch (size) {
273 			case 1:
274 				val = *((u8 *)addr);
275 				break;
276 			case 2:
277 				val = *((u16 *)addr);
278 				break;
279 			case 4:
280 				val = *((u32 *)addr);
281 				break;
282 			case 8:
283 				val = *((long long *)addr);
284 				break;
285 			default:
286 				val = -1;
287 				break;
288 			}
289 
290 			p += sprintf(p, "%#lx ", val);
291 			addr += size;
292 		}
293 
294 		p += sprintf(p, "\n");
295 	}
296 
297 	if (info->tx_tbl_num) {
298 		p += sprintf(p, "Tx BA stream table:\n");
299 		for (i = 0; i < info->tx_tbl_num; i++)
300 			p += sprintf(p, "tid = %d, ra = %pM\n",
301 				     info->tx_tbl[i].tid, info->tx_tbl[i].ra);
302 	}
303 
304 	if (info->rx_tbl_num) {
305 		p += sprintf(p, "Rx reorder table:\n");
306 		for (i = 0; i < info->rx_tbl_num; i++) {
307 			p += sprintf(p, "tid = %d, ta = %pM, ",
308 				     info->rx_tbl[i].tid,
309 				     info->rx_tbl[i].ta);
310 			p += sprintf(p, "start_win = %d, ",
311 				     info->rx_tbl[i].start_win);
312 			p += sprintf(p, "win_size = %d, buffer: ",
313 				     info->rx_tbl[i].win_size);
314 
315 			for (j = 0; j < info->rx_tbl[i].win_size; j++)
316 				p += sprintf(p, "%c ",
317 					     info->rx_tbl[i].buffer[j] ?
318 					     '1' : '0');
319 
320 			p += sprintf(p, "\n");
321 		}
322 	}
323 
324 	if (info->tdls_peer_num) {
325 		p += sprintf(p, "TDLS peer table:\n");
326 		for (i = 0; i < info->tdls_peer_num; i++) {
327 			p += sprintf(p, "peer = %pM",
328 				     info->tdls_list[i].peer_addr);
329 			p += sprintf(p, "\n");
330 		}
331 	}
332 
333 	return p - buf;
334 }
335 
336 static int
337 mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
338 			  struct rxpd *rx_pd)
339 {
340 	u16 stype;
341 	u8 category, action_code, *addr2;
342 	struct ieee80211_hdr *ieee_hdr = (void *)payload;
343 
344 	stype = (le16_to_cpu(ieee_hdr->frame_control) & IEEE80211_FCTL_STYPE);
345 
346 	switch (stype) {
347 	case IEEE80211_STYPE_ACTION:
348 		category = *(payload + sizeof(struct ieee80211_hdr));
349 		switch (category) {
350 		case WLAN_CATEGORY_PUBLIC:
351 			action_code = *(payload + sizeof(struct ieee80211_hdr)
352 					+ 1);
353 			if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
354 				addr2 = ieee_hdr->addr2;
355 				mwifiex_dbg(priv->adapter, INFO,
356 					    "TDLS discovery response %pM nf=%d, snr=%d\n",
357 					    addr2, rx_pd->nf, rx_pd->snr);
358 				mwifiex_auto_tdls_update_peer_signal(priv,
359 								     addr2,
360 								     rx_pd->snr,
361 								     rx_pd->nf);
362 			}
363 			break;
364 		case WLAN_CATEGORY_BACK:
365 			/*we dont indicate BACK action frames to cfg80211*/
366 			mwifiex_dbg(priv->adapter, INFO,
367 				    "drop BACK action frames");
368 			return -1;
369 		default:
370 			mwifiex_dbg(priv->adapter, INFO,
371 				    "unknown public action frame category %d\n",
372 				    category);
373 		}
374 		break;
375 	default:
376 		mwifiex_dbg(priv->adapter, INFO,
377 		    "unknown mgmt frame subtype %#x\n", stype);
378 		return 0;
379 	}
380 
381 	return 0;
382 }
383 /*
384  * This function processes the received management packet and send it
385  * to the kernel.
386  */
387 int
388 mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
389 			    struct sk_buff *skb)
390 {
391 	struct rxpd *rx_pd;
392 	u16 pkt_len;
393 	struct ieee80211_hdr *ieee_hdr;
394 
395 	if (!skb)
396 		return -1;
397 
398 	if (!priv->mgmt_frame_mask ||
399 	    priv->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) {
400 		mwifiex_dbg(priv->adapter, ERROR,
401 			    "do not receive mgmt frames on uninitialized intf");
402 		return -1;
403 	}
404 
405 	rx_pd = (struct rxpd *)skb->data;
406 
407 	skb_pull(skb, le16_to_cpu(rx_pd->rx_pkt_offset));
408 	skb_pull(skb, sizeof(pkt_len));
409 
410 	pkt_len = le16_to_cpu(rx_pd->rx_pkt_length);
411 
412 	ieee_hdr = (void *)skb->data;
413 	if (ieee80211_is_mgmt(ieee_hdr->frame_control)) {
414 		if (mwifiex_parse_mgmt_packet(priv, (u8 *)ieee_hdr,
415 					      pkt_len, rx_pd))
416 			return -1;
417 	}
418 	/* Remove address4 */
419 	memmove(skb->data + sizeof(struct ieee80211_hdr_3addr),
420 		skb->data + sizeof(struct ieee80211_hdr),
421 		pkt_len - sizeof(struct ieee80211_hdr));
422 
423 	pkt_len -= ETH_ALEN + sizeof(pkt_len);
424 	rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);
425 
426 	cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq,
427 			 CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
428 			 0);
429 
430 	return 0;
431 }
432 
433 /*
434  * This function processes the received packet before sending it to the
435  * kernel.
436  *
437  * It extracts the SKB from the received buffer and sends it to kernel.
438  * In case the received buffer does not contain the data in SKB format,
439  * the function creates a blank SKB, fills it with the data from the
440  * received buffer and then sends this new SKB to the kernel.
441  */
442 int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
443 {
444 	struct mwifiex_sta_node *src_node;
445 	struct ethhdr *p_ethhdr;
446 
447 	if (!skb)
448 		return -1;
449 
450 	priv->stats.rx_bytes += skb->len;
451 	priv->stats.rx_packets++;
452 
453 	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
454 		p_ethhdr = (void *)skb->data;
455 		src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source);
456 		if (src_node) {
457 			src_node->stats.last_rx = jiffies;
458 			src_node->stats.rx_bytes += skb->len;
459 			src_node->stats.rx_packets++;
460 		}
461 	}
462 
463 	skb->dev = priv->netdev;
464 	skb->protocol = eth_type_trans(skb, priv->netdev);
465 	skb->ip_summed = CHECKSUM_NONE;
466 
467 	/* This is required only in case of 11n and USB/PCIE as we alloc
468 	 * a buffer of 4K only if its 11N (to be able to receive 4K
469 	 * AMSDU packets). In case of SD we allocate buffers based
470 	 * on the size of packet and hence this is not needed.
471 	 *
472 	 * Modifying the truesize here as our allocation for each
473 	 * skb is 4K but we only receive 2K packets and this cause
474 	 * the kernel to start dropping packets in case where
475 	 * application has allocated buffer based on 2K size i.e.
476 	 * if there a 64K packet received (in IP fragments and
477 	 * application allocates 64K to receive this packet but
478 	 * this packet would almost double up because we allocate
479 	 * each 1.5K fragment in 4K and pass it up. As soon as the
480 	 * 64K limit hits kernel will start to drop rest of the
481 	 * fragments. Currently we fail the Filesndl-ht.scr script
482 	 * for UDP, hence this fix
483 	 */
484 	if ((priv->adapter->iface_type == MWIFIEX_USB ||
485 	     priv->adapter->iface_type == MWIFIEX_PCIE) &&
486 	    (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))
487 		skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);
488 
489 	if (in_interrupt())
490 		netif_rx(skb);
491 	else
492 		netif_rx_ni(skb);
493 
494 	return 0;
495 }
496 
497 /*
498  * IOCTL completion callback handler.
499  *
500  * This function is called when a pending IOCTL is completed.
501  *
502  * If work queue support is enabled, the function wakes up the
503  * corresponding waiting function. Otherwise, it processes the
504  * IOCTL response and frees the response buffer.
505  */
506 int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
507 			 struct cmd_ctrl_node *cmd_node)
508 {
509 	WARN_ON(!cmd_node->wait_q_enabled);
510 	mwifiex_dbg(adapter, CMD, "cmd completed: status=%d\n",
511 		    adapter->cmd_wait_q.status);
512 
513 	*cmd_node->condition = true;
514 	wake_up_interruptible(&adapter->cmd_wait_q.wait);
515 
516 	return 0;
517 }
518 
519 /* This function will return the pointer to station entry in station list
520  * table which matches specified mac address.
521  * This function should be called after acquiring RA list spinlock.
522  * NULL is returned if station entry is not found in associated STA list.
523  */
524 struct mwifiex_sta_node *
525 mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac)
526 {
527 	struct mwifiex_sta_node *node;
528 
529 	if (!mac)
530 		return NULL;
531 
532 	list_for_each_entry(node, &priv->sta_list, list) {
533 		if (!memcmp(node->mac_addr, mac, ETH_ALEN))
534 			return node;
535 	}
536 
537 	return NULL;
538 }
539 
540 static struct mwifiex_sta_node *
541 mwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status)
542 {
543 	struct mwifiex_sta_node *node;
544 
545 	list_for_each_entry(node, &priv->sta_list, list) {
546 		if (node->tdls_status == status)
547 			return node;
548 	}
549 
550 	return NULL;
551 }
552 
553 /* If tdls channel switching is on-going, tx data traffic should be
554  * blocked until the switching stage completed.
555  */
556 u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv)
557 {
558 	struct mwifiex_sta_node *sta_ptr;
559 
560 	if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
561 		return false;
562 
563 	sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING);
564 	if (sta_ptr)
565 		return true;
566 
567 	return false;
568 }
569 
570 u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv)
571 {
572 	struct mwifiex_sta_node *sta_ptr;
573 
574 	if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
575 		return false;
576 
577 	sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN);
578 	if (sta_ptr)
579 		return true;
580 
581 	return false;
582 }
583 
584 /* If tdls channel switching is on-going or tdls operate on off-channel,
585  * cmd path should be blocked until tdls switched to base-channel.
586  */
587 u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv)
588 {
589 	if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
590 		return true;
591 
592 	if (mwifiex_is_tdls_chan_switching(priv) ||
593 	    mwifiex_is_tdls_off_chan(priv))
594 		return false;
595 
596 	return true;
597 }
598 
599 /* This function will add a sta_node entry to associated station list
600  * table with the given mac address.
601  * If entry exist already, existing entry is returned.
602  * If received mac address is NULL, NULL is returned.
603  */
604 struct mwifiex_sta_node *
605 mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac)
606 {
607 	struct mwifiex_sta_node *node;
608 	unsigned long flags;
609 
610 	if (!mac)
611 		return NULL;
612 
613 	spin_lock_irqsave(&priv->sta_list_spinlock, flags);
614 	node = mwifiex_get_sta_entry(priv, mac);
615 	if (node)
616 		goto done;
617 
618 	node = kzalloc(sizeof(*node), GFP_ATOMIC);
619 	if (!node)
620 		goto done;
621 
622 	memcpy(node->mac_addr, mac, ETH_ALEN);
623 	list_add_tail(&node->list, &priv->sta_list);
624 
625 done:
626 	spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
627 	return node;
628 }
629 
630 /* This function will search for HT IE in association request IEs
631  * and set station HT parameters accordingly.
632  */
633 void
634 mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
635 		       int ies_len, struct mwifiex_sta_node *node)
636 {
637 	struct ieee_types_header *ht_cap_ie;
638 	const struct ieee80211_ht_cap *ht_cap;
639 
640 	if (!ies)
641 		return;
642 
643 	ht_cap_ie = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies,
644 					     ies_len);
645 	if (ht_cap_ie) {
646 		ht_cap = (void *)(ht_cap_ie + 1);
647 		node->is_11n_enabled = 1;
648 		node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
649 				  IEEE80211_HT_CAP_MAX_AMSDU ?
650 				  MWIFIEX_TX_DATA_BUF_SIZE_8K :
651 				  MWIFIEX_TX_DATA_BUF_SIZE_4K;
652 	} else {
653 		node->is_11n_enabled = 0;
654 	}
655 
656 	return;
657 }
658 
659 /* This function will delete a station entry from station list */
660 void mwifiex_del_sta_entry(struct mwifiex_private *priv, const u8 *mac)
661 {
662 	struct mwifiex_sta_node *node;
663 	unsigned long flags;
664 
665 	spin_lock_irqsave(&priv->sta_list_spinlock, flags);
666 
667 	node = mwifiex_get_sta_entry(priv, mac);
668 	if (node) {
669 		list_del(&node->list);
670 		kfree(node);
671 	}
672 
673 	spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
674 	return;
675 }
676 
677 /* This function will delete all stations from associated station list. */
678 void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
679 {
680 	struct mwifiex_sta_node *node, *tmp;
681 	unsigned long flags;
682 
683 	spin_lock_irqsave(&priv->sta_list_spinlock, flags);
684 
685 	list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
686 		list_del(&node->list);
687 		kfree(node);
688 	}
689 
690 	INIT_LIST_HEAD(&priv->sta_list);
691 	spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
692 	return;
693 }
694 
695 /* This function adds histogram data to histogram array*/
696 void mwifiex_hist_data_add(struct mwifiex_private *priv,
697 			   u8 rx_rate, s8 snr, s8 nflr)
698 {
699 	struct mwifiex_histogram_data *phist_data = priv->hist_data;
700 
701 	if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES)
702 		mwifiex_hist_data_reset(priv);
703 	mwifiex_hist_data_set(priv, rx_rate, snr, nflr);
704 }
705 
706 /* function to add histogram record */
707 void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr,
708 			   s8 nflr)
709 {
710 	struct mwifiex_histogram_data *phist_data = priv->hist_data;
711 
712 	atomic_inc(&phist_data->num_samples);
713 	atomic_inc(&phist_data->rx_rate[rx_rate]);
714 	atomic_inc(&phist_data->snr[snr]);
715 	atomic_inc(&phist_data->noise_flr[128 + nflr]);
716 	atomic_inc(&phist_data->sig_str[nflr - snr]);
717 }
718 
719 /* function to reset histogram data during init/reset */
720 void mwifiex_hist_data_reset(struct mwifiex_private *priv)
721 {
722 	int ix;
723 	struct mwifiex_histogram_data *phist_data = priv->hist_data;
724 
725 	atomic_set(&phist_data->num_samples, 0);
726 	for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++)
727 		atomic_set(&phist_data->rx_rate[ix], 0);
728 	for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++)
729 		atomic_set(&phist_data->snr[ix], 0);
730 	for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++)
731 		atomic_set(&phist_data->noise_flr[ix], 0);
732 	for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++)
733 		atomic_set(&phist_data->sig_str[ix], 0);
734 }
735 
736 void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags)
737 {
738 	struct sk_buff *skb;
739 	int buf_len, pad;
740 
741 	buf_len = rx_len + MWIFIEX_RX_HEADROOM + MWIFIEX_DMA_ALIGN_SZ;
742 
743 	skb = __dev_alloc_skb(buf_len, flags);
744 
745 	if (!skb)
746 		return NULL;
747 
748 	skb_reserve(skb, MWIFIEX_RX_HEADROOM);
749 
750 	pad = MWIFIEX_ALIGN_ADDR(skb->data, MWIFIEX_DMA_ALIGN_SZ) -
751 	      (long)skb->data;
752 
753 	skb_reserve(skb, pad);
754 
755 	return skb;
756 }
757 EXPORT_SYMBOL_GPL(mwifiex_alloc_dma_align_buf);
758