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