xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlinux/moal_cfg80211_util.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file moal_cfg80211_util.c
2  *
3  * @brief This file contains the functions for CFG80211 vendor.
4  *
5  *
6  * Copyright 2015-2022 NXP
7  *
8  * This software file (the File) is distributed by NXP
9  * under the terms of the GNU General Public License Version 2, June 1991
10  * (the License).  You may use, redistribute and/or modify the File in
11  * accordance with the terms and conditions of the License, a copy of which
12  * is available by writing to the Free Software Foundation, Inc.,
13  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15  *
16  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19  * this warranty disclaimer.
20  *
21  */
22 
23 #include "moal_cfg80211_util.h"
24 #include "moal_cfg80211.h"
25 
26 /********************************************************
27  *				Local Variables
28  ********************************************************/
29 
30 /********************************************************
31  *				Global Variables
32  ********************************************************/
33 
34 /********************************************************
35  *				Local Functions
36  ********************************************************/
37 
38 /********************************************************
39  *				Global Functions
40  ********************************************************/
41 
42 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
43 /**nxp vendor command and event*/
44 #define MRVL_VENDOR_ID 0x005043
45 /** vendor events */
46 static const struct nl80211_vendor_cmd_info vendor_events[] = {
47 	{
48 		.vendor_id = MRVL_VENDOR_ID,
49 		.subcmd = event_hang,
50 	}, /*event_id 0*/
51 	{
52 		.vendor_id = MRVL_VENDOR_ID,
53 		.subcmd = event_fw_dump_done,
54 	}, /*event_id 1*/
55 	{
56 		.vendor_id = MRVL_VENDOR_ID,
57 		.subcmd = event_fw_reset_success,
58 	}, /*event_id 2*/
59 	{
60 		.vendor_id = MRVL_VENDOR_ID,
61 		.subcmd = event_fw_reset_failure,
62 	}, /*event_id 3*/
63 	{
64 		.vendor_id = MRVL_VENDOR_ID,
65 		.subcmd = event_fw_reset_start,
66 	}, /*event_id 4*/
67 	{
68 		.vendor_id = MRVL_VENDOR_ID,
69 		.subcmd = event_rssi_monitor,
70 	}, /*event_id 0x1501*/
71 	{
72 		.vendor_id = MRVL_VENDOR_ID,
73 		.subcmd = event_set_key_mgmt_offload,
74 	}, /*event_id 0x10001*/
75 	{
76 		.vendor_id = MRVL_VENDOR_ID,
77 		.subcmd = event_fw_roam_success,
78 	}, /*event_id 0x10002*/
79 	{
80 		.vendor_id = MRVL_VENDOR_ID,
81 		.subcmd = event_cloud_keep_alive,
82 	}, /*event_id 0x10003*/
83 	{
84 		.vendor_id = MRVL_VENDOR_ID,
85 		.subcmd = event_dfs_radar_detected,
86 	}, /*event_id 0x10004*/
87 	{
88 		.vendor_id = MRVL_VENDOR_ID,
89 		.subcmd = event_dfs_cac_started,
90 	}, /*event_id 0x10005*/
91 	{
92 		.vendor_id = MRVL_VENDOR_ID,
93 		.subcmd = event_dfs_cac_finished,
94 	}, /*event_id 0x10006*/
95 	{
96 		.vendor_id = MRVL_VENDOR_ID,
97 		.subcmd = event_dfs_cac_aborted,
98 	}, /*event_id 0x10007*/
99 	{
100 		.vendor_id = MRVL_VENDOR_ID,
101 		.subcmd = event_dfs_nop_finished,
102 	}, /*event_id 0x10008*/
103 	{
104 		.vendor_id = MRVL_VENDOR_ID,
105 		.subcmd = event_wifi_logger_ring_buffer_data,
106 	},
107 	{
108 		.vendor_id = MRVL_VENDOR_ID,
109 		.subcmd = event_wifi_logger_alert,
110 	},
111 	{
112 		.vendor_id = MRVL_VENDOR_ID,
113 		.subcmd = event_packet_fate_monitor,
114 	},
115 	{
116 		.vendor_id = MRVL_VENDOR_ID,
117 		.subcmd = event_wake_reason_report,
118 	},
119 	/**add vendor event here*/
120 };
121 
122 /**nxp vendor policies*/
123 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
124 
125 static const struct nla_policy woal_ll_stat_policy[ATTR_LL_STATS_MAX + 1] = {
126 	[ATTR_LL_STATS_MPDU_SIZE_THRESHOLD] = {.type = NLA_U32},
127 	[ATTR_LL_STATS_AGGRESSIVE_STATS_GATHERING] = {.type = NLA_U32},
128 	[ATTR_LL_STATS_CLEAR_REQ_MASK] = {.type = NLA_U32},
129 	[ATTR_LL_STATS_STOP_REQ] = {.type = NLA_U8}};
130 
131 static const struct nla_policy woal_logger_policy[ATTR_WIFI_LOGGER_MAX + 1] = {
132 	[ATTR_WIFI_LOGGER_RING_ID] = {.type = NLA_STRING},
133 	[ATTR_WIFI_LOGGER_VERBOSE_LEVEL] = {.type = NLA_U32},
134 	[ATTR_WIFI_LOGGER_FLAGS] = {.type = NLA_U32},
135 	[ATTR_WIFI_LOGGER_MIN_DATA_SIZE] = {.type = NLA_U32},
136 	[ATTR_WIFI_LOGGER_MAX_INTERVAL_SEC] = {.type = NLA_U32}};
137 
138 static const struct nla_policy woal_attr_policy[ATTR_WIFI_MAX + 1] = {
139 	[ATTR_CHANNELS_BAND] = {.type = NLA_U32},
140 	[ATTR_SCAN_MAC_OUI_SET] = {.type = NLA_STRING, .len = 3},
141 	[ATTR_NODFS_VALUE] = {.type = NLA_U32},
142 	[ATTR_GET_CONCURRENCY_MATRIX_SET_SIZE_MAX] = {.type = NLA_U32},
143 };
144 
145 // clang-format off
146 static const struct nla_policy
147 	woal_nd_offload_policy[ATTR_ND_OFFLOAD_MAX + 1] = {
148 		[ATTR_ND_OFFLOAD_CONTROL] = {.type = NLA_U8},
149 };
150 // clang-format on
151 
152 static const struct nla_policy
153 	woal_rssi_monitor_policy[ATTR_RSSI_MONITOR_MAX + 1] = {
154 		[ATTR_RSSI_MONITOR_CONTROL] = {.type = NLA_U32},
155 		[ATTR_RSSI_MONITOR_MIN_RSSI] = {.type = NLA_S8},
156 		[ATTR_RSSI_MONITOR_MAX_RSSI] = {.type = NLA_S8},
157 };
158 
159 static const struct nla_policy
160 	woal_packet_filter_policy[ATTR_PACKET_FILTER_MAX + 1] = {
161 		[ATTR_PACKET_FILTER_TOTAL_LENGTH] = {.type = NLA_U32},
162 		[ATTR_PACKET_FILTER_PROGRAM] = {.type = NLA_STRING},
163 };
164 
165 // clang-format off
166 static const struct nla_policy
167 	woal_fw_roaming_policy[MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_MAX + 1] = {
168 		[MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONTROL] = {.type = NLA_U32},
169 		[MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_BSSID] = {
170 			.type = NLA_BINARY},
171 		[MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_SSID] = {
172 			.type = NLA_BINARY},
173 };
174 // clang-format on
175 
176 static const struct nla_policy
177 	woal_keep_alive_policy[MKEEP_ALIVE_ATTRIBUTE_MAX + 1] = {
178 		[MKEEP_ALIVE_ATTRIBUTE_ID] = {.type = NLA_U8},
179 		[MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE] = {.type = NLA_U16},
180 		[MKEEP_ALIVE_ATTRIBUTE_IP_PKT] = {.type = NLA_BINARY},
181 		[MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN] = {.type = NLA_U16},
182 		[MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR] = {.type = NLA_STRING,
183 							.len = ETH_ALEN},
184 		[MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR] = {.type = NLA_STRING,
185 							.len = ETH_ALEN},
186 		[MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC] = {.type = NLA_U32},
187 		[MKEEP_ALIVE_ATTRIBUTE_RETRY_INTERVAL] = {.type = NLA_U32},
188 		[MKEEP_ALIVE_ATTRIBUTE_RETRY_CNT] = {.type = NLA_U8},
189 };
190 #endif
191 
192 /**
193  * @brief get the event id of the events array
194  *
195  * @param event     vendor event
196  *
197  * @return    index of events array
198  */
woal_get_event_id(int event)199 static int woal_get_event_id(int event)
200 {
201 	int i = 0;
202 
203 	for (i = 0; i < (int)ARRAY_SIZE(vendor_events); i++) {
204 		if ((int)vendor_events[i].subcmd == event)
205 			return i;
206 	}
207 
208 	return event_max;
209 }
210 
211 /**
212  * @brief send vendor event to kernel
213  *
214  * @param priv       A pointer to moal_private
215  * @param event    vendor event
216  * @param data     a pointer to data
217  * @param  len     data length
218  *
219  * @return      0: success  1: fail
220  */
woal_cfg80211_vendor_event(moal_private * priv,int event,t_u8 * data,int len)221 int woal_cfg80211_vendor_event(moal_private *priv, int event, t_u8 *data,
222 			       int len)
223 {
224 	struct wiphy *wiphy = NULL;
225 	struct sk_buff *skb = NULL;
226 	int event_id = 0;
227 	t_u8 *pos = NULL;
228 	int ret = 0;
229 
230 	ENTER();
231 
232 	if (!priv || !priv->wdev || !priv->wdev->wiphy) {
233 		LEAVE();
234 		return ret;
235 	}
236 	wiphy = priv->wdev->wiphy;
237 	PRINTM(MEVENT, "vendor event :0x%x\n", event);
238 	event_id = woal_get_event_id(event);
239 	if (event_max == event_id) {
240 		PRINTM(MERROR, "Not find this event %d\n", event_id);
241 		ret = 1;
242 		LEAVE();
243 		return ret;
244 	}
245 
246 	/**allocate skb*/
247 #if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
248 	skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev, len, event_id,
249 					  GFP_ATOMIC);
250 #else
251 	skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, GFP_ATOMIC);
252 #endif
253 
254 	if (!skb) {
255 		PRINTM(MERROR, "allocate memory fail for vendor event\n");
256 		ret = 1;
257 		LEAVE();
258 		return ret;
259 	}
260 	pos = skb_put(skb, len);
261 	moal_memcpy_ext(priv->phandle, pos, data, len, len);
262 	/**send event*/
263 	cfg80211_vendor_event(skb, GFP_ATOMIC);
264 
265 	LEAVE();
266 	return ret;
267 }
268 
269 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
270 /**
271  * @brief send fw dump complete event to vendorhal
272  *
273  * @param priv       A pointer to moal_private
274  *
275  * @return      N/A
276  */
woal_cfg80211_vendor_event_fw_dump(moal_private * priv)277 void woal_cfg80211_vendor_event_fw_dump(moal_private *priv)
278 {
279 	PRINTM(MEVENT, "wlan: Notify FW dump complete event\n");
280 	woal_cfg80211_vendor_event(priv, event_fw_dump_done, CUS_EVT_FW_DUMP,
281 				   strlen(CUS_EVT_FW_DUMP));
282 }
283 #endif
284 
285 /**
286  * @brief send dfs vendor event to kernel
287  *
288  * @param priv       A pointer to moal_private
289  * @param event      dfs vendor event
290  * @param chandef    a pointer to struct cfg80211_chan_def
291  *
292  * @return      N/A
293  */
woal_cfg80211_dfs_vendor_event(moal_private * priv,int event,struct cfg80211_chan_def * chandef)294 void woal_cfg80211_dfs_vendor_event(moal_private *priv, int event,
295 				    struct cfg80211_chan_def *chandef)
296 {
297 	dfs_event evt;
298 
299 	ENTER();
300 	if (!chandef) {
301 		LEAVE();
302 		return;
303 	}
304 	memset(&evt, 0, sizeof(dfs_event));
305 	evt.freq = chandef->chan->center_freq;
306 	evt.chan_width = chandef->width;
307 	evt.cf1 = chandef->center_freq1;
308 	evt.cf2 = chandef->center_freq2;
309 	switch (chandef->width) {
310 	case NL80211_CHAN_WIDTH_20_NOHT:
311 		evt.ht_enabled = 0;
312 		break;
313 	case NL80211_CHAN_WIDTH_20:
314 		evt.ht_enabled = 1;
315 		break;
316 	case NL80211_CHAN_WIDTH_40:
317 		evt.ht_enabled = 1;
318 		if (chandef->center_freq1 < chandef->chan->center_freq)
319 			evt.chan_offset = -1;
320 		else
321 			evt.chan_offset = 1;
322 		break;
323 	case NL80211_CHAN_WIDTH_80:
324 	case NL80211_CHAN_WIDTH_80P80:
325 	case NL80211_CHAN_WIDTH_160:
326 		evt.ht_enabled = 1;
327 		break;
328 	default:
329 		break;
330 	}
331 	woal_cfg80211_vendor_event(priv, event, (t_u8 *)&evt,
332 				   sizeof(dfs_event));
333 	LEAVE();
334 }
335 
336 /**
337  * @brief vendor command to set drvdbg
338  *
339  * @param wiphy       A pointer to wiphy struct
340  * @param wdev     A pointer to wireless_dev struct
341  * @param data     a pointer to data
342  * @param  len     data length
343  *
344  * @return      0: success  1: fail
345  */
woal_cfg80211_subcmd_set_drvdbg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)346 static int woal_cfg80211_subcmd_set_drvdbg(struct wiphy *wiphy,
347 					   struct wireless_dev *wdev,
348 					   const void *data, int data_len)
349 {
350 #ifdef DEBUG_LEVEL1
351 	struct net_device *dev = wdev->netdev;
352 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
353 	struct sk_buff *skb = NULL;
354 	t_u8 *pos = NULL;
355 #endif
356 	int ret = 1;
357 
358 	ENTER();
359 #ifdef DEBUG_LEVEL1
360 	/**handle this sub command*/
361 	DBG_HEXDUMP(MCMD_D, "Vendor drvdbg", (t_u8 *)data, data_len);
362 
363 	if (data_len) {
364 		/* Get the driver debug bit masks from user */
365 		drvdbg = *((t_u32 *)data);
366 		PRINTM(MIOCTL, "new drvdbg %x\n", drvdbg);
367 		/* Set the driver debug bit masks into mlan */
368 		if (woal_set_drvdbg(priv, drvdbg)) {
369 			PRINTM(MERROR, "Set drvdbg failed!\n");
370 			ret = 1;
371 		}
372 	}
373 	/** Allocate skb for cmd reply*/
374 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(drvdbg));
375 	if (!skb) {
376 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
377 		ret = 1;
378 		LEAVE();
379 		return ret;
380 	}
381 	pos = skb_put(skb, sizeof(drvdbg));
382 	moal_memcpy_ext(priv->phandle, pos, &drvdbg, sizeof(drvdbg),
383 			sizeof(drvdbg));
384 	ret = cfg80211_vendor_cmd_reply(skb);
385 #endif
386 	LEAVE();
387 	return ret;
388 }
389 
390 /**
391  * @brief process one channel in bucket
392  *
393  * @param priv       A pointer to moal_private struct
394  *
395  * @param channel     a pointer to channel
396  *
397  * @return      0: success  other: fail
398  */
woal_band_to_valid_channels(moal_private * priv,wifi_band w_band,int channel[],t_u32 * nchannel)399 static mlan_status woal_band_to_valid_channels(moal_private *priv,
400 					       wifi_band w_band, int channel[],
401 					       t_u32 *nchannel)
402 {
403 	int band = 0;
404 	struct ieee80211_supported_band *sband;
405 	struct ieee80211_channel *ch;
406 	int i = 0;
407 	t_u8 cnt = 0;
408 	int *ch_ptr = channel;
409 
410 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
411 		if (!priv->wdev->wiphy->bands[band])
412 			continue;
413 		if ((band == IEEE80211_BAND_2GHZ) && !(w_band & WIFI_BAND_BG))
414 			continue;
415 		if ((band == IEEE80211_BAND_5GHZ) &&
416 		    !((w_band & WIFI_BAND_A) || (w_band & WIFI_BAND_A_DFS)))
417 			continue;
418 		sband = priv->wdev->wiphy->bands[band];
419 		for (i = 0; (i < sband->n_channels); i++) {
420 			ch = &sband->channels[i];
421 			if (ch->flags & IEEE80211_CHAN_DISABLED) {
422 				PRINTM(MERROR, "Skip DISABLED channel %d\n",
423 				       ch->center_freq);
424 				continue;
425 			}
426 			if (band == IEEE80211_BAND_5GHZ) {
427 				if (((ch->flags & IEEE80211_CHAN_RADAR) &&
428 				     !(w_band & WIFI_BAND_A_DFS)) ||
429 				    (!(ch->flags & IEEE80211_CHAN_RADAR) &&
430 				     !(w_band & WIFI_BAND_A)))
431 					continue;
432 			}
433 			if (cnt >= *nchannel) {
434 				PRINTM(MERROR,
435 				       "cnt=%d is exceed %d, cur ch=%d %dMHz\n",
436 				       cnt, *nchannel, ch->hw_value,
437 				       ch->center_freq);
438 				break;
439 			}
440 			*ch_ptr = ch->center_freq;
441 			ch_ptr++;
442 			cnt++;
443 		}
444 	}
445 
446 	PRINTM(MCMND, "w_band=%d cnt=%d\n", w_band, cnt);
447 	*nchannel = cnt;
448 	return MLAN_STATUS_SUCCESS;
449 }
450 
451 /**
452  * @brief GSCAN subcmd - enable full scan results
453  *
454  * @param wiphy       A pointer to wiphy struct
455  * @param wdev     A pointer to wireless_dev struct
456  *
457  * @param data     a pointer to data
458  * @param  data_len     data length
459  *
460  * @return      0: success  other: fail
461  */
woal_cfg80211_subcmd_get_valid_channels(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)462 static int woal_cfg80211_subcmd_get_valid_channels(struct wiphy *wiphy,
463 						   struct wireless_dev *wdev,
464 						   const void *data, int len)
465 {
466 	struct net_device *dev = wdev->netdev;
467 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
468 	struct nlattr *tb[ATTR_WIFI_MAX + 1];
469 	t_u32 band = 0;
470 	int ch_out[MAX_CHANNEL_NUM];
471 	t_u32 nchannel = 0;
472 	t_u32 mem_needed = 0;
473 	struct sk_buff *skb = NULL;
474 	int err = 0;
475 
476 	ENTER();
477 	PRINTM(MCMND, "Enter %s()\n", __func__);
478 
479 	err = nla_parse(tb, ATTR_WIFI_MAX, data, len, NULL
480 #if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
481 			,
482 			NULL
483 #endif
484 	);
485 	if (err) {
486 		PRINTM(MERROR, "%s: nla_parse fail\n", __func__);
487 		err = -EFAULT;
488 		goto done;
489 	}
490 
491 	if (!tb[ATTR_CHANNELS_BAND]) {
492 		PRINTM(MERROR, "%s: null attr: tb[ATTR_GET_CH]=%p\n", __func__,
493 		       tb[ATTR_CHANNELS_BAND]);
494 		err = -EINVAL;
495 		goto done;
496 	}
497 	band = nla_get_u32(tb[ATTR_CHANNELS_BAND]);
498 	if (band > WIFI_BAND_MAX) {
499 		PRINTM(MERROR, "%s: invalid band=%d\n", __func__, band);
500 		err = -EINVAL;
501 		goto done;
502 	}
503 
504 	memset(ch_out, 0x00, sizeof(ch_out));
505 	nchannel = MAX_CHANNEL_NUM;
506 	if (woal_band_to_valid_channels(priv, band, ch_out, &nchannel) !=
507 	    MLAN_STATUS_SUCCESS) {
508 		PRINTM(MERROR,
509 		       "get_channel_list: woal_band_to_valid_channels fail\n");
510 		return -EFAULT;
511 	}
512 
513 	mem_needed = nla_total_size(nchannel * sizeof(ch_out[0])) +
514 		     nla_total_size(sizeof(nchannel)) + VENDOR_REPLY_OVERHEAD;
515 	/* Alloc the SKB for vendor_event */
516 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
517 	if (unlikely(!skb)) {
518 		PRINTM(MERROR, "skb alloc failed");
519 		err = -ENOMEM;
520 		goto done;
521 	}
522 
523 	if (nla_put_u32(skb, ATTR_NUM_CHANNELS, nchannel) ||
524 	    nla_put(skb, ATTR_CHANNEL_LIST, nchannel * sizeof(ch_out[0]),
525 		    ch_out)) {
526 		PRINTM(MERROR, "nla_put failed!\n");
527 		kfree_skb(skb);
528 		err = -ENOMEM;
529 		goto done;
530 	}
531 	err = cfg80211_vendor_cmd_reply(skb);
532 	if (err) {
533 		PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
534 		goto done;
535 	}
536 
537 done:
538 	LEAVE();
539 	return err;
540 }
541 
542 /**
543  * @brief vendor command to get driver version
544  *
545  * @param wiphy       A pointer to wiphy struct
546  * @param wdev     A pointer to wireless_dev struct
547  * @param data     a pointer to data
548  * @param  len     data length
549  *
550  * @return      0: success  1: fail
551  */
woal_cfg80211_subcmd_get_drv_version(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)552 static int woal_cfg80211_subcmd_get_drv_version(struct wiphy *wiphy,
553 						struct wireless_dev *wdev,
554 						const void *data, int data_len)
555 {
556 	struct net_device *dev = wdev->netdev;
557 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
558 	struct sk_buff *skb = NULL;
559 	t_u32 reply_len = 0;
560 	int ret = 0;
561 	t_u32 drv_len = 0;
562 	char drv_version[MLAN_MAX_VER_STR_LEN] = {0};
563 	char *pos;
564 
565 	ENTER();
566 	moal_memcpy_ext(priv->phandle, drv_version,
567 			&priv->phandle->driver_version, MLAN_MAX_VER_STR_LEN,
568 			MLAN_MAX_VER_STR_LEN);
569 	drv_len = strlen(drv_version);
570 	pos = strstr(drv_version, "%s");
571 	/* remove 3 char "-%s" in driver_version string */
572 	if (pos != NULL)
573 		moal_memcpy_ext(priv->phandle, pos, pos + 3, strlen(pos) - 3,
574 				strlen(pos));
575 
576 	reply_len = strlen(drv_version) + 1;
577 	drv_len -= 3;
578 	drv_version[drv_len] = '\0';
579 
580 	/** Allocate skb for cmd reply*/
581 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
582 	if (!skb) {
583 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
584 		ret = -ENOMEM;
585 		goto done;
586 	}
587 
588 	nla_put(skb, MRVL_WLAN_VENDOR_ATTR_NAME, reply_len,
589 		(t_u8 *)drv_version);
590 	ret = cfg80211_vendor_cmd_reply(skb);
591 	if (ret)
592 		PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
593 done:
594 	LEAVE();
595 	return ret;
596 }
597 
598 /**
599  * @brief vendor command to get firmware version
600  *
601  * @param wiphy       A pointer to wiphy struct
602  * @param wdev     A pointer to wireless_dev struct
603  * @param data     a pointer to data
604  * @param  len     data length
605  *
606  * @return      0: success  1: fail
607  */
woal_cfg80211_subcmd_get_fw_version(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)608 static int woal_cfg80211_subcmd_get_fw_version(struct wiphy *wiphy,
609 					       struct wireless_dev *wdev,
610 					       const void *data, int data_len)
611 {
612 	struct net_device *dev = wdev->netdev;
613 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
614 	struct sk_buff *skb = NULL;
615 	t_u32 reply_len = 0;
616 	char end_c = '\0';
617 	int ret = 0;
618 	char fw_ver[32] = {0};
619 	union {
620 		t_u32 l;
621 		t_u8 c[4];
622 	} ver;
623 
624 	ENTER();
625 
626 	ver.l = priv->phandle->fw_release_number;
627 	snprintf(fw_ver, sizeof(fw_ver), "%u.%u.%u.p%u%c", ver.c[2], ver.c[1],
628 		 ver.c[0], ver.c[3], end_c);
629 	reply_len = strlen(fw_ver) + 1;
630 
631 	/** Allocate skb for cmd reply*/
632 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
633 	if (!skb) {
634 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
635 		ret = -ENOMEM;
636 		goto done;
637 	}
638 
639 	nla_put(skb, MRVL_WLAN_VENDOR_ATTR_NAME, reply_len, (t_u8 *)fw_ver);
640 	ret = cfg80211_vendor_cmd_reply(skb);
641 	if (ret)
642 		PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
643 done:
644 	LEAVE();
645 	return ret;
646 }
647 
648 /**
649  * @brief vendor command to get firmware memory dump
650  *
651  * @param wiphy       A pointer to wiphy struct
652  * @param wdev     A pointer to wireless_dev struct
653  * @param data     a pointer to data
654  * @param  len     data length
655  *
656  * @return      0: success  1: fail
657  */
woal_cfg80211_subcmd_get_fw_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)658 static int woal_cfg80211_subcmd_get_fw_dump(struct wiphy *wiphy,
659 					    struct wireless_dev *wdev,
660 					    const void *data, int data_len)
661 {
662 	struct net_device *dev = NULL;
663 	moal_private *priv = NULL;
664 	moal_handle *handle = NULL;
665 	int ret = MLAN_STATUS_SUCCESS;
666 	int length = 0;
667 	struct sk_buff *skb = NULL;
668 
669 	ENTER();
670 	if (!wdev || !wdev->netdev) {
671 		LEAVE();
672 		return -EFAULT;
673 	}
674 	dev = wdev->netdev;
675 	priv = (moal_private *)woal_get_netdev_priv(dev);
676 	handle = priv->phandle;
677 	if (handle) {
678 		memset(handle->firmware_dump_file, 0,
679 		       sizeof(handle->firmware_dump_file));
680 	}
681 	length = sizeof(handle->firmware_dump_file);
682 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, length);
683 	if (!skb) {
684 		PRINTM(MERROR, "Failed to allocate memory for skb\n");
685 		ret = -ENOMEM;
686 		goto done;
687 	}
688 	nla_put(skb, ATTR_FW_DUMP_PATH, sizeof(handle->firmware_dump_file),
689 		handle->firmware_dump_file);
690 	ret = cfg80211_vendor_cmd_reply(skb);
691 	if (ret)
692 		PRINTM(MERROR, "Command reply failed ret = %d\n", ret);
693 done:
694 	LEAVE();
695 	return ret;
696 }
697 
698 /**
699  * @brief vendor command to get driver memory dump
700  *
701  * @param wiphy       A pointer to wiphy struct
702  * @param wdev     A pointer to wireless_dev struct
703  * @param data     a pointer to data
704  * @param  len     data length
705  *
706  * @return      0: success  1: fail
707  */
woal_cfg80211_subcmd_get_drv_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)708 static int woal_cfg80211_subcmd_get_drv_dump(struct wiphy *wiphy,
709 					     struct wireless_dev *wdev,
710 					     const void *data, int data_len)
711 {
712 	struct net_device *dev = NULL;
713 	moal_private *priv = NULL;
714 	moal_handle *handle = NULL;
715 	int ret = MLAN_STATUS_SUCCESS;
716 	int length = 0;
717 	char driver_dump_file[128];
718 	struct sk_buff *skb = NULL;
719 
720 	ENTER();
721 
722 	if (!wdev || !wdev->netdev) {
723 		LEAVE();
724 		return -EFAULT;
725 	}
726 	dev = wdev->netdev;
727 	priv = (moal_private *)woal_get_netdev_priv(dev);
728 	handle = priv->phandle;
729 	memset(driver_dump_file, 0, sizeof(driver_dump_file));
730 	sprintf(driver_dump_file, "/proc/mwlan/");
731 	if (handle->handle_idx)
732 		sprintf(driver_dump_file, "drv_dump%d", handle->handle_idx);
733 	else
734 		sprintf(driver_dump_file, "drv_dump");
735 	PRINTM(MMSG, "driver dump file is %s\n", driver_dump_file);
736 	length = sizeof(driver_dump_file);
737 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, length);
738 	if (!skb) {
739 		PRINTM(MERROR, "Failed to allocate memory for skb\n");
740 		ret = -ENOMEM;
741 		goto done;
742 	}
743 	if (nla_put_string(skb, ATTR_DRV_DUMP_PATH, driver_dump_file)) {
744 		PRINTM(MERROR, "nla_put failed!\n");
745 		kfree_skb(skb);
746 		ret = -ENOMEM;
747 		goto done;
748 	}
749 	ret = cfg80211_vendor_cmd_reply(skb);
750 	if (ret)
751 		PRINTM(MERROR, "Command reply failed ret = %d\n", ret);
752 done:
753 	LEAVE();
754 	return ret;
755 }
756 
757 /**
758  * @brief vendor command to get supported feature set
759  *
760  * @param wiphy       A pointer to wiphy struct
761  * @param wdev     A pointer to wireless_dev struct
762  * @param data     a pointer to data
763  * @param  len     data length
764  *
765  * @return      0: success  1: fail
766  */
woal_cfg80211_subcmd_get_supp_feature_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)767 static int woal_cfg80211_subcmd_get_supp_feature_set(struct wiphy *wiphy,
768 						     struct wireless_dev *wdev,
769 						     const void *data,
770 						     int data_len)
771 {
772 	struct sk_buff *skb = NULL;
773 
774 	struct net_device *dev = wdev->netdev;
775 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
776 	mlan_fw_info fw_info;
777 
778 	t_u32 reply_len = 0;
779 	int ret = 0;
780 	t_u32 supp_feature_set = 0;
781 
782 	ENTER();
783 	supp_feature_set = WLAN_FEATURE_INFRA
784 #if defined(UAP_SUPPORT) && defined(STA_SUPPORT)
785 			   | WLAN_FEATURE_AP_STA
786 #endif
787 			   | WLAN_FEATURE_LINK_LAYER_STATS |
788 			   WLAN_FEATURE_LOGGER | WLAN_FEATURE_RSSI_MONITOR |
789 			   WLAN_FEATURE_CONFIG_NDO | WLAN_FEATURE_SCAN_RAND |
790 			   WLAN_FEATURE_MKEEP_ALIVE | WLAN_FEATURE_PNO |
791 			   WLAN_FEATURE_TDLS;
792 
793 	memset(&fw_info, 0, sizeof(mlan_fw_info));
794 	if (MLAN_STATUS_SUCCESS !=
795 	    woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) {
796 		PRINTM(MERROR, "Fail to get fw info\n");
797 		ret = -EFAULT;
798 		goto done;
799 	}
800 	if (fw_info.fw_bands & BAND_A)
801 		supp_feature_set |= WLAN_FEATURE_INFRA_5G;
802 	if (fw_info.fw_roaming_support)
803 		supp_feature_set |= WLAN_FEATURE_CONTROL_ROAMING;
804 
805 	priv->phandle->wifi_hal_flag = MTRUE;
806 
807 	reply_len = sizeof(supp_feature_set);
808 	/** Allocate skb for cmd reply*/
809 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
810 	if (!skb) {
811 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
812 		ret = -ENOMEM;
813 		goto done;
814 	}
815 	if (nla_put_u32(skb, ATTR_FEATURE_SET, supp_feature_set)) {
816 		PRINTM(MERROR, "nla_put failed!\n");
817 		kfree_skb(skb);
818 		ret = -ENOMEM;
819 		goto done;
820 	}
821 	ret = cfg80211_vendor_cmd_reply(skb);
822 	if (ret)
823 		PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
824 done:
825 	LEAVE();
826 	return ret;
827 }
828 
829 /**
830  * @brief vendor command to set country code
831  *
832  * @param wiphy       A pointer to wiphy struct
833  * @param wdev     A pointer to wireless_dev struct
834  * @param data     a pointer to data
835  * @param  len     data length
836  *
837  * @return      0: success  1: fail
838  */
woal_cfg80211_subcmd_set_country_code(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)839 static int woal_cfg80211_subcmd_set_country_code(struct wiphy *wiphy,
840 						 struct wireless_dev *wdev,
841 						 const void *data, int data_len)
842 {
843 	struct sk_buff *skb = NULL;
844 	t_u32 reply_len = 0;
845 	int ret = 0, rem, type;
846 	const struct nlattr *iter;
847 	char country[COUNTRY_CODE_LEN] = {0};
848 
849 	ENTER();
850 
851 	nla_for_each_attr (iter, data, data_len, rem) {
852 		type = nla_type(iter);
853 		switch (type) {
854 		case ATTR_COUNTRY_CODE:
855 			strncpy(country, nla_data(iter),
856 				MIN((int)sizeof(country) - 1, nla_len(iter)));
857 			break;
858 		default:
859 			PRINTM(MERROR, "Unknown type: %d\n", type);
860 			return ret;
861 		}
862 	}
863 
864 	if (!moal_extflg_isset((moal_handle *)woal_get_wiphy_priv(wiphy),
865 			       EXT_DISABLE_REGD_BY_DRIVER))
866 		regulatory_hint(wiphy, country);
867 
868 	/** Allocate skb for cmd reply*/
869 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
870 	if (!skb) {
871 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
872 		ret = -ENOMEM;
873 		goto done;
874 	}
875 
876 	ret = cfg80211_vendor_cmd_reply(skb);
877 	if (ret)
878 		PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
879 done:
880 	LEAVE();
881 	return ret;
882 }
883 
884 /**
885  * @brief vendor command to get supported feature set
886  *
887  * @param wiphy       A pointer to wiphy struct
888  * @param wdev     A pointer to wireless_dev struct
889  * @param data     a pointer to data
890  * @param  len     data length
891  *
892  * @return      0: success  1: fail
893  */
woal_cfg80211_subcmd_get_wifi_logger_supp_feature_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)894 static int woal_cfg80211_subcmd_get_wifi_logger_supp_feature_set(
895 	struct wiphy *wiphy, struct wireless_dev *wdev, const void *data,
896 	int data_len)
897 {
898 	struct sk_buff *skb = NULL;
899 	t_u32 reply_len = 0;
900 	int ret = 0;
901 	t_u32 supp_feature_set = 0;
902 
903 	ENTER();
904 
905 	supp_feature_set = WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
906 	reply_len = sizeof(supp_feature_set);
907 	/** Allocate skb for cmd reply*/
908 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
909 	if (!skb) {
910 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
911 		ret = -ENOMEM;
912 		goto done;
913 	}
914 	if (nla_put_u32(skb, ATTR_WIFI_LOGGER_FEATURE_SET, supp_feature_set)) {
915 		PRINTM(MERROR, "nla_put failed!\n");
916 		kfree_skb(skb);
917 		ret = -ENOMEM;
918 		goto done;
919 	}
920 	ret = cfg80211_vendor_cmd_reply(skb);
921 	if (ret)
922 		PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
923 done:
924 	LEAVE();
925 	return ret;
926 }
927 
928 /**
929  * @brief get ring status
930  *
931  * @param priv       A pointer to moal_private struct
932  * @param ring_id    ring buffer id
933  * @param status     a pointer to wifi_ring_buffer_status
934  *
935  * @return    void
936  */
woal_get_ring_status(moal_private * priv,int ring_id,wifi_ring_buffer_status * status)937 static void woal_get_ring_status(moal_private *priv, int ring_id,
938 				 wifi_ring_buffer_status *status)
939 {
940 	int id = 0;
941 	wifi_ring_buffer *ring;
942 
943 	ENTER();
944 	for (id = 0; id < RING_ID_MAX; id++) {
945 		ring = (wifi_ring_buffer *)priv->rings[id];
946 		if (ring && VALID_RING(ring->ring_id) &&
947 		    ring_id == ring->ring_id) {
948 			moal_memcpy(priv->phandle, status->name, ring->name,
949 				    sizeof(status->name) - 1);
950 			status->ring_id = ring->ring_id;
951 			status->ring_buffer_byte_size = ring->ring_size;
952 			status->written_bytes = ring->ctrl.written_bytes;
953 			status->written_records = ring->ctrl.written_records;
954 			status->read_bytes = ring->ctrl.read_bytes;
955 			status->verbose_level = ring->log_level;
956 			PRINTM(MINFO,
957 			       "%s, name: %s, ring_id: %d, ring_size : %d, written_bytes: %d, written_records: %d, read_bytes: %d\n",
958 			       __func__, status->name, status->ring_id,
959 			       status->ring_buffer_byte_size,
960 			       status->written_bytes, status->written_records,
961 			       status->read_bytes);
962 			break;
963 		}
964 	}
965 	LEAVE();
966 }
967 
968 /**
969  * @brief vendor command to get ring buffer status
970  *
971  * @param wiphy       A pointer to wiphy struct
972  * @param wdev     A pointer to wireless_dev struct
973  * @param data     a pointer to data
974  * @param  len     data length
975  *
976  * @return      0: success  1: fail
977  */
woal_cfg80211_subcmd_get_ring_buff_status(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)978 static int woal_cfg80211_subcmd_get_ring_buff_status(struct wiphy *wiphy,
979 						     struct wireless_dev *wdev,
980 						     const void *data,
981 						     int data_len)
982 {
983 	struct net_device *dev = wdev->netdev;
984 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
985 	struct sk_buff *skb = NULL;
986 	t_u32 reply_len = 0;
987 	t_u8 ringIdx, ring_cnt = 0;
988 	int ret = 0;
989 	wifi_ring_buffer_status status[RING_ID_MAX];
990 	wifi_ring_buffer_status ring_status;
991 
992 	ENTER();
993 	reply_len =
994 		RING_ID_MAX * sizeof(wifi_ring_buffer_status) + sizeof(t_u32);
995 	/** Allocate skb for cmd reply*/
996 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
997 	if (!skb) {
998 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
999 		ret = -ENOMEM;
1000 		goto done;
1001 	}
1002 
1003 	/* should sync with HAL side to decide payload layout.
1004 	 * just ring buffer status or ring buffer num + ring buffer status
1005 	 * currently only have ring buffer status
1006 	 */
1007 	for (ringIdx = 0; ringIdx < RING_ID_MAX; ringIdx++) {
1008 		memset(&ring_status, 0, sizeof(wifi_ring_buffer_status));
1009 		woal_get_ring_status(priv, ringIdx, &ring_status);
1010 		moal_memcpy_ext(priv->phandle, &status[ring_cnt++],
1011 				&ring_status, sizeof(wifi_ring_buffer_status),
1012 				sizeof(wifi_ring_buffer_status));
1013 	}
1014 
1015 	if (nla_put_u32(skb, ATTR_NUM_RINGS, ring_cnt) ||
1016 	    nla_put(skb, ATTR_RING_BUFFER_STATUS,
1017 		    sizeof(wifi_ring_buffer_status) * ring_cnt, status)) {
1018 		PRINTM(MERROR, "nla_put failed!\n");
1019 		kfree_skb(skb);
1020 		ret = -ENOMEM;
1021 		goto done;
1022 	}
1023 
1024 	ret = cfg80211_vendor_cmd_reply(skb);
1025 
1026 	if (ret)
1027 		PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
1028 done:
1029 	LEAVE();
1030 	return ret;
1031 }
1032 
1033 /**
1034  * @brief return ring_id based on ring_name
1035  *
1036  * @param priv          A pointer to moal_private struct
1037  * @param ring_name     A pointer to ring_name
1038  *
1039  * @return      An invalid ring id for failure or valid ring id on success.
1040  */
woal_get_ring_id_by_name(moal_private * priv,char * ring_name)1041 int woal_get_ring_id_by_name(moal_private *priv, char *ring_name)
1042 {
1043 	int id;
1044 	wifi_ring_buffer *ring;
1045 
1046 	ENTER();
1047 
1048 	for (id = 0; id < RING_ID_MAX; id++) {
1049 		ring = (wifi_ring_buffer *)priv->rings[id];
1050 		if (ring &&
1051 		    !strncmp(ring->name, ring_name, sizeof(ring->name) - 1))
1052 			break;
1053 	}
1054 
1055 	LEAVE();
1056 	return id;
1057 }
1058 
1059 /**
1060  * @brief start logger
1061  *
1062  * @param priv          A pointer to moal_private struct
1063  * @param ring_name     string ring_name
1064  * @param log_level     log level to record
1065  * @param flags         reserved
1066  * @param time_intval   interval to report log to HAL
1067  * @param threshold     buffer threshold to report log to HAL
1068  *
1069  * @return      0: success  1: fail
1070  */
woal_start_logging(moal_private * priv,char * ring_name,int log_level,int flags,int time_intval,int threshold)1071 int woal_start_logging(moal_private *priv, char *ring_name, int log_level,
1072 		       int flags, int time_intval, int threshold)
1073 {
1074 	int ret = 0;
1075 	int ring_id;
1076 	wifi_ring_buffer *ring_buffer;
1077 	unsigned long lock_flags;
1078 
1079 	ENTER();
1080 
1081 	ring_id = woal_get_ring_id_by_name(priv, ring_name);
1082 	if (!VALID_RING(ring_id)) {
1083 		ret = -EINVAL;
1084 		goto done;
1085 	}
1086 
1087 	PRINTM(MCMND,
1088 	       "%s , log_level : %d, time_intval : %d, threshod %d Bytes\n",
1089 	       __func__, log_level, time_intval, threshold);
1090 
1091 	ring_buffer = (wifi_ring_buffer *)priv->rings[ring_id];
1092 	if (!ring_buffer || ring_buffer->state == RING_STOP) {
1093 		PRINTM(MERROR, "Ring is stopped!\n");
1094 		ret = -EAGAIN;
1095 		goto done;
1096 	}
1097 
1098 	spin_lock_irqsave(&ring_buffer->lock, lock_flags);
1099 	ring_buffer->log_level = log_level;
1100 	ring_buffer->threshold = threshold;
1101 	if (log_level == 0)
1102 		ring_buffer->state = RING_SUSPEND;
1103 	else
1104 		ring_buffer->state = RING_ACTIVE;
1105 	ring_buffer->interval = msecs_to_jiffies(time_intval * MSEC_PER_SEC);
1106 	spin_unlock_irqrestore(&ring_buffer->lock, lock_flags);
1107 
1108 	if (log_level == 0) {
1109 		cancel_delayed_work_sync(&ring_buffer->work);
1110 	} else {
1111 		if (ring_buffer->interval)
1112 			schedule_delayed_work(&ring_buffer->work,
1113 					      ring_buffer->interval);
1114 	}
1115 
1116 done:
1117 	LEAVE();
1118 	return ret;
1119 }
1120 
1121 /**
1122  * @brief vendor command to start logging
1123  *
1124  * @param wiphy       A pointer to wiphy struct
1125  * @param wdev     A pointer to wireless_dev struct
1126  * @param data     a pointer to data
1127  * @param  len     data length
1128  *
1129  * @return      0: success  1: fail
1130  */
woal_cfg80211_subcmd_start_logging(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1131 static int woal_cfg80211_subcmd_start_logging(struct wiphy *wiphy,
1132 					      struct wireless_dev *wdev,
1133 					      const void *data, int len)
1134 {
1135 	int ret = 0, rem, type;
1136 	char ring_name[RING_NAME_MAX] = {0};
1137 	int log_level = 0, flags = 0, time_intval = 0, threshold = 0;
1138 	const struct nlattr *iter;
1139 	struct net_device *dev = wdev->netdev;
1140 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1141 
1142 	ENTER();
1143 
1144 	nla_for_each_attr (iter, data, len, rem) {
1145 		type = nla_type(iter);
1146 		switch (type) {
1147 		case ATTR_WIFI_LOGGER_RING_ID:
1148 			strncpy(ring_name, nla_data(iter),
1149 				MIN(sizeof(ring_name) - 1, nla_len(iter)));
1150 			break;
1151 		case ATTR_WIFI_LOGGER_VERBOSE_LEVEL:
1152 			log_level = nla_get_u32(iter);
1153 			break;
1154 		case ATTR_WIFI_LOGGER_FLAGS:
1155 			flags = nla_get_u32(iter);
1156 			break;
1157 		case ATTR_WIFI_LOGGER_MAX_INTERVAL_SEC:
1158 			time_intval = nla_get_u32(iter);
1159 			break;
1160 		case ATTR_WIFI_LOGGER_MIN_DATA_SIZE:
1161 			threshold = nla_get_u32(iter);
1162 			break;
1163 		default:
1164 			PRINTM(MERROR, "Unknown type: %d\n", type);
1165 			ret = -EINVAL;
1166 			goto done;
1167 		}
1168 	}
1169 
1170 	ret = woal_start_logging(priv, ring_name, log_level, flags, time_intval,
1171 				 threshold);
1172 	if (ret < 0)
1173 		PRINTM(MERROR, "Start_logging is failed ret: %d\n", ret);
1174 done:
1175 	LEAVE();
1176 	return ret;
1177 }
1178 
1179 /**
1180  * @brief get log data in ring buffer
1181  *
1182  * @param priv       A pointer to moal_private struct
1183  * @param ring_name  ring name string
1184  *
1185  * @return      0: success  1: fail
1186  */
woal_trigger_get_ring_data(moal_private * priv,char * ring_name)1187 static int woal_trigger_get_ring_data(moal_private *priv, char *ring_name)
1188 {
1189 	int ret = 0;
1190 	int ring_id;
1191 	wifi_ring_buffer *ring_buffer;
1192 
1193 	ENTER();
1194 
1195 	ring_id = woal_get_ring_id_by_name(priv, ring_name);
1196 	if (!VALID_RING(ring_id)) {
1197 		PRINTM(MERROR, "invalid ring_id\n");
1198 		ret = -EINVAL;
1199 		goto done;
1200 	}
1201 
1202 	ring_buffer = (wifi_ring_buffer *)priv->rings[ring_id];
1203 	if (!ring_buffer) {
1204 		PRINTM(MERROR, "invalid ring_buffer\n");
1205 		ret = -EINVAL;
1206 		goto done;
1207 	}
1208 	if (ring_buffer->interval)
1209 		cancel_delayed_work_sync(&ring_buffer->work);
1210 	schedule_delayed_work(&ring_buffer->work, 0);
1211 
1212 done:
1213 	LEAVE();
1214 	return ret;
1215 }
1216 
1217 /**
1218  * @brief vendor command to get ring buffer data
1219  *
1220  * @param wiphy       A pointer to wiphy struct
1221  * @param wdev     A pointer to wireless_dev struct
1222  * @param data     a pointer to data
1223  * @param  len     data length
1224  *
1225  * @return      0: success  1: fail
1226  */
woal_cfg80211_subcmd_get_ring_data(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1227 static int woal_cfg80211_subcmd_get_ring_data(struct wiphy *wiphy,
1228 					      struct wireless_dev *wdev,
1229 					      const void *data, int len)
1230 {
1231 	int ret = 0, rem, type;
1232 	char ring_name[RING_NAME_MAX] = {0};
1233 	const struct nlattr *iter;
1234 	struct net_device *dev = wdev->netdev;
1235 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1236 
1237 	ENTER();
1238 
1239 	nla_for_each_attr (iter, data, len, rem) {
1240 		type = nla_type(iter);
1241 		switch (type) {
1242 		case ATTR_WIFI_LOGGER_RING_ID:
1243 			strncpy(ring_name, nla_data(iter),
1244 				MIN(sizeof(ring_name) - 1, nla_len(iter)));
1245 			break;
1246 		default:
1247 			PRINTM(MERROR, "Unknown type: %d\n", type);
1248 			ret = -EINVAL;
1249 			goto done;
1250 		}
1251 	}
1252 
1253 	ret = woal_trigger_get_ring_data(priv, ring_name);
1254 	if (ret < 0)
1255 		PRINTM(MERROR, "trigger_get_data failed ret:%d\n", ret);
1256 
1257 done:
1258 	LEAVE();
1259 	return ret;
1260 }
1261 
1262 /**
1263  * @brief ring reset
1264  *
1265  * @param priv       A pointer to moal_private struct
1266  * @param ring    A pointer to wifi_ring_buffer
1267  *
1268  * @return    void
1269  */
woal_ring_reset(wifi_ring_buffer * ring)1270 static void woal_ring_reset(wifi_ring_buffer *ring)
1271 {
1272 	ENTER();
1273 	ring->wp = 0;
1274 	ring->rp = 0;
1275 	memset(&(ring->ctrl), 0x00, sizeof(ring->ctrl));
1276 	memset(ring->ring_buf, 0, ring->ring_size);
1277 
1278 	LEAVE();
1279 }
1280 
1281 /**
1282  * @brief get ring buffer entry
1283  *
1284  * @param ring       A pointer to wifi_ring_buffer struct
1285  * @param offset     entry offset
1286  *
1287  * @return     A pointer to wifi_ring_buffer_entry struct
1288  */
woal_get_ring_entry(wifi_ring_buffer * ring,t_u32 offset)1289 static wifi_ring_buffer_entry *woal_get_ring_entry(wifi_ring_buffer *ring,
1290 						   t_u32 offset)
1291 {
1292 	wifi_ring_buffer_entry *entry =
1293 		(wifi_ring_buffer_entry *)(ring->ring_buf + offset);
1294 
1295 	ENTER();
1296 
1297 	if (!entry->entry_size)
1298 		return (wifi_ring_buffer_entry *)ring->ring_buf;
1299 
1300 	LEAVE();
1301 	return entry;
1302 }
1303 
1304 /**
1305  * @brief get next ring buffer entry
1306  *
1307  * @param ring       A pointer to wifi_ring_buffer struct
1308  * @param offset     next entry offset
1309  *
1310  * @return     offset of next entry
1311  */
woal_get_ring_next_entry(wifi_ring_buffer * ring,t_u32 offset)1312 static t_u32 woal_get_ring_next_entry(wifi_ring_buffer *ring, t_u32 offset)
1313 {
1314 	wifi_ring_buffer_entry *entry =
1315 		(wifi_ring_buffer_entry *)(ring->ring_buf + offset);
1316 	wifi_ring_buffer_entry *next_entry = NULL;
1317 
1318 	ENTER();
1319 
1320 	if (!entry->entry_size) {
1321 		entry = (wifi_ring_buffer_entry *)ring->ring_buf;
1322 		LEAVE();
1323 		return ENTRY_LENGTH(entry);
1324 	}
1325 	if ((offset + ENTRY_LENGTH(entry)) >= ring->ring_size) {
1326 		/* move to head */
1327 		LEAVE();
1328 		return 0;
1329 	}
1330 	next_entry = (wifi_ring_buffer_entry *)(ring->ring_buf + offset +
1331 						ENTRY_LENGTH(entry));
1332 	if (!next_entry->entry_size) {
1333 		/* move to head */
1334 		LEAVE();
1335 		return 0;
1336 	}
1337 	LEAVE();
1338 	return offset + ENTRY_LENGTH(entry);
1339 }
1340 
1341 /**
1342  * @brief prepare log data to send to HAL
1343  *
1344  * @param priv       A pointer to moal_private struct
1345  * @param ring_id    ring ID
1346  * @param data       A pointer to data buffer
1347  * @param buf_len    log data length
1348  *
1349  * @return      data length
1350  */
woal_ring_pull_data(moal_private * priv,int ring_id,void * data,t_s32 buf_len)1351 int woal_ring_pull_data(moal_private *priv, int ring_id, void *data,
1352 			t_s32 buf_len)
1353 {
1354 	t_s32 r_len = 0;
1355 	wifi_ring_buffer *ring;
1356 	wifi_ring_buffer_entry *hdr;
1357 	t_s32 buf_left = buf_len;
1358 
1359 	ENTER();
1360 
1361 	ring = (wifi_ring_buffer *)priv->rings[ring_id];
1362 
1363 	/* get a fresh pending length */
1364 	while (buf_left > 0) {
1365 		hdr = woal_get_ring_entry(ring, ring->rp);
1366 		if (buf_left < ENTRY_LENGTH(hdr))
1367 			break;
1368 		moal_memcpy_ext(priv->phandle, data, hdr, ENTRY_LENGTH(hdr),
1369 				buf_left);
1370 		r_len += ENTRY_LENGTH(hdr);
1371 		data += ENTRY_LENGTH(hdr);
1372 		buf_left -= ENTRY_LENGTH(hdr);
1373 		ring->ctrl.read_bytes += ENTRY_LENGTH(hdr);
1374 		if (!buf_left) {
1375 			ring->rp += ENTRY_LENGTH(hdr);
1376 			break;
1377 		}
1378 		ring->rp = woal_get_ring_next_entry(ring, ring->rp);
1379 	}
1380 	PRINTM(MDATA, "Ring pull data: [wp=%d rp=%d] r_len=%d buf_len=%d\n",
1381 	       ring->wp, ring->rp, r_len, buf_len);
1382 
1383 	LEAVE();
1384 	return r_len;
1385 }
1386 
1387 /**
1388  * @brief send vendor event to kernel
1389  *
1390  * @param priv       A pointer to moal_private
1391  * @param event    vendor event
1392  * @param data     a pointer to data
1393  * @param  len     data length
1394  * @param ring_status    A pointer to wifi_ring_buffer status struct
1395  *
1396  * @return      0: success  1: fail
1397  */
woal_ring_buffer_data_vendor_event(moal_private * priv,int ring_id,t_u8 * data,int len,wifi_ring_buffer_status * ring_status)1398 int woal_ring_buffer_data_vendor_event(moal_private *priv, int ring_id,
1399 				       t_u8 *data, int len,
1400 				       wifi_ring_buffer_status *ring_status)
1401 {
1402 	struct wiphy *wiphy = NULL;
1403 	struct sk_buff *skb = NULL;
1404 	int event_id = 0;
1405 	int ret = 0;
1406 
1407 	ENTER();
1408 
1409 	if (!priv || !priv->wdev || !priv->wdev->wiphy) {
1410 		PRINTM(MERROR, "priv is null\n");
1411 		ret = -EINVAL;
1412 		goto done;
1413 	}
1414 	wiphy = priv->wdev->wiphy;
1415 	PRINTM(MEVENT, "%s ring_id:%d\n", __func__, ring_id);
1416 	event_id = woal_get_event_id(event_wifi_logger_ring_buffer_data);
1417 	if (event_max == event_id) {
1418 		PRINTM(MERROR, "Not find this event %d\n", event_id);
1419 		ret = -EINVAL;
1420 		goto done;
1421 	}
1422 
1423 /**allocate skb*/
1424 #if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
1425 	skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev,
1426 					  len + sizeof(wifi_ring_buffer_status),
1427 					  event_id, GFP_ATOMIC);
1428 #else
1429 	skb = cfg80211_vendor_event_alloc(wiphy,
1430 					  len + sizeof(wifi_ring_buffer_status),
1431 					  event_id, GFP_ATOMIC);
1432 #endif
1433 
1434 	if (!skb) {
1435 		PRINTM(MERROR, "allocate memory fail for vendor event\n");
1436 		ret = -ENOMEM;
1437 		goto done;
1438 	}
1439 	nla_put(skb, ATTR_RING_BUFFER_STATUS, sizeof(wifi_ring_buffer_status),
1440 		ring_status);
1441 	DBG_HEXDUMP(MEVT_D, "ring_buffer_data", data, len);
1442 	nla_put(skb, ATTR_RING_BUFFER, len, data);
1443 
1444 	/**send event*/
1445 	cfg80211_vendor_event(skb, GFP_ATOMIC);
1446 
1447 done:
1448 	LEAVE();
1449 	return ret;
1450 }
1451 
1452 /**
1453  * @brief send log data to HAL
1454  *
1455  * @param priv       A pointer to moal_private struct
1456  * @param ring_id    ring ID
1457  * @param data       A pointer to data buffer
1458  * @param len    log data length
1459  * @param ring_status    A pointer to wifi_ring_buffer status struct
1460  *
1461  * @return void
1462  */
woal_ring_data_send(moal_private * priv,int ring_id,const void * data,const t_u32 len,wifi_ring_buffer_status * ring_status)1463 static void woal_ring_data_send(moal_private *priv, int ring_id,
1464 				const void *data, const t_u32 len,
1465 				wifi_ring_buffer_status *ring_status)
1466 {
1467 	struct net_device *ndev = priv->netdev;
1468 
1469 	ENTER();
1470 
1471 	if (!ndev)
1472 		goto done;
1473 	woal_ring_buffer_data_vendor_event(priv, ring_id, (t_u8 *)data, len,
1474 					   ring_status);
1475 
1476 done:
1477 	LEAVE();
1478 }
1479 
1480 /**
1481  * @brief main thread to send log data
1482  *
1483  * @param work       A pointer to work_struct struct
1484  *
1485  * @return void
1486  */
woal_ring_poll_worker(struct work_struct * work)1487 void woal_ring_poll_worker(struct work_struct *work)
1488 {
1489 	struct delayed_work *d_work = to_delayed_work(work);
1490 	wifi_ring_buffer *ring_info =
1491 		container_of(d_work, wifi_ring_buffer, work);
1492 	moal_private *priv = ring_info->priv;
1493 	int ringid = ring_info->ring_id;
1494 	wifi_ring_buffer_status ring_status;
1495 	void *buf = NULL;
1496 	wifi_ring_buffer_entry *hdr;
1497 	t_s32 buflen, rlen;
1498 	unsigned long flags;
1499 
1500 	ENTER();
1501 	if (ring_info->state != RING_ACTIVE) {
1502 		PRINTM(MERROR, "Ring is not active!\n");
1503 		goto exit;
1504 	}
1505 	buf = kmalloc(ring_info->ring_size, GFP_KERNEL);
1506 	if (!buf) {
1507 		PRINTM(MERROR, "Fail to allocate buffer for poll work\n");
1508 		goto exit;
1509 	}
1510 	spin_lock_irqsave(&ring_info->lock, flags);
1511 	memset(&ring_status, 0, sizeof(ring_status));
1512 	woal_get_ring_status(priv, ringid, &ring_status);
1513 	PRINTM(MDATA, "Ring work: ringid %d write %d, read %d, size %d\n",
1514 	       ringid, ring_status.written_bytes, ring_status.read_bytes,
1515 	       ring_status.ring_buffer_byte_size);
1516 	if (ring_status.written_bytes > ring_status.read_bytes) {
1517 		buflen = ring_status.written_bytes - ring_status.read_bytes;
1518 		if (buflen > ring_info->ring_size) {
1519 			PRINTM(MERROR, "Pending data bigger than ring size\n");
1520 			spin_unlock_irqrestore(&ring_info->lock, flags);
1521 			goto exit;
1522 		}
1523 	} else {
1524 		spin_unlock_irqrestore(&ring_info->lock, flags);
1525 		PRINTM(MINFO, "No new records\n");
1526 		goto exit;
1527 	}
1528 
1529 	rlen = woal_ring_pull_data(priv, ringid, buf, buflen);
1530 	spin_unlock_irqrestore(&ring_info->lock, flags);
1531 	hdr = (wifi_ring_buffer_entry *)buf;
1532 	while (rlen > 0) {
1533 		ring_status.read_bytes += ENTRY_LENGTH(hdr);
1534 		woal_ring_data_send(priv, ringid, hdr, ENTRY_LENGTH(hdr),
1535 				    &ring_status);
1536 		rlen -= ENTRY_LENGTH(hdr);
1537 		hdr = (wifi_ring_buffer_entry *)((void *)hdr +
1538 						 ENTRY_LENGTH(hdr));
1539 	}
1540 exit:
1541 	kfree(buf);
1542 	if (ring_info->interval)
1543 		schedule_delayed_work(&ring_info->work, ring_info->interval);
1544 
1545 	LEAVE();
1546 }
1547 
1548 /**
1549  * @brief add log data to ring buffer
1550  *
1551  * @param priv       A pointer to moal_private struct
1552  * @param ring_id    ring ID
1553  * @param hdr        A pointer to wifi_ring_buffer_entry struct
1554  * @param data       A pointer to data buffer
1555  *
1556  * @return      0: success  -1: fail
1557  */
woal_ring_push_data(moal_private * priv,int ring_id,wifi_ring_buffer_entry * hdr,void * data)1558 int woal_ring_push_data(moal_private *priv, int ring_id,
1559 			wifi_ring_buffer_entry *hdr, void *data)
1560 {
1561 	unsigned long flags;
1562 	t_u32 w_len;
1563 	wifi_ring_buffer *ring;
1564 	wifi_ring_buffer_entry *w_entry;
1565 	int ret = 0;
1566 
1567 	ENTER();
1568 
1569 	ring = (wifi_ring_buffer *)priv->rings[ring_id];
1570 
1571 	if (!ring || ring->state != RING_ACTIVE) {
1572 		PRINTM(MERROR, "Ring is not active\n");
1573 		ret = -EINVAL;
1574 		goto done;
1575 	}
1576 
1577 	w_len = ENTRY_LENGTH(hdr);
1578 	if (w_len > ring->ring_size) {
1579 		PRINTM(MERROR, "event size too big =%d\n", w_len);
1580 		ret = -EINVAL;
1581 		goto done;
1582 	}
1583 	spin_lock_irqsave(&ring->lock, flags);
1584 	PRINTM(MDATA, "Ring push data: rp=%d  wp=%d, w_len=%d\n", ring->rp,
1585 	       ring->wp, w_len);
1586 	/* prep the space */
1587 	do {
1588 		if (ring->rp == ring->wp) {
1589 			if (ring->ctrl.read_bytes == ring->ctrl.written_bytes) {
1590 				if (ring->wp)
1591 					woal_ring_reset(ring);
1592 				break;
1593 			} else {
1594 				/* full, we should drop one entry */
1595 				w_entry =
1596 					(wifi_ring_buffer_entry
1597 						 *)(ring->ring_buf + ring->rp);
1598 				ring->rp = woal_get_ring_next_entry(ring,
1599 								    ring->rp);
1600 				ring->ctrl.written_bytes -=
1601 					ENTRY_LENGTH(w_entry);
1602 				memset((u8 *)w_entry, 0, ENTRY_LENGTH(w_entry));
1603 				ring->ctrl.written_records--;
1604 				continue;
1605 			}
1606 		}
1607 		if (ring->rp < ring->wp) {
1608 			if (ring->ring_size - ring->wp >= w_len) {
1609 				break;
1610 			} else if (ring->ring_size - ring->wp < w_len) {
1611 				if (ring->rp == 0) {
1612 					/** drop one entry */
1613 					w_entry = (wifi_ring_buffer_entry
1614 							   *)(ring->ring_buf +
1615 							      ring->rp);
1616 					ring->rp = woal_get_ring_next_entry(
1617 						ring, ring->rp);
1618 					ring->ctrl.written_bytes -=
1619 						ENTRY_LENGTH(w_entry);
1620 					memset((u8 *)w_entry, 0,
1621 					       ENTRY_LENGTH(w_entry));
1622 					ring->ctrl.written_records--;
1623 				}
1624 				ring->wp = 0;
1625 				continue;
1626 			}
1627 		}
1628 		if (ring->rp > ring->wp) {
1629 			if (ring->rp - ring->wp < w_len) {
1630 				/** drop one entry */
1631 				w_entry =
1632 					(wifi_ring_buffer_entry
1633 						 *)(ring->ring_buf + ring->rp);
1634 				ring->rp = woal_get_ring_next_entry(ring,
1635 								    ring->rp);
1636 				ring->ctrl.written_bytes -=
1637 					ENTRY_LENGTH(w_entry);
1638 				memset((u8 *)w_entry, 0, ENTRY_LENGTH(w_entry));
1639 				ring->ctrl.written_records--;
1640 				continue;
1641 			} else {
1642 				break;
1643 			}
1644 		}
1645 	} while (1);
1646 
1647 	if ((ring->wp + w_len) > ring->ring_size ||
1648 	    (ring->ctrl.written_bytes + w_len) > ring->ring_size) {
1649 		PRINTM(MERROR,
1650 		       "Ring push buffer overflow: rp=%d  wp=%d, write_bytes=%d\n",
1651 		       ring->rp, ring->wp, ring->ctrl.written_bytes);
1652 		goto done;
1653 	}
1654 
1655 	w_entry = (wifi_ring_buffer_entry *)(ring->ring_buf + ring->wp);
1656 	/* header */
1657 	moal_memcpy_ext(priv->phandle, w_entry, hdr, RING_ENTRY_SIZE,
1658 			ENTRY_LENGTH(w_entry));
1659 	/* payload */
1660 	moal_memcpy_ext(priv->phandle, (char *)w_entry + RING_ENTRY_SIZE, data,
1661 			w_entry->entry_size, w_entry->entry_size);
1662 	/* update write pointer */
1663 	ring->wp += w_len;
1664 	/* update statistics */
1665 	ring->ctrl.written_records++;
1666 	ring->ctrl.written_bytes += w_len;
1667 	spin_unlock_irqrestore(&ring->lock, flags);
1668 
1669 	PRINTM(MDATA,
1670 	       "Ring push data: wp=%d rp=%d  write_bytes=%d, read_bytes=%d\n",
1671 	       ring->wp, ring->rp, ring->ctrl.written_bytes,
1672 	       ring->ctrl.read_bytes);
1673 
1674 	/* if the current pending size is bigger than threshold */
1675 	if (ring->threshold && (READ_AVAIL_SPACE(ring) >= ring->threshold)) {
1676 		PRINTM(MDATA, "Ring threshold reached\n");
1677 		if (ring->interval)
1678 			cancel_delayed_work_sync(&ring->work);
1679 		schedule_delayed_work(&ring->work, 0);
1680 	}
1681 
1682 done:
1683 	LEAVE();
1684 	return ret;
1685 }
1686 
1687 /**
1688  *  @brief This function will init wifi logger ring buffer
1689  *
1690  *  @param priv          A pointer to moal_private structure
1691  *  @param ring_buff     A pointer to wifi_ring_buffer structure
1692  *  @param ringIdx       Ring buffer ID
1693  *  @param name          Ring buffer name
1694  *  @param ring_sz       Ring buffer size
1695  *
1696  *  @return        0 - success
1697  */
woal_init_ring_buffer_internal(moal_private * priv,void ** ring,t_u16 ringIdx,t_u8 * name,t_u32 ring_sz)1698 static int woal_init_ring_buffer_internal(moal_private *priv, void **ring,
1699 					  t_u16 ringIdx, t_u8 *name,
1700 					  t_u32 ring_sz)
1701 {
1702 	unsigned long flags;
1703 	wifi_ring_buffer *ring_buff;
1704 
1705 	ENTER();
1706 
1707 	*ring = vmalloc(sizeof(wifi_ring_buffer));
1708 	if (!unlikely(*ring)) {
1709 		PRINTM(MERROR, "WiFi Logger: ring alloc failed\n");
1710 		goto done;
1711 	}
1712 	memset(*ring, 0, sizeof(wifi_ring_buffer));
1713 	ring_buff = (wifi_ring_buffer *)*ring;
1714 
1715 	ring_buff->ring_buf = vmalloc(ring_sz);
1716 	if (!unlikely(ring_buff->ring_buf)) {
1717 		PRINTM(MERROR, "WiFi Logger: ring buffer data alloc failed\n");
1718 		vfree(ring_buff);
1719 		*ring = NULL;
1720 		goto done;
1721 	}
1722 	memset(ring_buff->ring_buf, 0, ring_sz);
1723 	spin_lock_init(&ring_buff->lock);
1724 	spin_lock_irqsave(&ring_buff->lock, flags);
1725 	ring_buff->rp = ring_buff->wp = 0;
1726 	INIT_DELAYED_WORK(&ring_buff->work, woal_ring_poll_worker);
1727 	moal_memcpy_ext(priv->phandle, ring_buff->name, name, strlen(name),
1728 			RING_NAME_MAX - 1);
1729 	ring_buff->name[RING_NAME_MAX - 1] = 0;
1730 	ring_buff->ring_id = ringIdx;
1731 	ring_buff->ring_size = ring_sz;
1732 	ring_buff->state = RING_SUSPEND;
1733 	ring_buff->threshold = ring_buff->ring_size / 2;
1734 	ring_buff->priv = priv;
1735 	spin_unlock_irqrestore(&ring_buff->lock, flags);
1736 done:
1737 	LEAVE();
1738 	return 0;
1739 }
1740 
1741 /**
1742  * @brief init each ring in moal_private
1743  *
1744  * @param priv       A pointer to moal_private struct
1745  *
1746  * @return      data length
1747  */
woal_init_ring_buffer(moal_private * priv)1748 static int woal_init_ring_buffer(moal_private *priv)
1749 {
1750 	ENTER();
1751 	woal_init_ring_buffer_internal(priv, &priv->rings[VERBOSE_RING_ID],
1752 				       VERBOSE_RING_ID, VERBOSE_RING_NAME,
1753 				       DEFAULT_RING_BUFFER_SIZE);
1754 	woal_init_ring_buffer_internal(priv, &priv->rings[EVENT_RING_ID],
1755 				       EVENT_RING_ID, EVENT_RING_NAME,
1756 				       DEFAULT_RING_BUFFER_SIZE);
1757 	LEAVE();
1758 	return 0;
1759 }
1760 
1761 /**
1762  * @brief deinit each ring in moal_private
1763  *
1764  * @param priv       A pointer to moal_private struct
1765  *
1766  * @return      data length
1767  */
woal_deinit_ring_buffer(moal_private * priv)1768 static int woal_deinit_ring_buffer(moal_private *priv)
1769 {
1770 	int i;
1771 	enum ring_state ring_state = RING_STOP;
1772 	unsigned long lock_flags = 0;
1773 	wifi_ring_buffer *ring_buff;
1774 
1775 	ENTER();
1776 
1777 	for (i = 0; i < RING_ID_MAX; i++) {
1778 		ring_buff = (wifi_ring_buffer *)priv->rings[i];
1779 		if (!ring_buff)
1780 			continue;
1781 		spin_lock_irqsave(&ring_buff->lock, lock_flags);
1782 		ring_state = ring_buff->state;
1783 		if (ring_state == RING_ACTIVE) {
1784 			ring_buff->state = RING_STOP;
1785 			ring_buff->interval = 0;
1786 		}
1787 		spin_unlock_irqrestore(&ring_buff->lock, lock_flags);
1788 		if (ring_state == RING_ACTIVE)
1789 			cancel_delayed_work_sync(&ring_buff->work);
1790 		vfree(ring_buff->ring_buf);
1791 		ring_buff->ring_buf = NULL;
1792 		vfree(ring_buff);
1793 		priv->rings[i] = NULL;
1794 	}
1795 
1796 	LEAVE();
1797 	return 0;
1798 }
1799 
1800 /**
1801  * @brief add log data to ring buffer
1802  *
1803  * @param priv       A pointer to moal_private struct
1804  * @param ring_id    ring ID
1805  * @param hdr        A pointer to wifi_ring_buffer_entry struct
1806  * @param data       A pointer to data buffer
1807  *
1808  * @return      0: success  -1: fail
1809  */
woal_ring_event_logger(moal_private * priv,int ring_id,pmlan_event pmevent)1810 int woal_ring_event_logger(moal_private *priv, int ring_id, pmlan_event pmevent)
1811 {
1812 	t_u8 event_buf[100] = {0};
1813 	wifi_ring_buffer_driver_connectivity_event *connectivity_event;
1814 	tlv_log *tlv;
1815 	t_u8 *pos;
1816 	wifi_ring_buffer_entry msg_hdr;
1817 	wifi_ring_buffer *ring;
1818 
1819 	ENTER();
1820 	ring = (wifi_ring_buffer *)priv->rings[ring_id];
1821 
1822 	if (!ring || ring->state != RING_ACTIVE) {
1823 		PRINTM(MINFO, "Ring is not active\n");
1824 		goto done;
1825 	}
1826 
1827 	switch (pmevent->event_id) {
1828 	case MLAN_EVENT_ID_DRV_ASSOC_SUCC_LOGGER:
1829 		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1830 			assoc_logger_data *pbss_desc =
1831 				(assoc_logger_data *)pmevent->event_buf;
1832 			memset(&msg_hdr, 0, sizeof(msg_hdr));
1833 			msg_hdr.flags |= RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP;
1834 			msg_hdr.type = ENTRY_TYPE_CONNECT_EVENT;
1835 			connectivity_event =
1836 				(wifi_ring_buffer_driver_connectivity_event *)
1837 					event_buf;
1838 			connectivity_event->event = WIFI_EVENT_ASSOC_COMPLETE;
1839 			pos = (t_u8 *)connectivity_event->tlvs;
1840 
1841 			tlv = (tlv_log *)pos;
1842 			tlv->tag = WIFI_TAG_VENDOR_SPECIFIC;
1843 			tlv->length = MLAN_MAC_ADDR_LENGTH / 2;
1844 			moal_memcpy_ext(priv->phandle, tlv->value,
1845 					pbss_desc->oui, tlv->length,
1846 					sizeof(event_buf) -
1847 						(tlv->value - event_buf));
1848 			msg_hdr.entry_size += tlv->length + TLV_LOG_HEADER_LEN;
1849 			pos = pos + tlv->length + TLV_LOG_HEADER_LEN;
1850 
1851 			tlv = (tlv_log *)pos;
1852 			tlv->tag = WIFI_TAG_BSSID;
1853 			tlv->length = sizeof(pbss_desc->bssid);
1854 			moal_memcpy_ext(
1855 				priv->phandle, tlv->value, pbss_desc->bssid,
1856 				sizeof(pbss_desc->bssid),
1857 				sizeof(event_buf) - (tlv->value - event_buf));
1858 			msg_hdr.entry_size += tlv->length + TLV_LOG_HEADER_LEN;
1859 			pos = pos + tlv->length + TLV_LOG_HEADER_LEN;
1860 
1861 			tlv = (tlv_log *)pos;
1862 			tlv->tag = WIFI_TAG_SSID;
1863 			tlv->length = strlen(pbss_desc->ssid);
1864 			moal_memcpy_ext(priv->phandle, tlv->value,
1865 					pbss_desc->ssid, tlv->length,
1866 					sizeof(event_buf) -
1867 						(tlv->value - event_buf));
1868 			msg_hdr.entry_size += tlv->length + TLV_LOG_HEADER_LEN;
1869 			pos = pos + tlv->length + TLV_LOG_HEADER_LEN;
1870 
1871 			if (pbss_desc->rssi) {
1872 				tlv = (tlv_log *)pos;
1873 				tlv->tag = WIFI_TAG_RSSI;
1874 				tlv->length = sizeof(pbss_desc->rssi);
1875 				moal_memcpy_ext(
1876 					priv->phandle, tlv->value,
1877 					&pbss_desc->rssi, tlv->length,
1878 					sizeof(event_buf) -
1879 						(tlv->value - event_buf));
1880 				msg_hdr.entry_size +=
1881 					tlv->length + TLV_LOG_HEADER_LEN;
1882 				pos = pos + tlv->length + TLV_LOG_HEADER_LEN;
1883 			}
1884 			if (pbss_desc->channel) {
1885 				tlv = (tlv_log *)pos;
1886 				tlv->tag = WIFI_TAG_CHANNEL;
1887 				tlv->length = sizeof(pbss_desc->channel);
1888 				moal_memcpy_ext(
1889 					priv->phandle, tlv->value,
1890 					&pbss_desc->channel,
1891 					sizeof(pbss_desc->channel),
1892 					sizeof(event_buf) -
1893 						(tlv->value - event_buf));
1894 				msg_hdr.entry_size +=
1895 					tlv->length + TLV_LOG_HEADER_LEN;
1896 			}
1897 			msg_hdr.entry_size += sizeof(connectivity_event->event);
1898 			DBG_HEXDUMP(MCMD_D, "connectivity_event",
1899 				    (t_u8 *)connectivity_event,
1900 				    msg_hdr.entry_size);
1901 			woal_ring_push_data(priv, ring_id, &msg_hdr,
1902 					    connectivity_event);
1903 		}
1904 		break;
1905 	case MLAN_EVENT_ID_DRV_ASSOC_FAILURE_LOGGER:
1906 		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1907 			int status_code = *(int *)pmevent->event_buf;
1908 
1909 			memset(&msg_hdr, 0, sizeof(msg_hdr));
1910 			msg_hdr.flags |= RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP;
1911 			msg_hdr.type = ENTRY_TYPE_CONNECT_EVENT;
1912 			connectivity_event =
1913 				(wifi_ring_buffer_driver_connectivity_event *)
1914 					event_buf;
1915 			connectivity_event->event = WIFI_EVENT_ASSOC_COMPLETE;
1916 			pos = (t_u8 *)connectivity_event->tlvs;
1917 			tlv = (tlv_log *)pos;
1918 			tlv->tag = WIFI_TAG_STATUS;
1919 			tlv->length = sizeof(status_code);
1920 			moal_memcpy_ext(priv->phandle, tlv->value, &status_code,
1921 					sizeof(status_code),
1922 					sizeof(event_buf) -
1923 						(tlv->value - event_buf));
1924 			msg_hdr.entry_size += tlv->length + 4;
1925 			msg_hdr.entry_size += sizeof(connectivity_event->event);
1926 			woal_ring_push_data(priv, ring_id, &msg_hdr,
1927 					    connectivity_event);
1928 		}
1929 		break;
1930 	case MLAN_EVENT_ID_DRV_DISCONNECT_LOGGER:
1931 		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1932 			t_u16 reason_code = *(t_u16 *)pmevent->event_buf;
1933 
1934 			memset(&msg_hdr, 0, sizeof(msg_hdr));
1935 			msg_hdr.flags |= RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP;
1936 			msg_hdr.type = ENTRY_TYPE_CONNECT_EVENT;
1937 			connectivity_event =
1938 				(wifi_ring_buffer_driver_connectivity_event *)
1939 					event_buf;
1940 			connectivity_event->event = WIFI_EVENT_ASSOC_COMPLETE;
1941 			pos = (t_u8 *)connectivity_event->tlvs;
1942 			tlv = (tlv_log *)pos;
1943 			tlv->tag = WIFI_TAG_REASON_CODE;
1944 			tlv->length = sizeof(reason_code);
1945 			moal_memcpy_ext(priv->phandle, tlv->value, &reason_code,
1946 					sizeof(reason_code),
1947 					sizeof(event_buf) -
1948 						(tlv->value - event_buf));
1949 			msg_hdr.entry_size += tlv->length + 4;
1950 			msg_hdr.entry_size += sizeof(connectivity_event->event);
1951 			woal_ring_push_data(priv, ring_id, &msg_hdr,
1952 					    connectivity_event);
1953 		}
1954 		break;
1955 	default:
1956 		break;
1957 	}
1958 done:
1959 	LEAVE();
1960 	return 0;
1961 }
1962 
1963 /**
1964  * @brief send vendor event to kernel
1965  *
1966  * @param priv               A pointer to moal_private struct
1967  * @param wake_reason        wake_reason
1968  *
1969  * @return      0: success  1: fail
1970  */
woal_wake_reason_vendor_event(moal_private * priv,mlan_ds_hs_wakeup_reason wake_reason)1971 int woal_wake_reason_vendor_event(moal_private *priv,
1972 				  mlan_ds_hs_wakeup_reason wake_reason)
1973 {
1974 	struct wiphy *wiphy = NULL;
1975 	struct sk_buff *skb = NULL;
1976 	int event_id = 0;
1977 	int ret = 0;
1978 
1979 	ENTER();
1980 
1981 	if (!priv || !priv->wdev || !priv->wdev->wiphy) {
1982 		PRINTM(MERROR, "priv is null\n");
1983 		ret = -EINVAL;
1984 		goto done;
1985 	}
1986 	wiphy = priv->wdev->wiphy;
1987 
1988 	event_id = woal_get_event_id(event_wake_reason_report);
1989 	if (event_max == event_id) {
1990 		PRINTM(MERROR, "Not find this event %d\n", event_id);
1991 		ret = MLAN_STATUS_FAILURE;
1992 		goto done;
1993 	}
1994 
1995 /**allocate skb*/
1996 #if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
1997 	skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev,
1998 					  sizeof(wake_reason.hs_wakeup_reason),
1999 					  event_id, GFP_ATOMIC);
2000 #else
2001 	skb = cfg80211_vendor_event_alloc(wiphy,
2002 					  sizeof(wake_reason.hs_wakeup_reason),
2003 					  event_id, GFP_ATOMIC);
2004 #endif
2005 
2006 	if (!skb) {
2007 		PRINTM(MERROR, "allocate memory fail for vendor event\n");
2008 		ret = -ENOMEM;
2009 		goto done;
2010 	}
2011 
2012 	PRINTM(MINFO, "wake_reason.hs_wakeup_reason = %d\n",
2013 	       wake_reason.hs_wakeup_reason);
2014 	nla_put_u16(skb, ATTR_WAKE_REASON_STAT, wake_reason.hs_wakeup_reason);
2015 	/**send event*/
2016 	cfg80211_vendor_event(skb, GFP_ATOMIC);
2017 
2018 done:
2019 	PRINTM(MINFO, "wake reason vendor event ret %d\n", ret);
2020 	LEAVE();
2021 	return ret;
2022 }
2023 
2024 /**
2025  * @brief log wake reason
2026  *
2027  * @param priv       A pointer to moal_private struct
2028  * @param wake_reason    wake_reason
2029  *
2030  * @return      0: success  -1: fail
2031  */
woal_wake_reason_logger(moal_private * priv,mlan_ds_hs_wakeup_reason wake_reason)2032 int woal_wake_reason_logger(moal_private *priv,
2033 			    mlan_ds_hs_wakeup_reason wake_reason)
2034 {
2035 	int ret = 0;
2036 
2037 	ENTER();
2038 
2039 	ret = woal_wake_reason_vendor_event(priv, wake_reason);
2040 
2041 	LEAVE();
2042 	return ret;
2043 }
2044 
2045 /**
2046  * @brief vendor command to start packet fate monitor
2047  *
2048  * @param wiphy       A pointer to wiphy struct
2049  * @param wdev     A pointer to wireless_dev struct
2050  * @param data     a pointer to data
2051  * @param  len     data length
2052  *
2053  * @return      0: success  1: fail
2054  */
2055 static int
woal_cfg80211_subcmd_start_packet_fate_monitor(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2056 woal_cfg80211_subcmd_start_packet_fate_monitor(struct wiphy *wiphy,
2057 					       struct wireless_dev *wdev,
2058 					       const void *data, int data_len)
2059 {
2060 	struct sk_buff *skb = NULL;
2061 	t_u32 reply_len = 0;
2062 	int ret = 0;
2063 
2064 	/* TODO: Tune pkt fate monitor for TP, Disabling it for now */
2065 	// struct net_device *dev = wdev->netdev;
2066 	// moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2067 
2068 	ENTER();
2069 
2070 	/** Allocate skb for cmd reply*/
2071 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
2072 	if (!skb) {
2073 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
2074 		ret = -ENOMEM;
2075 		goto done;
2076 	}
2077 
2078 	/* TODO: Tune pkt fate monitor for TP, Disabling it for now */
2079 	// priv->pkt_fate_monitor_enable = MTRUE;
2080 
2081 	ret = cfg80211_vendor_cmd_reply(skb);
2082 
2083 	if (ret)
2084 		PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
2085 done:
2086 	LEAVE();
2087 	return ret;
2088 }
2089 
2090 /**
2091  * @brief send vendor event to kernel
2092  *
2093  * @param priv               A pointer to moal_private struct
2094  * @param pkt_type           tx or rx
2095  * @param fate               packet fate
2096  * @param payload_type       type of payload
2097  * @param drv_ts_usec        driver time in usec
2098  * @param fw_ts_usec         firmware time in usec
2099  * @param data               frame data
2100  * @param len                frame data len
2101  *
2102  * @return      0: success  1: fail
2103  */
woal_packet_fate_vendor_event(moal_private * priv,packet_fate_packet_type pkt_type,t_u8 fate,frame_type payload_type,t_u32 drv_ts_usec,t_u32 fw_ts_usec,t_u8 * data,t_u32 len)2104 int woal_packet_fate_vendor_event(moal_private *priv,
2105 				  packet_fate_packet_type pkt_type, t_u8 fate,
2106 				  frame_type payload_type, t_u32 drv_ts_usec,
2107 				  t_u32 fw_ts_usec, t_u8 *data, t_u32 len)
2108 {
2109 	struct wiphy *wiphy = NULL;
2110 	struct sk_buff *skb = NULL;
2111 	int event_id = 0;
2112 	int ret = 0;
2113 	PACKET_FATE_REPORT fate_report;
2114 
2115 	ENTER();
2116 
2117 	if (!priv || !priv->wdev || !priv->wdev->wiphy) {
2118 		PRINTM(MERROR, "priv is null\n");
2119 		ret = -EINVAL;
2120 		goto done;
2121 	}
2122 	wiphy = priv->wdev->wiphy;
2123 
2124 	event_id = woal_get_event_id(event_packet_fate_monitor);
2125 	if (event_max == event_id) {
2126 		PRINTM(MERROR, "Not find this event %d\n", event_id);
2127 		ret = MLAN_STATUS_FAILURE;
2128 		goto done;
2129 	}
2130 
2131 /**allocate skb*/
2132 #if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
2133 	skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev,
2134 					  len + sizeof(PACKET_FATE_REPORT),
2135 					  event_id, GFP_ATOMIC);
2136 #else
2137 	skb = cfg80211_vendor_event_alloc(
2138 		wiphy, len + sizeof(PACKET_FATE_REPORT), event_id, GFP_ATOMIC);
2139 #endif
2140 
2141 	if (!skb) {
2142 		PRINTM(MERROR, "allocate memory fail for vendor event\n");
2143 		ret = -ENOMEM;
2144 		goto done;
2145 	}
2146 
2147 	memset(&fate_report, 0, sizeof(PACKET_FATE_REPORT));
2148 	if (pkt_type == PACKET_TYPE_TX) {
2149 		fate_report.u.tx_report_i.fate = fate;
2150 		fate_report.u.tx_report_i.frame_inf.payload_type = payload_type;
2151 		fate_report.u.tx_report_i.frame_inf.driver_timestamp_usec =
2152 			drv_ts_usec;
2153 		fate_report.u.tx_report_i.frame_inf.firmware_timestamp_usec =
2154 			fw_ts_usec;
2155 		fate_report.u.tx_report_i.frame_inf.frame_len = len;
2156 		nla_put(skb, ATTR_PACKET_FATE_TX, sizeof(PACKET_FATE_REPORT),
2157 			&fate_report);
2158 	} else {
2159 		fate_report.u.rx_report_i.fate = fate;
2160 		fate_report.u.rx_report_i.frame_inf.payload_type = payload_type;
2161 		fate_report.u.rx_report_i.frame_inf.driver_timestamp_usec =
2162 			drv_ts_usec;
2163 		fate_report.u.rx_report_i.frame_inf.firmware_timestamp_usec =
2164 			fw_ts_usec;
2165 		fate_report.u.rx_report_i.frame_inf.frame_len = len;
2166 		nla_put(skb, ATTR_PACKET_FATE_RX, sizeof(PACKET_FATE_REPORT),
2167 			&fate_report);
2168 	}
2169 	DBG_HEXDUMP(MCMD_D, "fate_report", (t_u8 *)&fate_report,
2170 		    sizeof(PACKET_FATE_REPORT));
2171 
2172 	nla_put(skb, ATTR_PACKET_FATE_DATA, len, data);
2173 	DBG_HEXDUMP(MCMD_D, "packet_fate_data", data, len);
2174 
2175 	/**send event*/
2176 	cfg80211_vendor_event(skb, GFP_ATOMIC);
2177 
2178 done:
2179 	PRINTM(MINFO, "packet fate vendor event ret %d\n", ret);
2180 	LEAVE();
2181 	return ret;
2182 }
2183 
2184 /**
2185  * @brief log packet fate
2186  *
2187  * @param priv               A pointer to moal_private struct
2188  * @param pkt_type           tx or rx
2189  * @param fate               packet fate
2190  * @param payload_type       type of payload
2191  * @param drv_ts_usec        driver time in usec
2192  * @param fw_ts_usec         firmware time in usec
2193  * @param data               frame data
2194  * @param len                frame data len
2195  *
2196  * @return      0: success  -1: fail
2197  */
woal_packet_fate_monitor(moal_private * priv,packet_fate_packet_type pkt_type,t_u8 fate,frame_type payload_type,t_u32 drv_ts_usec,t_u32 fw_ts_usec,t_u8 * data,t_u32 len)2198 int woal_packet_fate_monitor(moal_private *priv,
2199 			     packet_fate_packet_type pkt_type, t_u8 fate,
2200 			     frame_type payload_type, t_u32 drv_ts_usec,
2201 			     t_u32 fw_ts_usec, t_u8 *data, t_u32 len)
2202 {
2203 	int ret = 0;
2204 
2205 	ENTER();
2206 
2207 	if (priv->pkt_fate_monitor_enable)
2208 		ret = woal_packet_fate_vendor_event(priv, pkt_type, fate,
2209 						    payload_type, drv_ts_usec,
2210 						    fw_ts_usec, data, len);
2211 
2212 	PRINTM(MINFO, "packet fate monitor ret %d\n", ret);
2213 	LEAVE();
2214 	return ret;
2215 }
2216 
2217 /**
2218  * @brief init packet_filter in moal_private
2219  *
2220  * @param priv       A pointer to moal_private struct
2221  *
2222  * @return      0: success  -1: fail
2223  */
woal_init_packet_filter(moal_private * priv)2224 static int woal_init_packet_filter(moal_private *priv)
2225 {
2226 	int ret = 0;
2227 	packet_filter *pkt_filter = NULL;
2228 
2229 	ENTER();
2230 
2231 	pkt_filter = vmalloc(sizeof(packet_filter));
2232 	if (!unlikely(pkt_filter)) {
2233 		PRINTM(MERROR, "WiFi Logger: packet_filter alloc failed\n");
2234 		ret = -ENOMEM;
2235 		goto done;
2236 	}
2237 
2238 	memset(pkt_filter, 0, sizeof(packet_filter));
2239 
2240 	spin_lock_init(&pkt_filter->lock);
2241 	pkt_filter->packet_filter_max_len = PACKET_FILTER_MAX_LEN;
2242 	pkt_filter->packet_filter_len = 0;
2243 	pkt_filter->packet_filter_version = APF_VERSION;
2244 	pkt_filter->state = PACKET_FILTER_STATE_STOP;
2245 
2246 	priv->packet_filter = pkt_filter;
2247 
2248 done:
2249 	LEAVE();
2250 	return ret;
2251 }
2252 
2253 /**
2254  * @brief deinit packet_filter in moal_private
2255  *
2256  * @param priv       A pointer to moal_private struct
2257  *
2258  * @return      0: success  -1: fail
2259  */
woal_deinit_packet_filter(moal_private * priv)2260 static int woal_deinit_packet_filter(moal_private *priv)
2261 {
2262 	int ret = 0;
2263 	packet_filter *pkt_filter = NULL;
2264 	unsigned long flags;
2265 
2266 	ENTER();
2267 
2268 	pkt_filter = priv->packet_filter;
2269 
2270 	if (!unlikely(pkt_filter))
2271 		goto done;
2272 
2273 	spin_lock_irqsave(&pkt_filter->lock, flags);
2274 	pkt_filter->state = PACKET_FILTER_STATE_INIT;
2275 	spin_unlock_irqrestore(&pkt_filter->lock, flags);
2276 
2277 	vfree(pkt_filter);
2278 	priv->packet_filter = NULL;
2279 
2280 done:
2281 	LEAVE();
2282 	return ret;
2283 }
2284 
2285 /**
2286  * @brief vendor command to set packet filter
2287  *
2288  * @param wiphy       A pointer to wiphy struct
2289  * @param wdev     A pointer to wireless_dev struct
2290  * @param data     a pointer to data
2291  * @param  len     data length
2292  *
2293  * @return      0: success  1: fail
2294  */
woal_cfg80211_subcmd_set_packet_filter(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2295 static int woal_cfg80211_subcmd_set_packet_filter(struct wiphy *wiphy,
2296 						  struct wireless_dev *wdev,
2297 						  const void *data, int len)
2298 {
2299 	struct net_device *dev = wdev->netdev;
2300 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2301 	int ret = 0, rem, type;
2302 	const struct nlattr *iter;
2303 	packet_filter *pkt_filter = NULL;
2304 	t_u32 packet_filter_len = 0;
2305 	unsigned long flags;
2306 
2307 	ENTER();
2308 	pkt_filter = priv->packet_filter;
2309 	if (!unlikely(pkt_filter) ||
2310 	    pkt_filter->state == PACKET_FILTER_STATE_INIT) {
2311 		PRINTM(MERROR, "packet_filter not init\n");
2312 		ret = -EINVAL;
2313 		goto done;
2314 	}
2315 
2316 	nla_for_each_attr (iter, data, len, rem) {
2317 		type = nla_type(iter);
2318 		switch (type) {
2319 		case ATTR_PACKET_FILTER_TOTAL_LENGTH:
2320 			packet_filter_len = nla_get_u32(iter);
2321 			if (packet_filter_len >
2322 			    pkt_filter->packet_filter_max_len) {
2323 				PRINTM(MERROR,
2324 				       "packet_filter_len exceed max\n");
2325 				ret = -EINVAL;
2326 				goto done;
2327 			}
2328 			break;
2329 		case ATTR_PACKET_FILTER_PROGRAM:
2330 			spin_lock_irqsave(&pkt_filter->lock, flags);
2331 			strncpy(pkt_filter->packet_filter_program,
2332 				nla_data(iter),
2333 				MIN(packet_filter_len, nla_len(iter)));
2334 			pkt_filter->packet_filter_len =
2335 				MIN(packet_filter_len, nla_len(iter));
2336 			pkt_filter->state = PACKET_FILTER_STATE_START;
2337 			spin_unlock_irqrestore(&pkt_filter->lock, flags);
2338 			DBG_HEXDUMP(MDAT_D, "packet_filter_program",
2339 				    pkt_filter->packet_filter_program,
2340 				    pkt_filter->packet_filter_len);
2341 			break;
2342 		default:
2343 			PRINTM(MERROR, "Unknown type: %d\n", type);
2344 			ret = -EINVAL;
2345 			goto done;
2346 		}
2347 	}
2348 
2349 	if (ret)
2350 		PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
2351 done:
2352 	LEAVE();
2353 	return ret;
2354 }
2355 
2356 /**
2357  * @brief vendor command to get packet filter capability
2358  *
2359  * @param wiphy       A pointer to wiphy struct
2360  * @param wdev     A pointer to wireless_dev struct
2361  * @param data     a pointer to data
2362  * @param  len     data length
2363  *
2364  * @return      0: success  1: fail
2365  */
woal_cfg80211_subcmd_get_packet_filter_capability(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)2366 static int woal_cfg80211_subcmd_get_packet_filter_capability(
2367 	struct wiphy *wiphy, struct wireless_dev *wdev, const void *data,
2368 	int data_len)
2369 {
2370 	struct net_device *dev = wdev->netdev;
2371 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2372 	struct sk_buff *skb = NULL;
2373 	t_u32 reply_len = 0;
2374 	int ret = 0;
2375 	packet_filter *pkt_filter;
2376 
2377 	ENTER();
2378 	pkt_filter = priv->packet_filter;
2379 	if (!unlikely(pkt_filter)) {
2380 		PRINTM(MERROR, "packet_filter not init\n");
2381 		ret = -EINVAL;
2382 		goto done;
2383 	}
2384 
2385 	reply_len = sizeof(pkt_filter->packet_filter_version) +
2386 		    sizeof(pkt_filter->packet_filter_max_len);
2387 	/** Allocate skb for cmd reply*/
2388 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, reply_len);
2389 	if (!skb) {
2390 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
2391 		ret = -ENOMEM;
2392 		goto done;
2393 	}
2394 
2395 	if (nla_put_u32(skb, ATTR_PACKET_FILTER_VERSION,
2396 			pkt_filter->packet_filter_version) ||
2397 	    nla_put_u32(skb, ATTR_PACKET_FILTER_MAX_LEN,
2398 			pkt_filter->packet_filter_max_len)) {
2399 		PRINTM(MERROR, "nla_put failed!\n");
2400 		kfree_skb(skb);
2401 		ret = -ENOMEM;
2402 		goto done;
2403 	}
2404 
2405 	ret = cfg80211_vendor_cmd_reply(skb);
2406 
2407 	if (ret)
2408 		PRINTM(MERROR, "Vendor command reply failed ret = %d\n", ret);
2409 done:
2410 	LEAVE();
2411 	return ret;
2412 }
2413 
2414 /**
2415  * Runs a packet filtering program over a packet.
2416  *
2417  * @param program the program bytecode.
2418  * @param program_len the length of {@code apf_program} in bytes.
2419  * @param packet the packet bytes, starting from the 802.3 header and not
2420  *               including any CRC bytes at the end.
2421  * @param packet_len the length of {@code packet} in bytes.
2422  * @param filter_age the number of seconds since the filter was programmed.
2423  *
2424  * @return non-zero if packet should be passed to AP, zero if
2425  *         packet should be dropped.
2426  */
process_packet(const t_u8 * program,t_u32 program_len,const t_u8 * packet,t_u32 packet_len,t_u32 filter_age)2427 int process_packet(const t_u8 *program, t_u32 program_len, const t_u8 *packet,
2428 		   t_u32 packet_len, t_u32 filter_age)
2429 {
2430 	/* Program counter */
2431 	t_u32 pc = 0;
2432 	/* Memory slot values. */
2433 	t_u32 mem[MEM_ITEMS] = {};
2434 	/* Register values. */
2435 	t_u32 reg[2] = {};
2436 	/* Number of instructions remaining to execute. This is done to make
2437 	 * sure there is upper bound on execution time. It should never be hit
2438 	 * and is only for safety. Initialize to the number of bytes in the
2439 	 * program which is an
2440 	 * upper bound on the number of instructions in the program.
2441 	 */
2442 	t_u32 instructions_left = program_len;
2443 
2444 	t_u8 bytecode;
2445 	t_u32 opcode;
2446 	t_u32 reg_num;
2447 	t_u32 len_field;
2448 	t_u32 imm_len;
2449 	t_u32 end_offs;
2450 	t_u32 val = 0;
2451 	t_u32 last_pkt_offs;
2452 	t_u32 imm = 0;
2453 	int32_t sign_imm = 0;
2454 	t_u32 offs = 0;
2455 	t_u32 i;
2456 	t_u32 load_size;
2457 
2458 /* Is offset within program bounds? */
2459 #define WITHIN_PROGRAM_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < program_len)
2460 /* Is offset within packet bounds? */
2461 #define WITHIN_PACKET_BOUNDS(p) (ENFORCE_UNSIGNED(p) && (p) < packet_len)
2462 /* Verify an internal condition and accept packet if it fails. */
2463 #define ASSERT_RETURN(c)                                                       \
2464 	do {                                                                   \
2465 		if (!(c))                                                      \
2466 			return PASS_PKT;                                       \
2467 	} while (0)
2468 /* If not within program bounds, Accept the packet */
2469 #define ASSERT_WITHIN_PROGRAM_BOUNDS(p) ASSERT_RETURN(WITHIN_PROGRAM_BOUNDS(p))
2470 /* If not within packet bounds, Accept the packet */
2471 #define ASSERT_WITHIN_PKT_BOUNDS(p) ASSERT_RETURN(WITHIN_PACKET_BOUNDS(p))
2472 /* If not within program or not ahead of program counter, Accept the packet */
2473 #define ASSERT_FORWARD_WITHIN_PROGRAM(p)                                       \
2474 	ASSERT_RETURN(WITHIN_PROGRAM_BOUNDS(p) && (p) >= pc)
2475 
2476 	/* Fill in pre-filled memory slot values. */
2477 	mem[MEM_OFFSET_PKT_SIZE] = packet_len;
2478 	mem[MEM_OFFSET_FILTER_AGE] = filter_age;
2479 	ASSERT_WITHIN_PKT_BOUNDS(APF_FRAME_HEADER_SIZE);
2480 
2481 	/* Only populate if IP version is IPv4. */
2482 	if ((packet[APF_FRAME_HEADER_SIZE] & 0xf0) == 0x40) {
2483 		mem[MEM_OFFSET_IPV4_HEADER_SIZE] =
2484 			(packet[APF_FRAME_HEADER_SIZE] & 15) * 4;
2485 	}
2486 
2487 	do {
2488 		if (pc == program_len)
2489 			return PASS_PKT;
2490 		else if (pc == (program_len + 1))
2491 			return DROP_PKT;
2492 		ASSERT_WITHIN_PROGRAM_BOUNDS(pc);
2493 		bytecode = program[pc++];
2494 		opcode = GET_OPCODE(bytecode);
2495 		reg_num = GET_REGISTER(bytecode);
2496 
2497 		/* All instructions have immediate fields, so load them now. */
2498 		len_field = GET_IMM_LENGTH(bytecode);
2499 		imm = 0;
2500 		sign_imm = 0;
2501 
2502 #define REG (reg[reg_num])
2503 #define OTHER_REG (reg[reg_num ^ 1])
2504 
2505 		if (len_field) {
2506 			imm_len = 1 << (len_field - 1);
2507 			ASSERT_FORWARD_WITHIN_PROGRAM(pc + imm_len - 1);
2508 			for (i = 0; i < imm_len; i++)
2509 				imm = (imm << 8) | program[pc++];
2510 			/* Sign extend imm into signed_imm. */
2511 			sign_imm = imm << ((4 - imm_len) * 8);
2512 			sign_imm >>= (4 - imm_len) * 8;
2513 		}
2514 		switch (opcode) {
2515 		case NXP_LDB_OPCODE:
2516 		case NXP_LDH_OPCODE:
2517 		case NXP_LDW_OPCODE:
2518 		case NXP_LDBX_OPCODE:
2519 		case NXP_LDHX_OPCODE:
2520 		case NXP_LDWX_OPCODE: {
2521 			offs = imm;
2522 			if (opcode >= NXP_LDBX_OPCODE) {
2523 				/* Note: this can overflow and actually decrease
2524 				 * offs.
2525 				 */
2526 				offs += reg[1];
2527 			}
2528 			ASSERT_WITHIN_PKT_BOUNDS(offs);
2529 			switch (opcode) {
2530 			case NXP_LDB_OPCODE:
2531 			case NXP_LDBX_OPCODE:
2532 				load_size = 1;
2533 				break;
2534 			case NXP_LDH_OPCODE:
2535 			case NXP_LDHX_OPCODE:
2536 				load_size = 2;
2537 				break;
2538 			case NXP_LDW_OPCODE:
2539 			case NXP_LDWX_OPCODE:
2540 				load_size = 4;
2541 				break;
2542 				/* Immediately enclosing switch statement
2543 				 * guarantees
2544 				 * opcode cannot be any other value.
2545 				 */
2546 			}
2547 			end_offs = offs + (load_size - 1);
2548 			/* Catch overflow/wrap-around. */
2549 			ASSERT_RETURN(end_offs >= offs);
2550 			ASSERT_WITHIN_PKT_BOUNDS(end_offs);
2551 			val = 0;
2552 			while (load_size--)
2553 				val = (val << 8) | packet[offs++];
2554 			REG = val;
2555 			break;
2556 		}
2557 		case NXP_JMP_OPCODE:
2558 			/* This can jump backwards. Infinite looping prevented
2559 			 * by instructions_remaining.
2560 			 */
2561 			pc += imm;
2562 			break;
2563 		case NXP_JEQ_OPCODE:
2564 		case NXP_JNE_OPCODE:
2565 		case NXP_JGT_OPCODE:
2566 		case NXP_JLT_OPCODE:
2567 		case NXP_JSET_OPCODE:
2568 		case NXP_JNEBS_OPCODE: {
2569 			/* Load second immediate field. */
2570 			t_u32 cmp_imm = 0;
2571 
2572 			if (reg_num == 1) {
2573 				cmp_imm = reg[1];
2574 			} else if (len_field != 0) {
2575 				t_u32 cmp_imm_len = 1 << (len_field - 1);
2576 
2577 				ASSERT_FORWARD_WITHIN_PROGRAM(pc + cmp_imm_len -
2578 							      1);
2579 				for (i = 0; i < cmp_imm_len; i++)
2580 					cmp_imm =
2581 						(cmp_imm << 8) | program[pc++];
2582 			}
2583 			switch (opcode) {
2584 			case NXP_JEQ_OPCODE:
2585 				if (reg[0] == cmp_imm)
2586 					pc += imm;
2587 				break;
2588 			case NXP_JNE_OPCODE:
2589 				if (reg[0] != cmp_imm)
2590 					pc += imm;
2591 				break;
2592 			case NXP_JGT_OPCODE:
2593 				if (reg[0] > cmp_imm)
2594 					pc += imm;
2595 				break;
2596 			case NXP_JLT_OPCODE:
2597 				if (reg[0] < cmp_imm)
2598 					pc += imm;
2599 				break;
2600 			case NXP_JSET_OPCODE:
2601 				if (reg[0] & cmp_imm)
2602 					pc += imm;
2603 				break;
2604 			case NXP_JNEBS_OPCODE: {
2605 				/* cmp_imm is size in bytes of data to compare.
2606 				 * pc is offset of program bytes to compare.
2607 				 * imm is jump target offset.
2608 				 * REG is offset of packet bytes to compare.
2609 				 */
2610 				ASSERT_FORWARD_WITHIN_PROGRAM(pc + cmp_imm - 1);
2611 				ASSERT_WITHIN_PKT_BOUNDS(REG);
2612 				last_pkt_offs = REG + cmp_imm - 1;
2613 				ASSERT_RETURN(last_pkt_offs >= REG);
2614 				ASSERT_WITHIN_PKT_BOUNDS(last_pkt_offs);
2615 				if (memcmp(program + pc, packet + REG, cmp_imm))
2616 					pc += imm;
2617 				/* skip past comparison bytes */
2618 				pc += cmp_imm;
2619 				break;
2620 			}
2621 			}
2622 			break;
2623 		}
2624 		case NXP_ADD_OPCODE:
2625 			reg[0] += reg_num ? reg[1] : imm;
2626 			break;
2627 		case NXP_MUL_OPCODE:
2628 			reg[0] *= reg_num ? reg[1] : imm;
2629 			break;
2630 		case NXP_DIV_OPCODE: {
2631 			const t_u32 div_operand = reg_num ? reg[1] : imm;
2632 
2633 			ASSERT_RETURN(div_operand);
2634 			reg[0] /= div_operand;
2635 			break;
2636 		}
2637 		case NXP_AND_OPCODE:
2638 			reg[0] &= reg_num ? reg[1] : imm;
2639 			break;
2640 		case NXP_OR_OPCODE:
2641 			reg[0] |= reg_num ? reg[1] : imm;
2642 			break;
2643 		case NXP_SH_OPCODE: {
2644 			const int32_t shift_val =
2645 				reg_num ? (int32_t)reg[1] : sign_imm;
2646 			if (shift_val > 0)
2647 				reg[0] <<= shift_val;
2648 			else
2649 				reg[0] >>= -shift_val;
2650 			break;
2651 		}
2652 		case NXP_LI_OPCODE:
2653 			REG = sign_imm;
2654 			break;
2655 		case NXP_EXT_OPCODE:
2656 			if (
2657 /* If LDM_EXT_OPCODE is 0 and imm is compared with it, a compiler error will
2658  * result,
2659  * instead just enforce that imm is unsigned (so it's always greater or equal to
2660  * 0).
2661  */
2662 #if NXP_LDM_EXT_OPCODE == 0
2663 				ENFORCE_UNSIGNED(imm) &&
2664 #else
2665 				imm >= NXP_LDM_EXT_OPCODE &&
2666 #endif
2667 				imm < (NXP_LDM_EXT_OPCODE + MEM_ITEMS)) {
2668 				REG = mem[imm - NXP_LDM_EXT_OPCODE];
2669 			} else if (imm >= NXP_STM_EXT_OPCODE &&
2670 				   imm < (NXP_STM_EXT_OPCODE + MEM_ITEMS)) {
2671 				mem[imm - NXP_STM_EXT_OPCODE] = REG;
2672 			} else
2673 				switch (imm) {
2674 				case NXP_NOT_EXT_OPCODE:
2675 					REG = ~REG;
2676 					break;
2677 				case NXP_NEG_EXT_OPCODE:
2678 					REG = -REG;
2679 					break;
2680 				case NXP_SWAP_EXT_OPCODE: {
2681 					t_u32 tmp = REG;
2682 
2683 					REG = OTHER_REG;
2684 					OTHER_REG = tmp;
2685 					break;
2686 				}
2687 				case NXP_MOV_EXT_OPCODE:
2688 					REG = OTHER_REG;
2689 					break;
2690 				/* Unknown extended opcode */
2691 				default:
2692 					/* Bail out */
2693 					return PASS_PKT;
2694 				}
2695 			break;
2696 		/* Unknown opcode */
2697 		default:
2698 			/* Bail out */
2699 			return PASS_PKT;
2700 		}
2701 	} while (instructions_left--);
2702 	return PASS_PKT;
2703 }
2704 
2705 /**
2706  * @brief filter packet
2707  *
2708  * @param priv          A pointer to moal_private struct
2709  * @param data          packet data
2710  * @param len           packet len
2711  * @param filter_age    filter age
2712  * @return non-zero if packet should be passed to AP, zero if
2713  *         packet should be dropped.
2714  */
woal_filter_packet(moal_private * priv,t_u8 * data,t_u32 len,t_u32 filter_age)2715 int woal_filter_packet(moal_private *priv, t_u8 *data, t_u32 len,
2716 		       t_u32 filter_age)
2717 {
2718 	packet_filter *pkt_filter = NULL;
2719 	int ret = PASS_PKT;
2720 	unsigned long flags;
2721 
2722 	ENTER();
2723 	pkt_filter = priv->packet_filter;
2724 	if (!unlikely(pkt_filter)) {
2725 		PRINTM(MINFO, "packet_filter not init\n");
2726 		goto done;
2727 	}
2728 
2729 	if (pkt_filter->state != PACKET_FILTER_STATE_START)
2730 		goto done;
2731 
2732 	DBG_HEXDUMP(MDAT_D, "packet_filter_program",
2733 		    pkt_filter->packet_filter_program,
2734 		    pkt_filter->packet_filter_len);
2735 	DBG_HEXDUMP(MDAT_D, "packet_filter_data", data, len);
2736 	spin_lock_irqsave(&pkt_filter->lock, flags);
2737 	ret = process_packet(pkt_filter->packet_filter_program,
2738 			     pkt_filter->packet_filter_len, data, len,
2739 			     filter_age);
2740 	spin_unlock_irqrestore(&pkt_filter->lock, flags);
2741 
2742 done:
2743 	PRINTM(MINFO, "packet filter ret %d\n", ret);
2744 	LEAVE();
2745 	return ret;
2746 }
2747 
2748 /**
2749  * @brief init wifi hal
2750  *
2751  * @param priv       A pointer to moal_private struct
2752  *
2753  * @return      0: success  1: fail
2754  */
woal_init_wifi_hal(moal_private * priv)2755 int woal_init_wifi_hal(moal_private *priv)
2756 {
2757 	ENTER();
2758 	woal_init_ring_buffer(priv);
2759 	priv->pkt_fate_monitor_enable = MFALSE;
2760 	woal_init_packet_filter(priv);
2761 
2762 	LEAVE();
2763 	return 0;
2764 }
2765 
2766 /**
2767  * @brief deinit wifi hal
2768  *
2769  * @param priv       A pointer to moal_private struct
2770  *
2771  * @return      0: success  1: fail
2772  */
woal_deinit_wifi_hal(moal_private * priv)2773 int woal_deinit_wifi_hal(moal_private *priv)
2774 {
2775 	ENTER();
2776 	woal_deinit_ring_buffer(priv);
2777 	priv->pkt_fate_monitor_enable = MFALSE;
2778 	woal_deinit_packet_filter(priv);
2779 
2780 	LEAVE();
2781 	return 0;
2782 }
2783 
2784 /**
2785  * @brief vendor command to get link layer statistic
2786  *
2787  * @param wiphy    A pointer to wiphy struct
2788  * @param wdev     A pointer to wireless_dev struct
2789  * @param data     a pointer to data
2790  * @param  len     data length
2791  *
2792  * @return      0: success  -1: fail
2793  */
woal_cfg80211_subcmd_link_statistic_get(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2794 static int woal_cfg80211_subcmd_link_statistic_get(struct wiphy *wiphy,
2795 						   struct wireless_dev *wdev,
2796 						   const void *data, int len)
2797 {
2798 	struct net_device *dev = wdev->netdev;
2799 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2800 	struct sk_buff *skb = NULL;
2801 	mlan_ioctl_req *req = NULL;
2802 	mlan_ds_get_info *info = NULL;
2803 	mlan_status status = MLAN_STATUS_SUCCESS;
2804 	wifi_radio_stat *radio_stat = NULL;
2805 	wifi_radio_stat *radio_stat_tmp = NULL;
2806 	wifi_iface_stat *iface_stat = NULL;
2807 	t_u32 num_radio = 0, iface_stat_len = 0, radio_stat_len = 0;
2808 	int err = -1, length = 0, i;
2809 	char *ioctl_link_stats_buf = NULL;
2810 	t_u64 cur_time = 0;
2811 	t_u64 inter_msec = 0;
2812 	t_u64 max_msec = (t_u64)24 * (t_u64)24 * (t_u64)3600 * (t_u64)1000;
2813 	moal_handle *handle = priv->phandle;
2814 
2815 	/* Allocate an IOCTL request buffer */
2816 	req = woal_alloc_mlan_ioctl_req(sizeof(t_u32) + BUF_MAXLEN);
2817 	if (req == NULL) {
2818 		PRINTM(MERROR, "Could not allocate mlan ioctl request!\n");
2819 		return -ENOMEM;
2820 	}
2821 
2822 	/* Fill request buffer */
2823 	info = (mlan_ds_get_info *)req->pbuf;
2824 	info->sub_command = MLAN_OID_LINK_STATS;
2825 	req->req_id = MLAN_IOCTL_GET_INFO;
2826 	req->action = MLAN_ACT_GET;
2827 
2828 	/* Send IOCTL request to MLAN */
2829 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2830 	if (status != MLAN_STATUS_SUCCESS) {
2831 		PRINTM(MERROR, "get link layer statistic fail\n");
2832 		goto done;
2833 	}
2834 
2835 	ioctl_link_stats_buf = info->param.link_statistic;
2836 	num_radio = *((t_u32 *)info->param.link_statistic);
2837 
2838 	radio_stat = (wifi_radio_stat *)(info->param.link_statistic +
2839 					 sizeof(num_radio));
2840 	radio_stat_len = num_radio * sizeof(wifi_radio_stat);
2841 
2842 	/* Re-write on_time/tx_time/rx_time/on_time_scan from moal handle */
2843 	PRINTM(MINFO, "handle->on_time=%llu\n", handle->on_time);
2844 	if (handle->on_time) {
2845 		moal_get_boot_ktime(handle, &cur_time);
2846 		inter_msec = moal_do_div(cur_time - handle->on_time, 1000000);
2847 		PRINTM(MINFO, "cur_time=%llu inter_msec=%llu max_msec=%llu\n",
2848 		       cur_time, inter_msec, max_msec);
2849 		/* When we report the time up, u32 is not big enough(represent
2850 		 * max 49days) and might out of range, make the max value to
2851 		 * 24days.
2852 		 */
2853 		if (inter_msec > max_msec) {
2854 			PRINTM(MMSG,
2855 			       "Out of range, set inter_msec=%llu to max_msec=%llu\n",
2856 			       inter_msec, max_msec);
2857 			inter_msec = max_msec;
2858 		}
2859 	}
2860 	PRINTM(MINFO, "handle->tx_time=%llu\n", handle->tx_time);
2861 	PRINTM(MINFO, "handle->rx_time=%llu\n", handle->rx_time);
2862 	PRINTM(MINFO, "handle->scan_time=%llu\n", handle->scan_time);
2863 	radio_stat_tmp = radio_stat;
2864 	for (i = 0; i < num_radio; i++) {
2865 		radio_stat_tmp->on_time = (t_u32)inter_msec;
2866 		radio_stat_tmp->tx_time =
2867 			(t_u32)moal_do_div(handle->tx_time, 1000);
2868 		radio_stat_tmp->rx_time =
2869 			(t_u32)moal_do_div(handle->rx_time, 1000);
2870 		radio_stat_tmp->on_time_scan =
2871 			(t_u32)moal_do_div(handle->scan_time, 1000);
2872 		radio_stat_tmp++;
2873 	}
2874 
2875 	iface_stat = (wifi_iface_stat *)(info->param.link_statistic +
2876 					 sizeof(num_radio) + radio_stat_len);
2877 	iface_stat_len = sizeof(wifi_iface_stat);
2878 
2879 	/* could get peer info with separate cmd */
2880 	for (i = 0; i < iface_stat->num_peers; i++) {
2881 		/* no need copy, just increase iface_stat length*/
2882 		iface_stat_len += sizeof(wifi_peer_info) +
2883 				  sizeof(wifi_rate_stat) *
2884 					  iface_stat->peer_info[i].num_rate;
2885 	}
2886 
2887 	/* Here the length doesn't contain addition 2 attribute header length */
2888 	length = NLA_HDRLEN * 2 + sizeof(num_radio) + radio_stat_len +
2889 		 iface_stat_len;
2890 
2891 	/* Alloc the SKB for vendor_event */
2892 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, length);
2893 	if (unlikely(!skb)) {
2894 		PRINTM(MERROR, "skb alloc failed\n");
2895 		goto done;
2896 	}
2897 
2898 	if (nla_put_u32(skb, ATTR_LL_STATS_NUM_RADIO, num_radio) ||
2899 	    nla_put(skb, ATTR_LL_STATS_RADIO, radio_stat_len, radio_stat) ||
2900 	    nla_put(skb, ATTR_LL_STATS_IFACE, iface_stat_len, iface_stat)) {
2901 		PRINTM(MERROR, "nla_put failed!\n");
2902 		kfree_skb(skb);
2903 		goto done;
2904 	}
2905 
2906 	PRINTM(MDAT_D, "%s: <<< Start DUMP\n", __func__);
2907 	PRINTM(MDAT_D, "sizeof(wifi_radio_stat)=%zu\n",
2908 	       sizeof(wifi_radio_stat));
2909 	DBG_HEXDUMP(MDAT_D, "radio_stat", (t_u8 *)radio_stat, radio_stat_len);
2910 	PRINTM(MDAT_D, "sizeof(wifi_channel_stat)=%zu\n",
2911 	       sizeof(wifi_channel_stat));
2912 	DBG_HEXDUMP(MDAT_D, "iface_stat", (t_u8 *)iface_stat, iface_stat_len);
2913 	PRINTM(MDAT_D, "num_radio=%d\n", num_radio);
2914 	radio_stat_tmp = radio_stat;
2915 	for (i = 0; i < num_radio; i++) {
2916 		PRINTM(MDAT_D, "--radio_stat[%d]--\n", i);
2917 		PRINTM(MDAT_D, "radio=%d\n", radio_stat_tmp->radio);
2918 		PRINTM(MDAT_D, "on_time=%d\n", radio_stat_tmp->on_time);
2919 		PRINTM(MDAT_D, "tx_time=%d\n", radio_stat_tmp->tx_time);
2920 		PRINTM(MDAT_D, "reserved0=%d\n", radio_stat_tmp->reserved0);
2921 		PRINTM(MDAT_D, "rx_time=%d\n", radio_stat_tmp->rx_time);
2922 		PRINTM(MDAT_D, "on_time_scan=%d\n",
2923 		       radio_stat_tmp->on_time_scan);
2924 		PRINTM(MDAT_D, "on_time_nbd=%d\n", radio_stat_tmp->on_time_nbd);
2925 		PRINTM(MDAT_D, "on_time_gscan=%d\n",
2926 		       radio_stat_tmp->on_time_gscan);
2927 		PRINTM(MDAT_D, "on_time_roam_scan=%d\n",
2928 		       radio_stat_tmp->on_time_roam_scan);
2929 		PRINTM(MDAT_D, "on_time_pno_scan=%d\n",
2930 		       radio_stat_tmp->on_time_pno_scan);
2931 		PRINTM(MDAT_D, "on_time_hs20=%d\n",
2932 		       radio_stat_tmp->on_time_hs20);
2933 		PRINTM(MDAT_D, "num_channels=%d\n",
2934 		       radio_stat_tmp->num_channels);
2935 		radio_stat_tmp++;
2936 	}
2937 	PRINTM(MDAT_D, "%s: >>> End DUMP\n", __func__);
2938 
2939 	err = cfg80211_vendor_cmd_reply(skb);
2940 	if (unlikely(err))
2941 		PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
2942 
2943 done:
2944 	if (status != MLAN_STATUS_PENDING)
2945 		kfree(req);
2946 	return err;
2947 }
2948 
2949 /**
2950  * @brief API to trigger the link layer statistics collection.
2951  *   Unless his API is invoked - link layer statistics will not be collected.
2952  *   Radio statistics (once started) do not stop or get reset unless
2953  *   wifi_clear_link_stats is invoked, Interface statistics (once started)
2954  *   reset and start afresh after each connection.
2955  *
2956  * @param wiphy    A pointer to wiphy struct
2957  * @param wdev     A pointer to wireless_dev struct
2958  * @param data     a pointer to data
2959  * @param  len     data length
2960  *
2961  * @return      0: success  -1: fail
2962  */
woal_cfg80211_subcmd_link_statistic_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2963 static int woal_cfg80211_subcmd_link_statistic_set(struct wiphy *wiphy,
2964 						   struct wireless_dev *wdev,
2965 						   const void *data, int len)
2966 {
2967 	moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
2968 	struct nlattr *tb[ATTR_LL_STATS_MAX + 1];
2969 	wifi_link_layer_params ll_params;
2970 	mlan_ioctl_req *req = NULL;
2971 	mlan_ds_get_info *info = NULL;
2972 	mlan_status status = MLAN_STATUS_SUCCESS;
2973 	int err = 0;
2974 
2975 	err = nla_parse(tb, ATTR_LL_STATS_MAX, data, len, NULL
2976 #if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
2977 			,
2978 			NULL
2979 #endif
2980 	);
2981 	if (err)
2982 		return err;
2983 
2984 	if (!tb[ATTR_LL_STATS_MPDU_SIZE_THRESHOLD] ||
2985 	    !tb[ATTR_LL_STATS_AGGRESSIVE_STATS_GATHERING])
2986 		return -EINVAL;
2987 
2988 	ll_params.mpdu_size_threshold =
2989 		nla_get_u32(tb[ATTR_LL_STATS_MPDU_SIZE_THRESHOLD]);
2990 	ll_params.aggressive_statistics_gathering =
2991 		nla_get_u32(tb[ATTR_LL_STATS_AGGRESSIVE_STATS_GATHERING]);
2992 
2993 	PRINTM(MEVENT,
2994 	       "link layer params mpdu_size_threshold = 0x%x, aggressive_statistics_gathering = 0x%x\n",
2995 	       ll_params.mpdu_size_threshold,
2996 	       ll_params.aggressive_statistics_gathering);
2997 
2998 	/* Allocate an IOCTL request buffer */
2999 	req = woal_alloc_mlan_ioctl_req(sizeof(t_u32) +
3000 					sizeof(mlan_ds_get_info));
3001 	if (req == NULL) {
3002 		PRINTM(MERROR, "Could not allocate mlan ioctl request!\n");
3003 		return -ENOMEM;
3004 	}
3005 
3006 	/* Fill request buffer */
3007 	info = (mlan_ds_get_info *)req->pbuf;
3008 	info->sub_command = MLAN_OID_LINK_STATS;
3009 	req->req_id = MLAN_IOCTL_GET_INFO;
3010 	req->action = MLAN_ACT_SET;
3011 
3012 	/* Configure parameter to firmware */
3013 	moal_memcpy_ext(priv->phandle, info->param.link_statistic, &ll_params,
3014 			sizeof(ll_params),
3015 			sizeof(mlan_ds_get_info) - sizeof(t_u32));
3016 
3017 	/* Send IOCTL request to MLAN */
3018 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3019 	if (status == MLAN_STATUS_SUCCESS)
3020 		PRINTM(MMSG, "enable link layer statistic successfully\n");
3021 
3022 	if (status != MLAN_STATUS_PENDING)
3023 		kfree(req);
3024 	return 0;
3025 }
3026 
3027 /**
3028  * @brief clear function should download command to fimrware,
3029  *	  so that firmware could cleanup per peer statistic number
3030  *
3031  * @param wiphy    A pointer to wiphy struct
3032  * @param wdev     A pointer to wireless_dev struct
3033  * @param data     a pointer to data
3034  * @param  len     data length
3035  *
3036  * @return      0: success  -1: fail
3037  */
woal_cfg80211_subcmd_link_statistic_clr(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3038 static int woal_cfg80211_subcmd_link_statistic_clr(struct wiphy *wiphy,
3039 						   struct wireless_dev *wdev,
3040 						   const void *data, int len)
3041 {
3042 	moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
3043 	struct nlattr *tb[ATTR_LL_STATS_MAX + 1];
3044 	mlan_ioctl_req *req = NULL;
3045 	mlan_ds_get_info *info = NULL;
3046 	mlan_status status = MLAN_STATUS_SUCCESS;
3047 	u32 stats_clear_req_mask = 0x0, stats_clear_rsp_mask = 0x0;
3048 	u8 stop_req = 0x0, stop_rsp = 0x0;
3049 	struct sk_buff *skb = NULL;
3050 	int err = 0, length = 0;
3051 
3052 	err = nla_parse(tb, ATTR_LL_STATS_MAX, data, len, NULL
3053 #if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
3054 			,
3055 			NULL
3056 #endif
3057 	);
3058 	if (err)
3059 		return err;
3060 
3061 	if (!tb[ATTR_LL_STATS_CLEAR_REQ_MASK])
3062 		return -EINVAL;
3063 	else
3064 		stats_clear_req_mask =
3065 			nla_get_u32(tb[ATTR_LL_STATS_CLEAR_REQ_MASK]);
3066 
3067 	if (!tb[ATTR_LL_STATS_STOP_REQ])
3068 		return -EINVAL;
3069 	else
3070 		stop_req = nla_get_u8(tb[ATTR_LL_STATS_STOP_REQ]);
3071 
3072 	PRINTM(MEVENT,
3073 	       "link layer clear stats_clear_req_mask = 0x%x, stop_req = 0x%x\n",
3074 	       stats_clear_req_mask, stop_req);
3075 
3076 	/* Allocate an IOCTL request buffer */
3077 	req = woal_alloc_mlan_ioctl_req(sizeof(t_u32) +
3078 					sizeof(mlan_ds_get_info));
3079 	if (req == NULL) {
3080 		PRINTM(MERROR, "Could not allocate mlan ioctl request!\n");
3081 		return -ENOMEM;
3082 	}
3083 
3084 	/* Fill request buffer */
3085 	info = (mlan_ds_get_info *)req->pbuf;
3086 	info->sub_command = MLAN_OID_LINK_STATS;
3087 	req->req_id = MLAN_IOCTL_GET_INFO;
3088 	req->action = MLAN_ACT_CLEAR;
3089 
3090 	/* Send IOCTL request to MLAN */
3091 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3092 	if (status == MLAN_STATUS_SUCCESS)
3093 		PRINTM(MMSG, "disable link layer statistic successfully\n");
3094 
3095 	length = NLA_HDRLEN + sizeof(stats_clear_rsp_mask) + sizeof(stop_rsp);
3096 	/* Alloc the SKB for vendor_event */
3097 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, length);
3098 	if (unlikely(!skb)) {
3099 		PRINTM(MERROR, "skb alloc failed\n");
3100 		err = -EINVAL;
3101 		goto exit;
3102 	}
3103 
3104 	/*  clear api to reset statistics, stats_clear_rsp_mask identifies what
3105 	 * stats have been cleared stop_req = 1 will imply whether to stop the
3106 	 * statistics collection. stop_rsp = 1 will imply that stop_req was
3107 	 * honored and statistics collection was stopped.
3108 	 */
3109 	stats_clear_rsp_mask = WIFI_STATS_RADIO | WIFI_STATS_IFACE;
3110 	stop_rsp = 1;
3111 	if (nla_put_u32(skb, ATTR_LL_STATS_CLEAR_RSP_MASK,
3112 			stats_clear_rsp_mask) ||
3113 	    nla_put_u8(skb, ATTR_LL_STATS_STOP_RSP, stop_rsp)) {
3114 		PRINTM(MERROR, "nla_put failed!\n");
3115 		kfree_skb(skb);
3116 		err = -EINVAL;
3117 		goto exit;
3118 	}
3119 
3120 	err = cfg80211_vendor_cmd_reply(skb);
3121 	if (unlikely(err)) {
3122 		PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
3123 		goto exit;
3124 		;
3125 	}
3126 
3127 exit:
3128 	if (status != MLAN_STATUS_PENDING)
3129 		kfree(req);
3130 	return err;
3131 }
3132 
3133 #ifdef STA_CFG80211
3134 #define RSSI_MONOTOR_START 1
3135 #define RSSI_MONOTOR_STOP 0
3136 
3137 /**
3138  * @brief vendor command to control rssi monitor
3139  *
3140  * @param wiphy    A pointer to wiphy struct
3141  * @param wdev     A pointer to wireless_dev struct
3142  * @param data     a pointer to data
3143  * @param  len     data length
3144  *
3145  * @return      0: success  -1: fail
3146  */
woal_cfg80211_subcmd_rssi_monitor(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3147 static int woal_cfg80211_subcmd_rssi_monitor(struct wiphy *wiphy,
3148 					     struct wireless_dev *wdev,
3149 					     const void *data, int len)
3150 {
3151 	struct nlattr *tb[ATTR_RSSI_MONITOR_MAX + 1];
3152 	moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
3153 	u32 rssi_monitor_control = 0x0;
3154 	s8 rssi_min = 0, rssi_max = 0;
3155 	int err = 0;
3156 	t_u8 *pos = NULL;
3157 	struct sk_buff *skb = NULL;
3158 	int ret = 0;
3159 
3160 	ENTER();
3161 
3162 	if (!priv->media_connected) {
3163 		ret = -EINVAL;
3164 		goto done;
3165 	}
3166 
3167 	ret = nla_parse(tb, ATTR_RSSI_MONITOR_MAX, data, len, NULL
3168 #if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
3169 			,
3170 			NULL
3171 #endif
3172 	);
3173 	if (ret)
3174 		goto done;
3175 
3176 	if (!tb[ATTR_RSSI_MONITOR_CONTROL]) {
3177 		ret = -EINVAL;
3178 		goto done;
3179 	}
3180 	rssi_monitor_control = nla_get_u32(tb[ATTR_RSSI_MONITOR_CONTROL]);
3181 
3182 	if (rssi_monitor_control == RSSI_MONOTOR_START) {
3183 		if ((!tb[ATTR_RSSI_MONITOR_MIN_RSSI]) ||
3184 		    (!tb[ATTR_RSSI_MONITOR_MAX_RSSI])) {
3185 			ret = -EINVAL;
3186 			goto done;
3187 		}
3188 
3189 		rssi_min = nla_get_s8(tb[ATTR_RSSI_MONITOR_MIN_RSSI]);
3190 		rssi_max = nla_get_s8(tb[ATTR_RSSI_MONITOR_MAX_RSSI]);
3191 
3192 		PRINTM(MEVENT,
3193 		       "start rssi monitor rssi_min = %d, rssi_max= %d\n",
3194 		       rssi_min, rssi_max);
3195 
3196 		/* set rssi low/high threshold */
3197 		priv->cqm_rssi_high_thold = rssi_max;
3198 		priv->cqm_rssi_thold = rssi_min;
3199 		priv->cqm_rssi_hyst = 4;
3200 		if (MLAN_STATUS_SUCCESS !=
3201 		    woal_set_rssi_threshold(priv, 0, MOAL_IOCTL_WAIT)) {
3202 			PRINTM(MERROR, "set rssi threhold fail\n");
3203 			ret = -EFAULT;
3204 			goto done;
3205 		}
3206 	} else if (rssi_monitor_control == RSSI_MONOTOR_STOP) {
3207 		/* stop rssi monitor */
3208 		PRINTM(MEVENT, "stop rssi monitor\n");
3209 		/* set both rssi_thold/hyst to 0, will trigger subscribe event
3210 		 * clear
3211 		 */
3212 		priv->cqm_rssi_high_thold = 0;
3213 		priv->cqm_rssi_thold = 0;
3214 		priv->cqm_rssi_hyst = 0;
3215 		if (MLAN_STATUS_SUCCESS !=
3216 		    woal_set_rssi_threshold(priv, 0, MOAL_IOCTL_WAIT)) {
3217 			PRINTM(MERROR, "set rssi threhold fail\n");
3218 			ret = -EFAULT;
3219 			goto done;
3220 		}
3221 	} else {
3222 		PRINTM(MERROR, "invalid rssi_monitor control request\n");
3223 		ret = -EINVAL;
3224 		goto done;
3225 	}
3226 
3227 	/* Alloc the SKB for cmd reply */
3228 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
3229 	if (unlikely(!skb)) {
3230 		PRINTM(MERROR, "skb alloc failed\n");
3231 		ret = -EINVAL;
3232 		goto done;
3233 	}
3234 	pos = skb_put(skb, len);
3235 	moal_memcpy_ext(priv->phandle, pos, data, len, len);
3236 	err = cfg80211_vendor_cmd_reply(skb);
3237 	if (unlikely(err)) {
3238 		PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
3239 		ret = err;
3240 	}
3241 done:
3242 	LEAVE();
3243 	return ret;
3244 }
3245 
3246 /**
3247  * @brief send rssi event to kernel
3248  *
3249  * @param priv       A pointer to moal_private
3250  * @param rssi       current rssi value
3251  *
3252  * @return      N/A
3253  */
woal_cfg80211_rssi_monitor_event(moal_private * priv,t_s16 rssi)3254 void woal_cfg80211_rssi_monitor_event(moal_private *priv, t_s16 rssi)
3255 {
3256 	struct sk_buff *skb = NULL;
3257 	t_s8 rssi_value = 0;
3258 
3259 	ENTER();
3260 
3261 	skb = dev_alloc_skb(NLA_HDRLEN * 2 + ETH_ALEN + sizeof(t_s8));
3262 	if (!skb)
3263 		goto done;
3264 	/* convert t_s16 to t_s8*/
3265 	rssi_value = -abs(rssi);
3266 	if (nla_put(skb, ATTR_RSSI_MONITOR_CUR_BSSID, ETH_ALEN,
3267 		    priv->conn_bssid) ||
3268 	    nla_put_s8(skb, ATTR_RSSI_MONITOR_CUR_RSSI, rssi_value)) {
3269 		PRINTM(MERROR, "nla_put failed!\n");
3270 		kfree(skb);
3271 		goto done;
3272 	}
3273 	woal_cfg80211_vendor_event(priv, event_rssi_monitor, (t_u8 *)skb->data,
3274 				   skb->len);
3275 	kfree(skb);
3276 done:
3277 	LEAVE();
3278 }
3279 #endif
3280 
3281 /**
3282  * @brief vendor command to key_mgmt_set_key
3283  *
3284  * @param wiphy    A pointer to wiphy struct
3285  * @param wdev     A pointer to wireless_dev struct
3286  * @param data     a pointer to data
3287  * @param  len     data length
3288  *
3289  * @return      0: success  fail otherwise
3290  */
3291 static int
woal_cfg80211_subcmd_set_roaming_offload_key(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3292 woal_cfg80211_subcmd_set_roaming_offload_key(struct wiphy *wiphy,
3293 					     struct wireless_dev *wdev,
3294 					     const void *data, int data_len)
3295 {
3296 	moal_private *priv;
3297 	struct net_device *dev;
3298 	struct sk_buff *skb = NULL;
3299 	t_u8 *pos = (t_u8 *)data;
3300 	int ret = MLAN_STATUS_SUCCESS;
3301 
3302 	ENTER();
3303 
3304 	if (data)
3305 		DBG_HEXDUMP(MCMD_D, "Vendor pmk", (t_u8 *)data, data_len);
3306 
3307 	if (!wdev || !wdev->netdev) {
3308 		LEAVE();
3309 		return -EFAULT;
3310 	}
3311 
3312 	dev = wdev->netdev;
3313 	priv = (moal_private *)woal_get_netdev_priv(dev);
3314 	if (!priv || !pos) {
3315 		LEAVE();
3316 		return -EFAULT;
3317 	}
3318 
3319 	if (data_len > MLAN_MAX_KEY_LENGTH) {
3320 		moal_memcpy_ext(priv->phandle, &priv->pmk.pmk_r0, pos,
3321 				MLAN_MAX_KEY_LENGTH, MLAN_MAX_KEY_LENGTH);
3322 		pos += MLAN_MAX_KEY_LENGTH;
3323 		moal_memcpy_ext(priv->phandle, &priv->pmk.pmk_r0_name, pos,
3324 				data_len - MLAN_MAX_KEY_LENGTH,
3325 				MLAN_MAX_PMKR0_NAME_LENGTH);
3326 	} else {
3327 		moal_memcpy_ext(priv->phandle, &priv->pmk.pmk, data, data_len,
3328 				MLAN_MAX_KEY_LENGTH);
3329 	}
3330 	priv->pmk_saved = MTRUE;
3331 
3332 	/** Allocate skb for cmd reply*/
3333 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, data_len);
3334 	if (!skb) {
3335 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
3336 		LEAVE();
3337 		return -EFAULT;
3338 	}
3339 	pos = skb_put(skb, data_len);
3340 	moal_memcpy_ext(priv->phandle, pos, data, data_len, data_len);
3341 	ret = cfg80211_vendor_cmd_reply(skb);
3342 
3343 	LEAVE();
3344 	return ret;
3345 }
3346 
3347 /**
3348  * @brief vendor command to supplicant to update AP info
3349  *
3350  * @param priv     A pointer to moal_private
3351  * @param data     a pointer to data
3352  * @param  len     data length
3353  *
3354  * @return      0: success  1: fail
3355  */
woal_roam_ap_info(moal_private * priv,t_u8 * data,int len)3356 int woal_roam_ap_info(moal_private *priv, t_u8 *data, int len)
3357 {
3358 	struct wiphy *wiphy = priv->wdev->wiphy;
3359 	struct sk_buff *skb = NULL;
3360 	int ret = MLAN_STATUS_SUCCESS;
3361 	key_info *pkey = NULL;
3362 	apinfo *pinfo = NULL;
3363 	apinfo *req_tlv = NULL;
3364 	MrvlIEtypesHeader_t *tlv = NULL;
3365 	t_u16 tlv_type = 0, tlv_len = 0, tlv_buf_left = 0;
3366 	int event_id = 0;
3367 	t_u8 authorized = 1;
3368 
3369 	ENTER();
3370 
3371 	event_id = woal_get_event_id(event_fw_roam_success);
3372 	if (event_max == event_id) {
3373 		PRINTM(MERROR, "Not find this event %d\n", event_id);
3374 		ret = 1;
3375 		LEAVE();
3376 		return ret;
3377 	}
3378 	/**allocate skb*/
3379 #if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
3380 	skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev, len + 50,
3381 #else
3382 	skb = cfg80211_vendor_event_alloc(wiphy, len + 50,
3383 #endif
3384 					  event_id, GFP_ATOMIC);
3385 
3386 	if (!skb) {
3387 		PRINTM(MERROR, "allocate memory fail for vendor event\n");
3388 		ret = 1;
3389 		LEAVE();
3390 		return ret;
3391 	}
3392 
3393 	nla_put(skb, MRVL_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
3394 		MLAN_MAC_ADDR_LENGTH, (t_u8 *)data);
3395 	nla_put(skb, MRVL_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED,
3396 		sizeof(authorized), &authorized);
3397 	tlv = (MrvlIEtypesHeader_t *)(data + MLAN_MAC_ADDR_LENGTH);
3398 	tlv_buf_left = len - MLAN_MAC_ADDR_LENGTH;
3399 	while (tlv_buf_left >= sizeof(MrvlIEtypesHeader_t)) {
3400 		tlv_type = woal_le16_to_cpu(tlv->type);
3401 		tlv_len = woal_le16_to_cpu(tlv->len);
3402 
3403 		if (tlv_buf_left < (tlv_len + sizeof(MrvlIEtypesHeader_t))) {
3404 			PRINTM(MERROR,
3405 			       "Error processing firmware roam success TLVs, bytes left < TLV length\n");
3406 			break;
3407 		}
3408 
3409 		switch (tlv_type) {
3410 		case TLV_TYPE_APINFO:
3411 			pinfo = (apinfo *)tlv;
3412 			nla_put(skb, MRVL_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE,
3413 				pinfo->header.len, pinfo->rsp_ie);
3414 			break;
3415 		case TLV_TYPE_ASSOC_REQ_IE:
3416 			req_tlv = (apinfo *)tlv;
3417 			nla_put(skb, MRVL_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE,
3418 				req_tlv->header.len, req_tlv->rsp_ie);
3419 			break;
3420 		case TLV_TYPE_KEYINFO:
3421 			pkey = (key_info *)tlv;
3422 			nla_put(skb,
3423 				MRVL_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR,
3424 				MLAN_REPLAY_CTR_LEN, pkey->key.replay_ctr);
3425 			nla_put(skb, MRVL_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK,
3426 				MLAN_KCK_LEN, pkey->key.kck);
3427 			nla_put(skb, MRVL_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK,
3428 				MLAN_KEK_LEN, pkey->key.kek);
3429 			break;
3430 		default:
3431 			break;
3432 		}
3433 		tlv_buf_left -= tlv_len + sizeof(MrvlIEtypesHeader_t);
3434 		tlv = (MrvlIEtypesHeader_t *)((t_u8 *)tlv + tlv_len +
3435 					      sizeof(MrvlIEtypesHeader_t));
3436 	}
3437 
3438 	/**send event*/
3439 	cfg80211_vendor_event(skb, GFP_ATOMIC);
3440 
3441 	LEAVE();
3442 	return ret;
3443 }
3444 
3445 /**
3446  * @brief vendor command to get fw roaming capability
3447  *
3448  * @param wiphy    A pointer to wiphy struct
3449  * @param wdev     A pointer to wireless_dev struct
3450  * @param data     a pointer to data
3451  * @param  len     data length
3452  *
3453  * @return      0: success  fail otherwise
3454  */
3455 static int
woal_cfg80211_subcmd_get_roaming_capability(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3456 woal_cfg80211_subcmd_get_roaming_capability(struct wiphy *wiphy,
3457 					    struct wireless_dev *wdev,
3458 					    const void *data, int len)
3459 {
3460 	int ret = MLAN_STATUS_SUCCESS;
3461 	wifi_roaming_capabilities capa;
3462 	struct sk_buff *skb = NULL;
3463 	int err = 0;
3464 
3465 	ENTER();
3466 
3467 	if (!wdev || !wdev->netdev) {
3468 		LEAVE();
3469 		return -EFAULT;
3470 	}
3471 
3472 	capa.max_blacklist_size = MAX_AP_LIST;
3473 	capa.max_whitelist_size = MAX_SSID_NUM;
3474 
3475 	/* Alloc the SKB for vendor_event */
3476 	skb = cfg80211_vendor_cmd_alloc_reply_skb(
3477 		wiphy, sizeof(wifi_roaming_capabilities) + 50);
3478 	if (unlikely(!skb)) {
3479 		PRINTM(MERROR, "skb alloc failed\n");
3480 		goto done;
3481 	}
3482 
3483 	/* Push the data to the skb */
3484 	nla_put(skb, MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CAPA,
3485 		sizeof(wifi_roaming_capabilities), (t_u8 *)&capa);
3486 
3487 	err = cfg80211_vendor_cmd_reply(skb);
3488 	if (unlikely(err))
3489 		PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
3490 
3491 done:
3492 	LEAVE();
3493 	return ret;
3494 }
3495 
3496 /**
3497  * @brief vendor command to enable/disable fw roaming
3498  *
3499  * @param wiphy    A pointer to wiphy struct
3500  * @param wdev     A pointer to wireless_dev struct
3501  * @param data     a pointer to data
3502  * @param  len     data length
3503  *
3504  * @return      0: success  fail otherwise
3505  */
woal_cfg80211_subcmd_fw_roaming_enable(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3506 static int woal_cfg80211_subcmd_fw_roaming_enable(struct wiphy *wiphy,
3507 						  struct wireless_dev *wdev,
3508 						  const void *data, int len)
3509 {
3510 	moal_private *priv;
3511 	struct net_device *dev;
3512 	int ret = MLAN_STATUS_SUCCESS;
3513 	struct sk_buff *skb = NULL;
3514 	const struct nlattr *iter;
3515 	int type, rem, err;
3516 	t_u32 fw_roaming_enable = 0;
3517 #ifdef STA_CFG80211
3518 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
3519 	t_u8 enable = 0;
3520 #endif
3521 #endif
3522 
3523 	ENTER();
3524 
3525 	if (!wdev || !wdev->netdev) {
3526 		LEAVE();
3527 		return -EFAULT;
3528 	}
3529 
3530 	dev = wdev->netdev;
3531 	priv = (moal_private *)woal_get_netdev_priv(dev);
3532 	if (!priv || !priv->phandle) {
3533 		LEAVE();
3534 		return -EFAULT;
3535 	}
3536 
3537 	nla_for_each_attr (iter, data, len, rem) {
3538 		type = nla_type(iter);
3539 		switch (type) {
3540 		case MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONTROL:
3541 			fw_roaming_enable = nla_get_u32(iter);
3542 			break;
3543 		default:
3544 			PRINTM(MERROR, "Unknown type: %d\n", type);
3545 			ret = -EINVAL;
3546 			goto done;
3547 		}
3548 	}
3549 
3550 	PRINTM(MMSG, "FW roaming set enable=%d from wifi hal.\n",
3551 	       fw_roaming_enable);
3552 	ret = woal_enable_fw_roaming(priv, fw_roaming_enable);
3553 	/* Alloc the SKB for vendor_event */
3554 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(t_u32) + 50);
3555 	if (unlikely(!skb)) {
3556 		PRINTM(MERROR, "skb alloc failed\n");
3557 		goto done;
3558 	}
3559 
3560 	nla_put(skb, MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONTROL, sizeof(t_u32),
3561 		&fw_roaming_enable);
3562 	err = cfg80211_vendor_cmd_reply(skb);
3563 	if (unlikely(err))
3564 		PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", err);
3565 
3566 #ifdef STA_CFG80211
3567 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
3568 	if (!fw_roaming_enable)
3569 		woal_cfg80211_vendor_event(priv, event_set_key_mgmt_offload,
3570 					   &enable, sizeof(enable));
3571 #endif
3572 #endif
3573 
3574 done:
3575 	LEAVE();
3576 	return ret;
3577 }
3578 
3579 /**
3580  * @brief vendor command to config blacklist and whitelist for fw roaming
3581  *
3582  * @param wiphy    A pointer to wiphy struct
3583  * @param wdev     A pointer to wireless_dev struct
3584  * @param data     a pointer to data
3585  * @param  len     data length
3586  *
3587  * @return      0: success  fail otherwise
3588  */
woal_cfg80211_subcmd_fw_roaming_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3589 static int woal_cfg80211_subcmd_fw_roaming_config(struct wiphy *wiphy,
3590 						  struct wireless_dev *wdev,
3591 						  const void *data, int len)
3592 {
3593 	moal_private *priv;
3594 	struct net_device *dev;
3595 	int ret = MLAN_STATUS_SUCCESS;
3596 	const struct nlattr *iter;
3597 	int type, rem;
3598 	woal_roam_offload_cfg *roam_offload_cfg = NULL;
3599 	wifi_bssid_params blacklist;
3600 	wifi_ssid_params whitelist;
3601 
3602 	ENTER();
3603 
3604 	if (!wdev || !wdev->netdev) {
3605 		LEAVE();
3606 		return -EFAULT;
3607 	}
3608 
3609 	dev = wdev->netdev;
3610 	priv = (moal_private *)woal_get_netdev_priv(dev);
3611 	if (!priv || !priv->phandle) {
3612 		LEAVE();
3613 		return -EFAULT;
3614 	}
3615 
3616 	memset((char *)&blacklist, 0, sizeof(wifi_bssid_params));
3617 	memset((char *)&whitelist, 0, sizeof(wifi_ssid_params));
3618 	nla_for_each_attr (iter, data, len, rem) {
3619 		type = nla_type(iter);
3620 		switch (type) {
3621 		case MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_BSSID:
3622 			moal_memcpy_ext(priv->phandle, (t_u8 *)&blacklist,
3623 					nla_data(iter), nla_len(iter),
3624 					sizeof(wifi_bssid_params));
3625 			break;
3626 		case MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_CONFIG_SSID:
3627 			moal_memcpy_ext(priv->phandle, (t_u8 *)&whitelist,
3628 					nla_data(iter), nla_len(iter),
3629 					sizeof(wifi_ssid_params));
3630 			break;
3631 		default:
3632 			PRINTM(MERROR, "Unknown type: %d\n", type);
3633 			ret = -EINVAL;
3634 			goto done;
3635 		}
3636 	}
3637 
3638 	if (moal_extflg_isset(priv->phandle, EXT_ROAMOFFLOAD_IN_HS)) {
3639 		/*save blacklist and whitelist in driver*/
3640 		priv->phandle->fw_roam_params.black_list.ap_num =
3641 			blacklist.num_bssid;
3642 		moal_memcpy_ext(
3643 			priv->phandle,
3644 			(t_u8 *)priv->phandle->fw_roam_params.black_list.ap_mac,
3645 			(t_u8 *)blacklist.mac_addr,
3646 			sizeof(wifi_bssid_params) - sizeof(blacklist.num_bssid),
3647 			sizeof(mlan_ds_misc_roam_offload_aplist) -
3648 				sizeof(priv->phandle->fw_roam_params.black_list
3649 					       .ap_num));
3650 		priv->phandle->fw_roam_params.ssid_list.ssid_num =
3651 			whitelist.num_ssid;
3652 		moal_memcpy_ext(
3653 			priv->phandle,
3654 			(t_u8 *)priv->phandle->fw_roam_params.ssid_list.ssids,
3655 			(t_u8 *)whitelist.whitelist_ssid,
3656 			sizeof(wifi_ssid_params) - sizeof(whitelist.num_ssid),
3657 			MAX_SSID_NUM * sizeof(mlan_802_11_ssid));
3658 	} else {
3659 		roam_offload_cfg = (woal_roam_offload_cfg *)kmalloc(
3660 			sizeof(woal_roam_offload_cfg), GFP_KERNEL);
3661 		if (!roam_offload_cfg) {
3662 			PRINTM(MERROR, "kmalloc failed!\n");
3663 			ret = -ENOMEM;
3664 			goto done;
3665 		}
3666 		/*download parameters directly to fw*/
3667 		memset((char *)roam_offload_cfg, 0,
3668 		       sizeof(woal_roam_offload_cfg));
3669 		roam_offload_cfg->black_list.ap_num = blacklist.num_bssid;
3670 		moal_memcpy_ext(priv->phandle,
3671 				(t_u8 *)&roam_offload_cfg->black_list.ap_mac,
3672 				(t_u8 *)blacklist.mac_addr,
3673 				sizeof(wifi_bssid_params) -
3674 					sizeof(blacklist.num_bssid),
3675 				sizeof(mlan_ds_misc_roam_offload_aplist) -
3676 					sizeof(priv->phandle->fw_roam_params
3677 						       .black_list.ap_num));
3678 		roam_offload_cfg->ssid_list.ssid_num = whitelist.num_ssid;
3679 		moal_memcpy_ext(priv->phandle,
3680 				(t_u8 *)&roam_offload_cfg->ssid_list.ssids,
3681 				(t_u8 *)whitelist.whitelist_ssid,
3682 				sizeof(wifi_ssid_params) -
3683 					sizeof(whitelist.num_ssid),
3684 				MAX_SSID_NUM * sizeof(mlan_802_11_ssid));
3685 		if (woal_config_fw_roaming(priv, ROAM_OFFLOAD_PARAM_CFG,
3686 					   roam_offload_cfg)) {
3687 			PRINTM(MERROR, "%s: config fw roaming failed \n",
3688 			       __func__);
3689 			ret = -EFAULT;
3690 		}
3691 	}
3692 
3693 done:
3694 	if (roam_offload_cfg)
3695 		kfree(roam_offload_cfg);
3696 	LEAVE();
3697 	return ret;
3698 }
3699 
3700 /**
3701  * @brief vendor command to enable/disable 11k
3702  *
3703  * @param wiphy         A pointer to wiphy struct
3704  * @param wdev          A pointer to wireless_dev struct
3705  * @param data           a pointer to data
3706  * @param data_len     data length
3707  *
3708  * @return      0: success  <0: fail
3709  */
woal_cfg80211_subcmd_11k_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3710 static int woal_cfg80211_subcmd_11k_cfg(struct wiphy *wiphy,
3711 					struct wireless_dev *wdev,
3712 					const void *data, int data_len)
3713 {
3714 	struct net_device *dev = NULL;
3715 	moal_private *priv = NULL;
3716 	mlan_ioctl_req *req = NULL;
3717 	struct nlattr *tb_vendor[ATTR_ND_OFFLOAD_MAX + 1];
3718 	int ret = 0;
3719 	int status = MLAN_STATUS_SUCCESS;
3720 
3721 	ENTER();
3722 	if (!wdev || !wdev->netdev) {
3723 		LEAVE();
3724 		return -EFAULT;
3725 	}
3726 
3727 	dev = wdev->netdev;
3728 	priv = (moal_private *)woal_get_netdev_priv(dev);
3729 
3730 	nla_parse(tb_vendor, ATTR_ND_OFFLOAD_MAX, (struct nlattr *)data,
3731 		  data_len, NULL
3732 #if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
3733 		  ,
3734 		  NULL
3735 #endif
3736 	);
3737 	if (!tb_vendor[ATTR_ND_OFFLOAD_CONTROL]) {
3738 		PRINTM(MINFO, "%s: ATTR_ND_OFFLOAD not found\n", __func__);
3739 		ret = -EFAULT;
3740 		goto done;
3741 	}
3742 done:
3743 	if (status != MLAN_STATUS_PENDING)
3744 		kfree(req);
3745 
3746 	LEAVE();
3747 	return ret;
3748 }
3749 
3750 /**
3751  * @brief vendor command to set scan mac oui
3752  *
3753  * @param wiphy         A pointer to wiphy struct
3754  * @param wdev          A pointer to wireless_dev struct
3755  * @param data           a pointer to data
3756  * @param data_len     data length
3757  *
3758  * @return      0: success  <0: fail
3759  */
woal_cfg80211_subcmd_set_scan_mac_oui(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)3760 static int woal_cfg80211_subcmd_set_scan_mac_oui(struct wiphy *wiphy,
3761 						 struct wireless_dev *wdev,
3762 						 const void *data, int data_len)
3763 {
3764 	struct net_device *dev = NULL;
3765 	moal_private *priv = NULL;
3766 	struct nlattr *tb_vendor[ATTR_WIFI_MAX + 1];
3767 	t_u8 mac_oui[3];
3768 	int ret = MLAN_STATUS_SUCCESS;
3769 
3770 	ENTER();
3771 
3772 	if (!wdev || !wdev->netdev) {
3773 		LEAVE();
3774 		return -EFAULT;
3775 	}
3776 	dev = wdev->netdev;
3777 	priv = (moal_private *)woal_get_netdev_priv(dev);
3778 
3779 	nla_parse(tb_vendor, ATTR_WIFI_MAX, (struct nlattr *)data, data_len,
3780 		  NULL
3781 #if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
3782 		  ,
3783 		  NULL
3784 #endif
3785 	);
3786 	if (!tb_vendor[ATTR_SCAN_MAC_OUI_SET]) {
3787 		PRINTM(MINFO, "%s: ATTR_SCAN_MAC_OUI_SET not found\n",
3788 		       __func__);
3789 		ret = -EFAULT;
3790 		goto done;
3791 	}
3792 	moal_memcpy_ext(priv->phandle, mac_oui,
3793 			nla_data(tb_vendor[ATTR_SCAN_MAC_OUI_SET]), 3, 3);
3794 	moal_memcpy_ext(priv->phandle, priv->random_mac, priv->current_addr,
3795 			ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
3796 	moal_memcpy_ext(priv->phandle, priv->random_mac, mac_oui, 3,
3797 			MLAN_MAC_ADDR_LENGTH);
3798 	PRINTM(MCMND, "random_mac is " FULL_MACSTR "\n",
3799 	       FULL_MAC2STR(priv->random_mac));
3800 done:
3801 	LEAVE();
3802 	return ret;
3803 }
3804 
3805 /**
3806  * @brief vendor command to start keep alive
3807  *
3808  * @param wiphy    A pointer to wiphy struct
3809  * @param wdev     A pointer to wireless_dev struct
3810  * @param data     a pointer to data
3811  * @param  len     data length
3812  *
3813  * @return      0: success  fail otherwise
3814  */
woal_cfg80211_subcmd_start_keep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3815 static int woal_cfg80211_subcmd_start_keep_alive(struct wiphy *wiphy,
3816 						 struct wireless_dev *wdev,
3817 						 const void *data, int len)
3818 {
3819 	moal_private *priv;
3820 	struct net_device *dev;
3821 	int ret = MLAN_STATUS_SUCCESS;
3822 	int type, rem;
3823 	t_u8 mkeep_alive_id = 0;
3824 	t_u16 ether_type = 0;
3825 	t_u8 *ip_pkt = NULL;
3826 	t_u16 ip_pkt_len = 0;
3827 	t_u8 src_mac[ETH_ALEN];
3828 	t_u8 dst_mac[ETH_ALEN];
3829 	t_u32 period_msec = 0;
3830 	t_u32 retry_interval = 0;
3831 	t_u8 retry_cnt = 0;
3832 	const struct nlattr *iter;
3833 
3834 	ENTER();
3835 
3836 	if (!wdev || !wdev->netdev) {
3837 		LEAVE();
3838 		return -EFAULT;
3839 	}
3840 
3841 	dev = wdev->netdev;
3842 	priv = (moal_private *)woal_get_netdev_priv(dev);
3843 	if (!priv) {
3844 		LEAVE();
3845 		return -EFAULT;
3846 	}
3847 
3848 	nla_for_each_attr (iter, data, len, rem) {
3849 		type = nla_type(iter);
3850 		switch (type) {
3851 		case MKEEP_ALIVE_ATTRIBUTE_ID:
3852 			mkeep_alive_id = nla_get_u8(iter);
3853 			break;
3854 		case MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE:
3855 			ether_type = nla_get_u16(iter);
3856 			break;
3857 		case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
3858 			ip_pkt_len = nla_get_u16(iter);
3859 			if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
3860 				ret = -EINVAL;
3861 				goto exit;
3862 			}
3863 			break;
3864 		case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
3865 			if (ip_pkt_len) {
3866 				if (ip_pkt) {
3867 					kfree(ip_pkt);
3868 					ip_pkt = NULL;
3869 				}
3870 				ip_pkt = (u8 *)kzalloc(ip_pkt_len, GFP_ATOMIC);
3871 				if (ip_pkt == NULL) {
3872 					ret = -ENOMEM;
3873 					PRINTM(MERROR,
3874 					       "Failed to allocate mem for ip packet\n");
3875 					goto exit;
3876 				}
3877 				moal_memcpy_ext(priv->phandle, ip_pkt,
3878 						(u8 *)nla_data(iter),
3879 						nla_len(iter), ip_pkt_len);
3880 			}
3881 			break;
3882 		case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
3883 			moal_memcpy_ext(priv->phandle, src_mac, nla_data(iter),
3884 					nla_len(iter), ETH_ALEN);
3885 			break;
3886 		case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
3887 			moal_memcpy_ext(priv->phandle, dst_mac, nla_data(iter),
3888 					nla_len(iter), ETH_ALEN);
3889 			break;
3890 		case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
3891 			period_msec = nla_get_u32(iter);
3892 			break;
3893 		case MKEEP_ALIVE_ATTRIBUTE_RETRY_INTERVAL:
3894 			retry_interval = nla_get_u32(iter);
3895 			break;
3896 		case MKEEP_ALIVE_ATTRIBUTE_RETRY_CNT:
3897 			retry_cnt = nla_get_u8(iter);
3898 			break;
3899 		default:
3900 			PRINTM(MERROR, "Unknown type: %d\n", type);
3901 			ret = -EINVAL;
3902 			goto exit;
3903 		}
3904 	}
3905 
3906 	ret = woal_priv_save_cloud_keep_alive_params(
3907 		priv, mkeep_alive_id, true, ether_type, ip_pkt, ip_pkt_len,
3908 		src_mac, dst_mac, period_msec, retry_interval, retry_cnt);
3909 	if (ret < 0)
3910 		PRINTM(MERROR, "start_mkeep_alive is failed ret: %d\n", ret);
3911 
3912 exit:
3913 	if (ip_pkt)
3914 		kfree(ip_pkt);
3915 
3916 	LEAVE();
3917 	return ret;
3918 }
3919 
3920 /**
3921  * @brief vendor command to stop keep alive
3922  *
3923  * @param wiphy    A pointer to wiphy struct
3924  * @param wdev     A pointer to wireless_dev struct
3925  * @param data     a pointer to data
3926  * @param  len     data length
3927  *
3928  * @return      0: success  fail otherwise
3929  */
woal_cfg80211_subcmd_stop_keep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3930 static int woal_cfg80211_subcmd_stop_keep_alive(struct wiphy *wiphy,
3931 						struct wireless_dev *wdev,
3932 						const void *data, int len)
3933 {
3934 	moal_private *priv;
3935 	struct net_device *dev;
3936 	int ret = MLAN_STATUS_SUCCESS;
3937 	int type, rem;
3938 	t_u8 mkeep_alive_id = 0;
3939 	const struct nlattr *iter;
3940 
3941 	ENTER();
3942 
3943 	if (!wdev || !wdev->netdev) {
3944 		LEAVE();
3945 		return -EFAULT;
3946 	}
3947 
3948 	dev = wdev->netdev;
3949 	priv = (moal_private *)woal_get_netdev_priv(dev);
3950 	if (!priv) {
3951 		LEAVE();
3952 		return -EFAULT;
3953 	}
3954 
3955 	nla_for_each_attr (iter, data, len, rem) {
3956 		type = nla_type(iter);
3957 		switch (type) {
3958 		case MKEEP_ALIVE_ATTRIBUTE_ID:
3959 			mkeep_alive_id = nla_get_u8(iter);
3960 			break;
3961 		default:
3962 			PRINTM(MERROR, "Unknown type: %d\n", type);
3963 			ret = -EINVAL;
3964 			break;
3965 		}
3966 	}
3967 
3968 	ret = woal_stop_mkeep_alive(priv, mkeep_alive_id, 0, NULL, NULL);
3969 	if (ret < 0)
3970 		PRINTM(MERROR, "stop_mkeep_alive is failed ret: %d\n", ret);
3971 
3972 	LEAVE();
3973 	return ret;
3974 }
3975 
3976 /**
3977  * @brief               Upload last keep alive packet to Host through vendor
3978  event
3979  *
3980  * @param priv          Pointer to moal_private structure
3981  * @param mkeep_alive   Pointer to mlan_ds_misc_keep_alive structure
3982 
3983  * @return      0: success  fail otherwise
3984  */
woal_mkeep_alive_vendor_event(moal_private * priv,mlan_ds_misc_keep_alive * mkeep_alive)3985 int woal_mkeep_alive_vendor_event(moal_private *priv,
3986 				  mlan_ds_misc_keep_alive *mkeep_alive)
3987 {
3988 	struct wiphy *wiphy = priv->wdev->wiphy;
3989 	struct sk_buff *skb = NULL;
3990 	int ret = MLAN_STATUS_SUCCESS;
3991 	int event_id = 0;
3992 	t_u16 len = 0;
3993 
3994 	ENTER();
3995 
3996 	event_id = woal_get_event_id(event_cloud_keep_alive);
3997 	if (event_max == event_id) {
3998 		PRINTM(MERROR, "Not find this event %d\n", event_id);
3999 		ret = MLAN_STATUS_FAILURE;
4000 		goto done;
4001 	}
4002 	if (!mkeep_alive) {
4003 		PRINTM(MERROR, "Parameter is NULL\n");
4004 		ret = MLAN_STATUS_FAILURE;
4005 		goto done;
4006 	}
4007 	len = mkeep_alive->pkt_len;
4008 
4009 	/**allocate skb*/
4010 #if KERNEL_VERSION(4, 1, 0) <= CFG80211_VERSION_CODE
4011 	skb = cfg80211_vendor_event_alloc(wiphy, priv->wdev, len + 50,
4012 #else
4013 	skb = cfg80211_vendor_event_alloc(wiphy, len + 50,
4014 #endif
4015 					  event_id, GFP_ATOMIC);
4016 
4017 	if (!skb) {
4018 		PRINTM(MERROR, "allocate memory fail for vendor event\n");
4019 		ret = MLAN_STATUS_FAILURE;
4020 		goto done;
4021 	}
4022 
4023 	nla_put(skb, MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN, sizeof(t_u16), &len);
4024 	nla_put(skb, MKEEP_ALIVE_ATTRIBUTE_IP_PKT, len, mkeep_alive->packet);
4025 
4026 	/**send event*/
4027 	cfg80211_vendor_event(skb, GFP_ATOMIC);
4028 
4029 done:
4030 	LEAVE();
4031 	return ret;
4032 }
4033 
4034 /**
4035  * @brief vendor command to set enable/disable dfs offload
4036  *
4037  * @param wiphy       A pointer to wiphy struct
4038  * @param wdev     A pointer to wireless_dev struct
4039  * @param data     a pointer to data
4040  * @param  len     data length
4041  *
4042  * @return      0: success  1: fail
4043  */
woal_cfg80211_subcmd_set_dfs_offload(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)4044 static int woal_cfg80211_subcmd_set_dfs_offload(struct wiphy *wiphy,
4045 						struct wireless_dev *wdev,
4046 						const void *data, int data_len)
4047 {
4048 	struct sk_buff *skb = NULL;
4049 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
4050 	int dfs_offload;
4051 	int ret = 1;
4052 
4053 	ENTER();
4054 	dfs_offload = moal_extflg_isset(handle, EXT_DFS_OFFLOAD);
4055 
4056 	/** Allocate skb for cmd reply*/
4057 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(dfs_offload));
4058 	if (!skb) {
4059 		PRINTM(MERROR, "allocate memory fail for vendor cmd\n");
4060 		ret = 1;
4061 		LEAVE();
4062 		return ret;
4063 	}
4064 	nla_put(skb, MRVL_WLAN_VENDOR_ATTR_DFS, sizeof(t_u32), &dfs_offload);
4065 	ret = cfg80211_vendor_cmd_reply(skb);
4066 
4067 	LEAVE();
4068 	return ret;
4069 }
4070 
4071 #define CSI_DUMP_FILE_MAX 1200000
4072 
4073 /**
4074  * @brief vendor command to set CSI params
4075  *
4076  * @param wiphy    A pointer to wiphy struct
4077  * @param wdev     A pointer to wireless_dev struct
4078  * @param data     a pointer to data
4079  * @param len     data length
4080  * @param csi_enable    enable/disable CSI
4081  *
4082  * @return      0: success  -1: fail
4083  */
woal_cfg80211_subcmd_set_csi(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len,int csi_enable)4084 static int woal_cfg80211_subcmd_set_csi(struct wiphy *wiphy,
4085 					struct wireless_dev *wdev,
4086 					const void *data, int len,
4087 					int csi_enable)
4088 {
4089 	struct net_device *dev = NULL;
4090 	moal_private *priv = NULL;
4091 	mlan_ioctl_req *req = NULL;
4092 	mlan_ds_misc_cfg *cfg = NULL;
4093 	struct nlattr *tb_vendor[ATTR_CSI_MAX + 1];
4094 	int ret = 0;
4095 	int status = MLAN_STATUS_SUCCESS;
4096 
4097 	ENTER();
4098 
4099 	if (!wdev || !wdev->netdev) {
4100 		LEAVE();
4101 		return -EFAULT;
4102 	}
4103 	dev = wdev->netdev;
4104 	priv = (moal_private *)woal_get_netdev_priv(dev);
4105 
4106 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
4107 	if (req == NULL) {
4108 		PRINTM(MERROR, "Could not allocate mlan ioctl request!\n");
4109 		ret = -EFAULT;
4110 		goto done;
4111 	}
4112 	req->req_id = MLAN_IOCTL_MISC_CFG;
4113 	cfg = (mlan_ds_misc_cfg *)req->pbuf;
4114 	cfg->sub_command = MLAN_OID_MISC_CSI;
4115 
4116 	priv->csi_enable = csi_enable;
4117 	if (csi_enable == 1) {
4118 		nla_parse(tb_vendor, ATTR_CSI_MAX, (struct nlattr *)data, len,
4119 			  NULL
4120 #if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
4121 			  ,
4122 			  NULL
4123 #endif
4124 		);
4125 		if (!tb_vendor[ATTR_CSI_CONFIG]) {
4126 			ret = -EFAULT;
4127 			goto done;
4128 		}
4129 		moal_memcpy_ext(priv->phandle, &cfg->param.csi_params,
4130 				(mlan_ds_csi_params *)nla_data(
4131 					tb_vendor[ATTR_CSI_CONFIG]),
4132 				sizeof(mlan_ds_csi_params),
4133 				sizeof(mlan_ds_csi_params));
4134 		moal_memcpy_ext(priv->phandle, &priv->csi_config,
4135 				&cfg->param.csi_params,
4136 				sizeof(mlan_ds_csi_params),
4137 				sizeof(mlan_ds_csi_params));
4138 		if (tb_vendor[ATTR_CSI_DUMP_FORMAT])
4139 			priv->csi_dump_format =
4140 				nla_get_u8(tb_vendor[ATTR_CSI_DUMP_FORMAT]);
4141 	} else if (csi_enable == 0) {
4142 		nla_parse(tb_vendor, ATTR_CSI_MAX, (struct nlattr *)data, len,
4143 			  NULL
4144 #if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
4145 			  ,
4146 			  NULL
4147 #endif
4148 		);
4149 		if (!tb_vendor[ATTR_PEER_MAC_ADDR]) {
4150 			ret = -EFAULT;
4151 			goto done;
4152 		}
4153 		memset(&cfg->param.csi_params, 0, sizeof(mlan_ds_csi_params));
4154 		moal_memcpy_ext(priv->phandle,
4155 				cfg->param.csi_params.csi_filter[0].mac_addr,
4156 				(t_u8 *)nla_data(tb_vendor[ATTR_PEER_MAC_ADDR]),
4157 				MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
4158 	}
4159 
4160 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4161 	if (status != MLAN_STATUS_SUCCESS) {
4162 		ret = -EFAULT;
4163 		goto done;
4164 	}
4165 
4166 done:
4167 	if (status != MLAN_STATUS_PENDING)
4168 		kfree(req);
4169 	LEAVE();
4170 	return ret;
4171 }
4172 
4173 /**
4174  * @brief vendor command to enable CSI
4175  *
4176  * @param wiphy    A pointer to wiphy struct
4177  * @param wdev     A pointer to wireless_dev struct
4178  * @param data     a pointer to data
4179  * @param len     data length
4180  *
4181  * @return      0: success  -1: fail
4182  */
woal_cfg80211_subcmd_csi_enable(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)4183 static int woal_cfg80211_subcmd_csi_enable(struct wiphy *wiphy,
4184 					   struct wireless_dev *wdev,
4185 					   const void *data, int len)
4186 {
4187 	int ret = 0;
4188 
4189 	ENTER();
4190 
4191 	ret = woal_cfg80211_subcmd_set_csi(wiphy, wdev, data, len, 1);
4192 
4193 	LEAVE();
4194 	return ret;
4195 }
4196 
4197 /**
4198  * @brief vendor command to disable CSI
4199  *
4200  * @param wiphy    A pointer to wiphy struct
4201  * @param wdev     A pointer to wireless_dev struct
4202  * @param data     a pointer to data
4203  * @param len     data length
4204  *
4205  * @return      0: success  -1: fail
4206  */
woal_cfg80211_subcmd_csi_disable(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)4207 static int woal_cfg80211_subcmd_csi_disable(struct wiphy *wiphy,
4208 					    struct wireless_dev *wdev,
4209 					    const void *data, int len)
4210 {
4211 	int ret = 0;
4212 
4213 	ENTER();
4214 
4215 	ret = woal_cfg80211_subcmd_set_csi(wiphy, wdev, data, len, 0);
4216 
4217 	LEAVE();
4218 	return ret;
4219 }
4220 
4221 /**
4222  * @brief vendor command to get CSI dump path
4223  *
4224  * @param wiphy    A pointer to wiphy struct
4225  * @param wdev     A pointer to wireless_dev struct
4226  * @param data     a pointer to data
4227  * @param len     data length
4228  *
4229  * @return      0: success  -1: fail
4230  */
woal_cfg80211_subcmd_get_csi_dump_path(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)4231 static int woal_cfg80211_subcmd_get_csi_dump_path(struct wiphy *wiphy,
4232 						  struct wireless_dev *wdev,
4233 						  const void *data, int len)
4234 {
4235 	int ret = 0;
4236 	struct net_device *dev = NULL;
4237 	moal_private *priv = NULL;
4238 	struct sk_buff *skb = NULL;
4239 
4240 	ENTER();
4241 
4242 	if (!wdev || !wdev->netdev) {
4243 		LEAVE();
4244 		return -EFAULT;
4245 	}
4246 	dev = wdev->netdev;
4247 	priv = (moal_private *)woal_get_netdev_priv(dev);
4248 
4249 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
4250 						  sizeof(priv->csi_dump_path));
4251 	if (unlikely(!skb)) {
4252 		PRINTM(MERROR, "skb alloc failed\n");
4253 		ret = MLAN_STATUS_FAILURE;
4254 		goto done;
4255 	}
4256 
4257 	/* Push the data to the skb */
4258 	nla_put(skb, ATTR_CSI_DUMP_PATH, sizeof(priv->csi_dump_path),
4259 		(t_u8 *)priv->csi_dump_path);
4260 
4261 	ret = cfg80211_vendor_cmd_reply(skb);
4262 	if (unlikely(ret)) {
4263 		PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", ret);
4264 		goto done;
4265 	}
4266 
4267 done:
4268 	LEAVE();
4269 	return ret;
4270 }
4271 
4272 /**
4273  * @brief vendor command to get CSI config
4274  *
4275  * @param wiphy    A pointer to wiphy struct
4276  * @param wdev     A pointer to wireless_dev struct
4277  * @param data     a pointer to data
4278  * @param len     data length
4279  *
4280  * @return      0: success  -1: fail
4281  */
woal_cfg80211_subcmd_get_csi_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)4282 static int woal_cfg80211_subcmd_get_csi_config(struct wiphy *wiphy,
4283 					       struct wireless_dev *wdev,
4284 					       const void *data, int len)
4285 {
4286 	int ret = 0;
4287 	struct net_device *dev = NULL;
4288 	moal_private *priv = NULL;
4289 	struct sk_buff *skb = NULL;
4290 
4291 	ENTER();
4292 
4293 	if (!wdev || !wdev->netdev) {
4294 		LEAVE();
4295 		return -EFAULT;
4296 	}
4297 	dev = wdev->netdev;
4298 	priv = (moal_private *)woal_get_netdev_priv(dev);
4299 
4300 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
4301 						  sizeof(priv->csi_config));
4302 	if (unlikely(!skb)) {
4303 		PRINTM(MERROR, "skb alloc failed\n");
4304 		ret = MLAN_STATUS_FAILURE;
4305 		goto done;
4306 	}
4307 	/* Push the data to the skb */
4308 	nla_put(skb, ATTR_CSI_CONFIG, sizeof(mlan_ds_csi_params),
4309 		(t_u8 *)&priv->csi_config);
4310 
4311 	ret = cfg80211_vendor_cmd_reply(skb);
4312 	if (unlikely(ret)) {
4313 		PRINTM(MERROR, "Vendor Command reply failed ret:%d\n", ret);
4314 		goto done;
4315 	}
4316 
4317 done:
4318 	LEAVE();
4319 	return ret;
4320 }
4321 
4322 /**
4323  * @brief vendor command to get CSI capability
4324  *
4325  * @param wiphy    A pointer to wiphy struct
4326  * @param wdev     A pointer to wireless_dev struct
4327  * @param data     a pointer to data
4328  * @param len     data length
4329  *
4330  * @return      0: success  -1: fail
4331  */
woal_cfg80211_subcmd_get_csi_capa(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)4332 static int woal_cfg80211_subcmd_get_csi_capa(struct wiphy *wiphy,
4333 					     struct wireless_dev *wdev,
4334 					     const void *data, int len)
4335 {
4336 	ENTER();
4337 	LEAVE();
4338 	return 0;
4339 }
4340 
4341 /**
4342  * @brief Save CSI dump to file
4343  *
4344  * @param dir_name    Directory name
4345  * @param file_name    File name
4346  * @param buf    Pointer to dump buffer
4347  * @param buf_len    Length of buf
4348  * @param name    Full path name of CSI dump
4349  *
4350  * @return      0: success  -1: fail
4351  */
woal_save_csi_dump_to_file(char * dir_name,char * file_name,t_u8 * buf,int buf_len,t_u8 format,char * name)4352 static mlan_status woal_save_csi_dump_to_file(char *dir_name, char *file_name,
4353 					      t_u8 *buf, int buf_len,
4354 					      t_u8 format, char *name)
4355 {
4356 	mlan_status ret = MLAN_STATUS_SUCCESS;
4357 	ENTER();
4358 
4359 	if (!dir_name || !file_name || !buf) {
4360 		PRINTM(MERROR, "Can't save dump info to file\n");
4361 		ret = MLAN_STATUS_FAILURE;
4362 		goto done;
4363 	}
4364 done:
4365 	LEAVE();
4366 	return ret;
4367 }
4368 
4369 /**
4370  * @brief vendor event to upload csi dump
4371  *
4372  * @param priv     A pointer to moal_private
4373  * @param data     a pointer to data
4374  * @param  len     data length
4375  *
4376  * @return      mlan_status
4377  */
woal_cfg80211_event_csi_dump(moal_private * priv,t_u8 * data,int len)4378 mlan_status woal_cfg80211_event_csi_dump(moal_private *priv, t_u8 *data,
4379 					 int len)
4380 {
4381 	mlan_status ret = MLAN_STATUS_SUCCESS;
4382 	char path_name[20];
4383 	char file_name[20];
4384 
4385 	ENTER();
4386 
4387 	DBG_HEXDUMP(MCMD_D, "CSI dump data", data, len);
4388 	sprintf(path_name, "/data");
4389 	if (priv->csi_dump_format == 1)
4390 		sprintf(file_name, "csi_dump.bin");
4391 	else
4392 		sprintf(file_name, "csi_dump.txt");
4393 	priv->csi_dump_len += len;
4394 	if (priv->csi_dump_len > CSI_DUMP_FILE_MAX) {
4395 		PRINTM(MERROR,
4396 		       "Reached file maximum size. Not saving CSI records.\n");
4397 		goto done;
4398 	}
4399 	/* Save CSI dump to file */
4400 	ret = woal_save_csi_dump_to_file(path_name, file_name, data, len,
4401 					 priv->csi_dump_format,
4402 					 priv->csi_dump_path);
4403 	if (ret != MLAN_STATUS_SUCCESS) {
4404 		PRINTM(MERROR, "Failed to save CSI dump to file\n");
4405 		goto done;
4406 	}
4407 
4408 done:
4409 	LEAVE();
4410 	return ret;
4411 }
4412 
4413 // clang-format off
4414 static const struct wiphy_vendor_command vendor_commands[] = {
4415 	{
4416 		.info = {
4417 				.vendor_id = MRVL_VENDOR_ID,
4418 				.subcmd = sub_cmd_set_drvdbg,
4419 			},
4420 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4421 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4422 		.doit = woal_cfg80211_subcmd_set_drvdbg,
4423 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4424 		.policy = VENDOR_CMD_RAW_DATA,
4425 #endif
4426 	},
4427 	{
4428 		.info = {
4429 				.vendor_id = MRVL_VENDOR_ID,
4430 				.subcmd = sub_cmd_get_valid_channels,
4431 			},
4432 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4433 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4434 		.doit = woal_cfg80211_subcmd_get_valid_channels,
4435 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4436 		.policy = woal_attr_policy,
4437 		.maxattr = ATTR_WIFI_MAX,
4438 #endif
4439 	},
4440 	{
4441 		.info = {
4442 				.vendor_id = MRVL_VENDOR_ID,
4443 				.subcmd = sub_cmd_set_scan_mac_oui,
4444 			},
4445 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4446 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4447 		.doit = woal_cfg80211_subcmd_set_scan_mac_oui,
4448 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4449 		.policy = woal_attr_policy,
4450 		.maxattr = ATTR_WIFI_MAX,
4451 #endif
4452 	},
4453 	{
4454 		.info = {
4455 				.vendor_id = MRVL_VENDOR_ID,
4456 				.subcmd = sub_cmd_link_statistic_set,
4457 			},
4458 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4459 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4460 		.doit = woal_cfg80211_subcmd_link_statistic_set,
4461 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4462 		.policy = woal_ll_stat_policy,
4463 		.maxattr = ATTR_LL_STATS_MAX,
4464 #endif
4465 	},
4466 	{
4467 		.info = {
4468 				.vendor_id = MRVL_VENDOR_ID,
4469 				.subcmd = sub_cmd_link_statistic_get,
4470 			},
4471 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4472 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4473 		.doit = woal_cfg80211_subcmd_link_statistic_get,
4474 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4475 		.policy = VENDOR_CMD_RAW_DATA,
4476 #endif
4477 	},
4478 	{
4479 		.info = {
4480 				.vendor_id = MRVL_VENDOR_ID,
4481 				.subcmd = sub_cmd_link_statistic_clr,
4482 			},
4483 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4484 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4485 		.doit = woal_cfg80211_subcmd_link_statistic_clr,
4486 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4487 		.policy = woal_ll_stat_policy,
4488 		.maxattr = ATTR_LL_STATS_MAX,
4489 #endif
4490 	},
4491 #ifdef STA_CFG80211
4492 	{
4493 		.info = {
4494 				.vendor_id = MRVL_VENDOR_ID,
4495 				.subcmd = sub_cmd_rssi_monitor,
4496 			},
4497 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4498 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4499 		.doit = woal_cfg80211_subcmd_rssi_monitor,
4500 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4501 		.policy = woal_rssi_monitor_policy,
4502 		.maxattr = ATTR_RSSI_MONITOR_MAX,
4503 #endif
4504 	},
4505 #endif
4506 	{
4507 		.info = {
4508 				.vendor_id = MRVL_VENDOR_ID,
4509 				.subcmd = sub_cmd_set_roaming_offload_key,
4510 			},
4511 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4512 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4513 		.doit = woal_cfg80211_subcmd_set_roaming_offload_key,
4514 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4515 		.policy = VENDOR_CMD_RAW_DATA,
4516 #endif
4517 	},
4518 	{
4519 		.info = {
4520 				.vendor_id = MRVL_VENDOR_ID,
4521 				.subcmd = sub_cmd_get_roaming_capability,
4522 			},
4523 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4524 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4525 		.doit = woal_cfg80211_subcmd_get_roaming_capability,
4526 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4527 		.policy = VENDOR_CMD_RAW_DATA,
4528 #endif
4529 	},
4530 	{
4531 		.info = {
4532 				.vendor_id = MRVL_VENDOR_ID,
4533 				.subcmd = sub_cmd_fw_roaming_enable,
4534 			},
4535 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4536 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4537 		.doit = woal_cfg80211_subcmd_fw_roaming_enable,
4538 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4539 		.policy = woal_fw_roaming_policy,
4540 		.maxattr = MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_MAX,
4541 #endif
4542 	},
4543 	{
4544 		.info = {
4545 				.vendor_id = MRVL_VENDOR_ID,
4546 				.subcmd = sub_cmd_fw_roaming_config,
4547 			},
4548 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4549 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4550 		.doit = woal_cfg80211_subcmd_fw_roaming_config,
4551 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4552 		.policy = woal_fw_roaming_policy,
4553 		.maxattr = MRVL_WLAN_VENDOR_ATTR_FW_ROAMING_MAX,
4554 #endif
4555 	},
4556 	{
4557 		.info = {
4558 				.vendor_id = MRVL_VENDOR_ID,
4559 				.subcmd = sub_cmd_start_keep_alive,
4560 			},
4561 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4562 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4563 		.doit = woal_cfg80211_subcmd_start_keep_alive,
4564 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4565 		.policy = woal_keep_alive_policy,
4566 		.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX,
4567 #endif
4568 	},
4569 	{
4570 		.info = {
4571 				.vendor_id = MRVL_VENDOR_ID,
4572 				.subcmd = sub_cmd_stop_keep_alive,
4573 			},
4574 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4575 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4576 		.doit = woal_cfg80211_subcmd_stop_keep_alive,
4577 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4578 		.policy = VENDOR_CMD_RAW_DATA,
4579 #endif
4580 	},
4581 	{
4582 		.info = {
4583 				.vendor_id = MRVL_VENDOR_ID,
4584 				.subcmd = sub_cmd_dfs_capability,
4585 			},
4586 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4587 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4588 		.doit = woal_cfg80211_subcmd_set_dfs_offload,
4589 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4590 		.policy = VENDOR_CMD_RAW_DATA,
4591 #endif
4592 	},
4593 
4594 
4595 	{
4596 		.info = {
4597 				.vendor_id = MRVL_VENDOR_ID,
4598 				.subcmd = sub_cmd_nd_offload
4599 			},
4600 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4601 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4602 		.doit = woal_cfg80211_subcmd_11k_cfg,
4603 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4604 		.policy = woal_nd_offload_policy,
4605 		.maxattr = ATTR_ND_OFFLOAD_MAX,
4606 #endif
4607 	},
4608 	{
4609 		.info = {
4610 				.vendor_id = MRVL_VENDOR_ID,
4611 				.subcmd = sub_cmd_get_drv_version,
4612 			},
4613 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4614 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4615 		.doit = woal_cfg80211_subcmd_get_drv_version,
4616 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4617 		.policy = VENDOR_CMD_RAW_DATA,
4618 #endif
4619 	},
4620 	{
4621 		.info = {
4622 				.vendor_id = MRVL_VENDOR_ID,
4623 				.subcmd = sub_cmd_get_fw_version,
4624 			},
4625 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4626 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4627 		.doit = woal_cfg80211_subcmd_get_fw_version,
4628 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4629 		.policy = VENDOR_CMD_RAW_DATA,
4630 #endif
4631 	},
4632 	{
4633 		.info = {
4634 				.vendor_id = MRVL_VENDOR_ID,
4635 				.subcmd = sub_cmd_get_wifi_supp_feature_set,
4636 			},
4637 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4638 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4639 		.doit = woal_cfg80211_subcmd_get_supp_feature_set,
4640 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4641 		.policy = VENDOR_CMD_RAW_DATA,
4642 #endif
4643 	},
4644 	{
4645 		.info = {
4646 				.vendor_id = MRVL_VENDOR_ID,
4647 				.subcmd = sub_cmd_set_country_code,
4648 			},
4649 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4650 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4651 		.doit = woal_cfg80211_subcmd_set_country_code,
4652 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4653 		.policy = VENDOR_CMD_RAW_DATA,
4654 #endif
4655 	},
4656 	{
4657 		.info = {
4658 				.vendor_id = MRVL_VENDOR_ID,
4659 				.subcmd =
4660 				   sub_cmd_get_wifi_logger_supp_feature_set,
4661 			},
4662 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4663 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4664 		.doit = woal_cfg80211_subcmd_get_wifi_logger_supp_feature_set,
4665 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4666 		.policy = woal_logger_policy,
4667 		.maxattr = ATTR_WIFI_LOGGER_MAX,
4668 #endif
4669 	},
4670 	{
4671 		.info = {
4672 				.vendor_id = MRVL_VENDOR_ID,
4673 				.subcmd = sub_cmd_get_ring_buff_status,
4674 			},
4675 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4676 			 WIPHY_VENDOR_CMD_NEED_NETDEV |
4677 			 WIPHY_VENDOR_CMD_NEED_RUNNING,
4678 		.doit = woal_cfg80211_subcmd_get_ring_buff_status,
4679 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4680 		.policy = woal_logger_policy,
4681 		.maxattr = ATTR_WIFI_LOGGER_MAX,
4682 #endif
4683 	},
4684 	{
4685 		.info = {
4686 				.vendor_id = MRVL_VENDOR_ID,
4687 				.subcmd = sub_cmd_start_logging,
4688 			},
4689 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4690 			 WIPHY_VENDOR_CMD_NEED_NETDEV |
4691 			 WIPHY_VENDOR_CMD_NEED_RUNNING,
4692 		.doit = woal_cfg80211_subcmd_start_logging,
4693 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4694 		.policy = woal_logger_policy,
4695 		.maxattr = ATTR_WIFI_LOGGER_MAX,
4696 #endif
4697 	},
4698 	{
4699 		.info = {
4700 				.vendor_id = MRVL_VENDOR_ID,
4701 				.subcmd = sub_cmd_get_ring_buff_data,
4702 			},
4703 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4704 			 WIPHY_VENDOR_CMD_NEED_NETDEV |
4705 			 WIPHY_VENDOR_CMD_NEED_RUNNING,
4706 		.doit = woal_cfg80211_subcmd_get_ring_data,
4707 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4708 		.policy = woal_logger_policy,
4709 		.maxattr = ATTR_WIFI_LOGGER_MAX,
4710 #endif
4711 	},
4712 	{
4713 		.info = {
4714 				.vendor_id = MRVL_VENDOR_ID,
4715 				.subcmd = sub_cmd_start_packet_fate_monitor,
4716 			},
4717 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4718 			 WIPHY_VENDOR_CMD_NEED_NETDEV |
4719 			 WIPHY_VENDOR_CMD_NEED_RUNNING,
4720 		.doit = woal_cfg80211_subcmd_start_packet_fate_monitor,
4721 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4722 		.policy = VENDOR_CMD_RAW_DATA,
4723 #endif
4724 	},
4725 	{
4726 		.info = {
4727 				.vendor_id = MRVL_VENDOR_ID,
4728 				.subcmd = sub_cmd_get_fw_mem_dump,
4729 			},
4730 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4731 			 WIPHY_VENDOR_CMD_NEED_NETDEV |
4732 			 WIPHY_VENDOR_CMD_NEED_RUNNING,
4733 		.doit = woal_cfg80211_subcmd_get_fw_dump,
4734 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4735 		.policy = VENDOR_CMD_RAW_DATA,
4736 #endif
4737 	},
4738 	{
4739 		.info = {
4740 				.vendor_id = MRVL_VENDOR_ID,
4741 				.subcmd = sub_cmd_get_drv_mem_dump,
4742 			},
4743 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4744 			 WIPHY_VENDOR_CMD_NEED_NETDEV |
4745 			 WIPHY_VENDOR_CMD_NEED_RUNNING,
4746 		.doit = woal_cfg80211_subcmd_get_drv_dump,
4747 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4748 		.policy = VENDOR_CMD_RAW_DATA,
4749 #endif
4750 	},
4751 	{
4752 		.info = {
4753 				.vendor_id = MRVL_VENDOR_ID,
4754 				.subcmd = sub_cmd_set_packet_filter,
4755 			},
4756 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4757 			 WIPHY_VENDOR_CMD_NEED_NETDEV |
4758 			 WIPHY_VENDOR_CMD_NEED_RUNNING,
4759 		.doit = woal_cfg80211_subcmd_set_packet_filter,
4760 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4761 		.policy = woal_packet_filter_policy,
4762 		.maxattr = ATTR_PACKET_FILTER_MAX,
4763 #endif
4764 	},
4765 	{
4766 		.info = {
4767 				.vendor_id = MRVL_VENDOR_ID,
4768 				.subcmd = sub_cmd_get_packet_filter_capability,
4769 			},
4770 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4771 			 WIPHY_VENDOR_CMD_NEED_NETDEV |
4772 			 WIPHY_VENDOR_CMD_NEED_RUNNING,
4773 		.doit = woal_cfg80211_subcmd_get_packet_filter_capability,
4774 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4775 		.policy = VENDOR_CMD_RAW_DATA,
4776 #endif
4777 	},
4778 	{
4779 		.info = {
4780 				.vendor_id = MRVL_VENDOR_ID,
4781 				.subcmd = subcmd_cfr_request,
4782 			},
4783 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4784 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4785 		.doit = woal_cfg80211_subcmd_csi_enable,
4786 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4787 		.policy = VENDOR_CMD_RAW_DATA,
4788 #endif
4789 	},
4790 	{
4791 		.info = {
4792 				.vendor_id = MRVL_VENDOR_ID,
4793 				.subcmd = subcmd_cfr_cancel,
4794 			},
4795 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4796 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4797 		.doit = woal_cfg80211_subcmd_csi_disable,
4798 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4799 		.policy = VENDOR_CMD_RAW_DATA,
4800 #endif
4801 	},
4802 	{
4803 		.info = {
4804 				.vendor_id = MRVL_VENDOR_ID,
4805 				.subcmd = subcmd_get_csi_dump_path,
4806 			},
4807 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4808 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4809 		.doit = woal_cfg80211_subcmd_get_csi_dump_path,
4810 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4811 		.policy = VENDOR_CMD_RAW_DATA,
4812 #endif
4813 	},
4814 	{
4815 		.info = {
4816 				.vendor_id = MRVL_VENDOR_ID,
4817 				.subcmd = subcmd_get_csi_config,
4818 			},
4819 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4820 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4821 		.doit = woal_cfg80211_subcmd_get_csi_config,
4822 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4823 		.policy = VENDOR_CMD_RAW_DATA,
4824 #endif
4825 	},
4826 	{
4827 		.info = {
4828 				.vendor_id = MRVL_VENDOR_ID,
4829 				.subcmd = subcmd_get_csi_capa,
4830 			},
4831 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4832 			 WIPHY_VENDOR_CMD_NEED_NETDEV,
4833 		.doit = woal_cfg80211_subcmd_get_csi_capa,
4834 #if KERNEL_VERSION(5, 3, 0) <= CFG80211_VERSION_CODE
4835 		.policy = VENDOR_CMD_RAW_DATA,
4836 #endif
4837 	},
4838 };
4839 // clang-format on
4840 
4841 /**
4842  * @brief register vendor commands and events
4843  *
4844  * @param wiphy       A pointer to wiphy struct
4845  *
4846  * @return
4847  */
woal_register_cfg80211_vendor_command(struct wiphy * wiphy)4848 void woal_register_cfg80211_vendor_command(struct wiphy *wiphy)
4849 {
4850 	ENTER();
4851 	wiphy->vendor_commands = vendor_commands;
4852 	wiphy->n_vendor_commands = ARRAY_SIZE(vendor_commands);
4853 	wiphy->vendor_events = vendor_events;
4854 	wiphy->n_vendor_events = ARRAY_SIZE(vendor_events);
4855 	LEAVE();
4856 }
4857 #endif
4858