1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Portions copyright (C) 2023 Broadcom Limited
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <stdint.h>
20 #include <fcntl.h>
21 #include <sys/socket.h>
22 #include <netlink/genl/genl.h>
23 #include <netlink/genl/family.h>
24 #include <netlink/genl/ctrl.h>
25 #include <linux/rtnetlink.h>
26 #include <netpacket/packet.h>
27 #include <linux/filter.h>
28 #include <linux/errqueue.h>
29 
30 #include <linux/pkt_sched.h>
31 #include <netlink/object-api.h>
32 #include <netlink/netlink.h>
33 #include <netlink/socket.h>
34 #include <netlink/handlers.h>
35 
36 #include "sync.h"
37 
38 #define LOG_TAG  "WifiHAL"
39 
40 #include <utils/Log.h>
41 
42 #include <hardware_legacy/wifi_hal.h>
43 #include "common.h"
44 #include "cpp_bindings.h"
45 
46 typedef enum {
47     ANDR_WIFI_ATTRIBUTE_INVALID        = 0,
48     ANDR_WIFI_ATTRIBUTE_NUM_RADIO      = 1,
49     ANDR_WIFI_ATTRIBUTE_STATS_INFO     = 2,
50     ANDR_WIFI_ATTRIBUTE_ML_STATS_INFO  = 3,
51     ANDR_WIFI_ATTRIBUTE_STATS_MAX      = 4
52 } LINK_STAT_ATTRIBUTE;
53 
54 /* Internal radio statistics structure in the driver */
55 typedef struct {
56 	wifi_radio radio;
57 	uint32_t on_time;
58 	uint32_t tx_time;
59 	uint32_t rx_time;
60 	uint32_t on_time_scan;
61 	uint32_t on_time_nbd;
62 	uint32_t on_time_gscan;
63 	uint32_t on_time_roam_scan;
64 	uint32_t on_time_pno_scan;
65 	uint32_t on_time_hs20;
66 	uint32_t num_channels;
67 	wifi_channel_stat channels[];
68 } wifi_radio_stat_internal;
69 
70 enum {
71     LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
72 };
73 
74 class GetLinkStatsCommand : public WifiCommand
75 {
76     wifi_stats_result_handler mHandler;
77 public:
GetLinkStatsCommand(wifi_interface_handle iface,wifi_stats_result_handler handler)78     GetLinkStatsCommand(wifi_interface_handle iface, wifi_stats_result_handler handler)
79         : WifiCommand("GetLinkStatsCommand", iface, 0), mHandler(handler)
80     { }
81 
create()82     virtual int create() {
83         ALOGI("Creating message to get link statistics; iface = %d", mIfaceInfo->id);
84 
85         int ret = mMsg.create(GOOGLE_OUI, LSTATS_SUBCMD_GET_INFO);
86         if (ret < 0) {
87             ALOGE("Failed to create %x - %d", LSTATS_SUBCMD_GET_INFO, ret);
88             return ret;
89         }
90 
91         return ret;
92     }
93 
94 protected:
handleResponse(WifiEvent & reply)95     virtual int handleResponse(WifiEvent& reply) {
96         bool ml_data = false;
97         wifi_iface_ml_stat *iface_ml_stat_ptr = NULL;
98         u8 *radioStatsBuf = NULL, *ifaceMlStatsBuf = NULL, *outbuf = NULL, *data_ptr = NULL;
99         u8 *data = NULL, *iface_stat = NULL;
100         uint32_t offset = 0, num_radios = 0, per_radio_size = 0, data_len = 0;
101         uint32_t outbuf_rem_len = 0, data_rem_len = 0;
102         int ret = 0, id = 0, subcmd = 0, len = 0;
103         u32 fixed_iface_ml_stat_size = 0, all_links_stat_size = 0;
104         u8 num_links = 0;
105 
106         // ALOGI("In GetLinkStatsCommand::handleResponse");
107 
108         if (reply.get_cmd() != NL80211_CMD_VENDOR) {
109             ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
110             return NL_SKIP;
111         }
112 
113         id = reply.get_vendor_id();
114         subcmd = reply.get_vendor_subcmd();
115         nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
116         len = reply.get_vendor_data_len();
117 
118         ALOGV("Id = %0x, subcmd = %d, len = %d\n", id, subcmd, len);
119         if (vendor_data == NULL || len == 0) {
120             ALOGE("no vendor data in GetLinkStatCommand response; ignoring it");
121             return NL_SKIP;
122         }
123 
124         for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
125             if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_RADIO) {
126                 num_radios = it.get_u32();
127             } else if (it.get_type() == ANDR_WIFI_ATTRIBUTE_STATS_INFO) {
128                 data = (u8 *)it.get_data();
129                 data_len = it.get_len();
130             } else if (it.get_type() == ANDR_WIFI_ATTRIBUTE_ML_STATS_INFO) {
131                 data = (u8 *)it.get_data();
132                 data_len = it.get_len();
133                 ml_data = true;
134             } else {
135                 ALOGW("Ignoring invalid attribute type = %d, size = %d",
136                 it.get_type(), it.get_len());
137                 return NL_SKIP;
138             }
139         }
140 
141         if (num_radios > MAX_NUM_RADIOS) {
142             ALOGE("Invalid num radios :%d\n", num_radios);
143             ret = WIFI_ERROR_INVALID_ARGS;
144             goto exit;
145         }
146 
147         outbuf_rem_len = MAX_CMD_RESP_BUF_LEN;
148         radioStatsBuf = (u8 *)malloc(MAX_CMD_RESP_BUF_LEN);
149         if (!radioStatsBuf) {
150             ALOGE("No memory\n");
151             return NL_SKIP;
152         }
153         memset(radioStatsBuf, 0, MAX_CMD_RESP_BUF_LEN);
154         outbuf = radioStatsBuf;
155 
156         if (!data || !data_len) {
157             ALOGE("%s: null data\n", __func__);
158             ret = WIFI_ERROR_INVALID_ARGS;
159             goto exit;
160         }
161 
162         data_ptr = data;
163         for (int i = 0; i < num_radios; i++) {
164             outbuf_rem_len -= per_radio_size;
165             if (outbuf_rem_len < per_radio_size) {
166                 ALOGE("No data left for radio %d\n", i);
167                 ret = WIFI_ERROR_INVALID_ARGS;
168                 goto exit;
169             }
170 
171             data_ptr = data + offset;
172             if (!data_ptr) {
173                 ALOGE("Invalid data for radio index = %d\n", i);
174                 ret = WIFI_ERROR_INVALID_ARGS;
175                 goto exit;
176             }
177             ret = convertToExternalRadioStatStructure((wifi_radio_stat*)data_ptr,
178                 &per_radio_size, &outbuf, &outbuf_rem_len);
179             if (ret < 0) {
180                 ALOGE(("Failed to map data radioStat struct\n"));
181                 goto exit;
182             }
183             if (!per_radio_size) {
184                 ALOGE("No data for radio %d\n", i);
185                 continue;
186             }
187             outbuf += per_radio_size;
188             /* Accounted size of all the radio data len */
189             offset += per_radio_size;
190         }
191 
192         if (ml_data) {
193             outbuf = NULL;
194             data_rem_len = data_len - offset;
195             fixed_iface_ml_stat_size = offsetof(wifi_iface_ml_stat, links);
196 
197             /* Allocate vendor hal buffer, instead of using the nlmsg allocated buffer */
198             ifaceMlStatsBuf = (u8 *)malloc(MAX_CMD_RESP_BUF_LEN);
199             if (!ifaceMlStatsBuf) {
200                 ALOGE("No memory\n");
201                 ret = WIFI_ERROR_OUT_OF_MEMORY;
202                 goto exit;
203             }
204             outbuf_rem_len = MAX_CMD_RESP_BUF_LEN;
205             memset(ifaceMlStatsBuf, 0, MAX_CMD_RESP_BUF_LEN);
206             outbuf = ifaceMlStatsBuf;
207 
208             if (data_rem_len >= fixed_iface_ml_stat_size) {
209                 data_ptr = (data + offset);
210                 if (!data_ptr) {
211                     ALOGE("No iface ml stats fixed data!!, data_len = %d, offset = %d\n",
212                         data_len, offset);
213                     ret = WIFI_ERROR_INVALID_ARGS;
214                     goto exit;
215                 }
216 
217                 if (outbuf_rem_len < fixed_iface_ml_stat_size) {
218                     ALOGE("No space to copy fixed iface ml stats!, rem_len %d, req_len %d\n",
219                         outbuf_rem_len, fixed_iface_ml_stat_size);
220                     ret = WIFI_ERROR_OUT_OF_MEMORY;
221                     goto exit;
222                 }
223 
224                 memcpy(outbuf, data_ptr, fixed_iface_ml_stat_size);
225                 data_rem_len -= fixed_iface_ml_stat_size;
226                 outbuf_rem_len -= fixed_iface_ml_stat_size;
227                 outbuf += fixed_iface_ml_stat_size;
228                 offset += fixed_iface_ml_stat_size;
229 
230                 iface_ml_stat_ptr = (wifi_iface_ml_stat *)ifaceMlStatsBuf;
231                 if (!iface_ml_stat_ptr) {
232                     ALOGE("No iface ml stats data!!");
233                     ret = WIFI_ERROR_INVALID_ARGS;
234                     goto exit;
235                 }
236 
237                 num_links = iface_ml_stat_ptr->num_links;
238                 all_links_stat_size = (num_links * offsetof(wifi_link_stat, peer_info));
239                 if (num_links > MAX_MLO_LINK) {
240                     ALOGE("Invalid num links :%d\n", num_links);
241                     ret = WIFI_ERROR_INVALID_ARGS;
242                     goto exit;
243                 }
244 
245                 if (num_links && (data_rem_len >= all_links_stat_size)) {
246                     ret = convertToExternalIfaceMlstatStructure(&data, &offset, &outbuf,
247                             &data_rem_len, num_links, &outbuf_rem_len);
248                     if (ret < 0) {
249                         ALOGE(("Failed to map data to iface ml struct\n"));
250                         goto exit;
251                     }
252                 } else {
253                     ALOGE("num_links %d, Required data not found: expected len %d,"
254                             " data_rem_len %d\n", num_links, all_links_stat_size, data_rem_len);
255                     ret = WIFI_ERROR_INVALID_ARGS;
256                     goto exit;
257                 }
258                 (*mHandler.on_multi_link_stats_results)(id,
259                     (wifi_iface_ml_stat *)ifaceMlStatsBuf, num_radios,
260                     (wifi_radio_stat *)radioStatsBuf);
261             }
262         } else if ((data_len >= (offset + sizeof(wifi_iface_stat)))) {
263             iface_stat = (data + offset);
264             if (!iface_stat) {
265                 ALOGE("No data for legacy iface stats!!, data_len = %d, offset = %d\n",
266                         data_len, offset);
267                 ret = WIFI_ERROR_INVALID_ARGS;
268                 goto exit;
269             }
270             (*mHandler.on_link_stats_results)(id, (wifi_iface_stat *)iface_stat,
271                 num_radios, (wifi_radio_stat *)radioStatsBuf);
272         } else {
273             ALOGE("No data for iface stats!!, data_len = %d, offset = %d\n",
274                     data_len, offset);
275             ret = WIFI_ERROR_INVALID_ARGS;
276             goto exit;
277         }
278 
279 exit:
280         /* report valid radiostat eventhough there is no linkstat info
281          * (non assoc/error case)
282          */
283         if ((ret != WIFI_SUCCESS) && num_radios && per_radio_size) {
284             (*mHandler.on_link_stats_results)(id, NULL,
285                     num_radios, (wifi_radio_stat *)radioStatsBuf);
286         }
287 
288         if (radioStatsBuf) {
289             free(radioStatsBuf);
290             radioStatsBuf = NULL;
291         }
292         if (ifaceMlStatsBuf) {
293             free(ifaceMlStatsBuf);
294             ifaceMlStatsBuf = NULL;
295         }
296         return NL_OK;
297     }
298 
299 private:
convertToExternalRadioStatStructure(wifi_radio_stat * internal_stat_ptr,uint32_t * per_radio_size,u8 ** outbuf,uint32_t * outbuf_rem_len)300     int convertToExternalRadioStatStructure(wifi_radio_stat *internal_stat_ptr,
301         uint32_t *per_radio_size, u8 **outbuf, uint32_t *outbuf_rem_len)
302     {
303         int ret = 0;
304         if (!internal_stat_ptr) {
305             ALOGE("Incoming data is null\n");
306             ret = WIFI_ERROR_INVALID_ARGS;
307         } else {
308             uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
309             *per_radio_size = offsetof(wifi_radio_stat, channels) + channel_size;
310             if (*outbuf_rem_len >= *per_radio_size) {
311                 memcpy(*outbuf, internal_stat_ptr, *per_radio_size);
312             } else {
313                 ALOGE("Insufficient buf size to copy. rem len %d, req size %d\n",
314                     *outbuf_rem_len, *per_radio_size);
315                 ret = WIFI_ERROR_OUT_OF_MEMORY;
316             }
317         }
318         return ret;
319     }
320 
convertToExternalRatestatsStructure(u8 ** data,u32 * offset,u8 ** outbuf,u32 * data_rem_len,wifi_peer_info * peer_info,u8 num_rate,u32 * outbuf_rem_len)321     int convertToExternalRatestatsStructure(u8 **data, u32 *offset, u8 **outbuf,
322         u32 *data_rem_len, wifi_peer_info *peer_info, u8 num_rate, u32 *outbuf_rem_len)
323     {
324         u8 k = 0, num_peers = 0;
325         int ret = 0;
326         u8 *data_ptr = NULL;
327         u32 all_rates_size = 0, per_rate_size = 0;
328 
329         per_rate_size = sizeof(wifi_rate_stat);
330         all_rates_size = num_rate * per_rate_size;
331         if (!peer_info && (*data_rem_len != all_rates_size)) {
332             ALOGE("Insufficient data for rate_stats, data_rem_len %d,"
333                 "required data size %d \n", *data_rem_len, all_rates_size);
334             ret = WIFI_ERROR_INVALID_ARGS;
335             goto exit;
336         }
337 
338         for (k = 0; k < num_rate; k++) {
339             data_ptr = ((*data) + (*offset));
340             if (!data_ptr) {
341                 ALOGE("rate_stats not found!! num_rate %d, *data_rem_len = %d, *offset = %d\n",
342                     num_rate, *data_rem_len, *offset);
343                 ret = WIFI_ERROR_OUT_OF_MEMORY;
344                 goto exit;
345             }
346 
347             if (*data_rem_len < per_rate_size) {
348                 ALOGE("no rate_stats!!, data_rem_len %d, rate_stat size %d\n",
349                     *data_rem_len, per_rate_size);
350                 ret = WIFI_ERROR_INVALID_ARGS;
351                 goto exit;
352             }
353 
354             if (*outbuf_rem_len < per_rate_size) {
355                 ALOGE("No space to copy rate_stats of index [%d]!, rem_len %d, req_len %d\n",
356                     k, *outbuf_rem_len, per_rate_size);
357                 ret = WIFI_ERROR_OUT_OF_MEMORY;
358                 goto exit;
359             }
360 
361             memcpy(*outbuf, data_ptr, per_rate_size);
362             *data_rem_len -= per_rate_size;
363             *outbuf_rem_len -= per_rate_size;
364             *outbuf += per_rate_size;
365             *offset += per_rate_size;
366         }
367     exit:
368         return ret;
369     }
370 
convertToExternalIfaceLinkstatStructure(u8 ** data,uint32_t * offset,u8 ** outbuf,u32 * data_rem_len,u8 num_peers,wifi_link_stat * links,u32 * outbuf_rem_len)371     int convertToExternalIfaceLinkstatStructure(u8 **data, uint32_t *offset, u8 **outbuf,
372             u32 *data_rem_len, u8 num_peers, wifi_link_stat *links, u32 *outbuf_rem_len)
373     {
374         int ret = 0, j = 0, num_rate = 0;
375         u32 all_rate_stats_per_peer_per_link_size = 0, fixed_peer_info_size = 0;
376         u8 *data_ptr = NULL;
377         wifi_peer_info *peer_info_ptr = NULL;
378 
379         for (j = 0; j < num_peers; j++) {
380             data_ptr = ((*data) + (*offset));
381             if (!data_ptr || (!*data_rem_len)) {
382                 ALOGE("no peer_info data!! num_peers %d, data_rem_len = %d, *offset = %d\n",
383                     num_peers, *data_rem_len, *offset);
384                 ret = WIFI_ERROR_OUT_OF_MEMORY;
385                 goto exit;
386             }
387 
388             fixed_peer_info_size = offsetof(wifi_peer_info, rate_stats);
389             if (*data_rem_len < fixed_peer_info_size) {
390                 ALOGE("no fixed peer_info data!!, data_rem_len %d, fixed peer info %d\n",
391                     *data_rem_len, fixed_peer_info_size);
392                 ret = WIFI_ERROR_INVALID_ARGS;
393                 goto exit;
394             }
395 
396             if (*outbuf_rem_len < fixed_peer_info_size) {
397                 ALOGE("No space to copy fixed peer_info of index[%d]!, rem_len %d, req_len %d\n",
398                     j, *outbuf_rem_len, fixed_peer_info_size);
399                 ret = WIFI_ERROR_OUT_OF_MEMORY;
400                 goto exit;
401             }
402 
403             memcpy(*outbuf, data_ptr, fixed_peer_info_size);
404             *data_rem_len -= fixed_peer_info_size;
405             *outbuf_rem_len -= fixed_peer_info_size;
406             *outbuf += fixed_peer_info_size;
407             *offset += fixed_peer_info_size;
408 
409             peer_info_ptr = (wifi_peer_info *)data_ptr;
410             if (!peer_info_ptr) {
411                 ALOGE("no peer_info data!!");
412                 ret = WIFI_ERROR_INVALID_ARGS;
413                 goto exit;
414             }
415 
416             num_rate = peer_info_ptr->num_rate;
417             if ((num_rate == NUM_RATE) || (num_rate == NUM_RATE_NON_BE)) {
418                 all_rate_stats_per_peer_per_link_size = num_rate * sizeof(wifi_rate_stat);
419                 if (num_rate && (*data_rem_len >= all_rate_stats_per_peer_per_link_size)) {
420                     ret = convertToExternalRatestatsStructure(data, offset, outbuf, data_rem_len,
421                         peer_info_ptr, num_rate, outbuf_rem_len);
422                     if (ret != WIFI_SUCCESS) {
423                         ALOGE(("Failed to convert it to rate stats\n"));
424                         goto exit;
425                     }
426                 } else {
427                     ALOGI("num_rate %d, Required rate_stats not found: expected len %d,"
428                         " data_rem_len %d\n", num_rate, all_rate_stats_per_peer_per_link_size,
429                         *data_rem_len);
430                     continue;
431                 }
432             } else if (num_rate == 0) {
433                 ALOGI("Sta is not associated, num rate :%d\n", num_rate);
434             } else {
435                 ALOGE("Invalid num rate :%d\n", num_rate);
436                 ret = WIFI_ERROR_INVALID_ARGS;
437                 goto exit;
438             }
439         }
440 
441     exit:
442         return ret;
443     }
444 
convertToExternalIfaceMlstatStructure(u8 ** data,u32 * offset,u8 ** outbuf,u32 * data_rem_len,u8 num_links,u32 * outbuf_rem_len)445     int convertToExternalIfaceMlstatStructure(u8 **data, u32 *offset, u8 **outbuf,
446         u32 *data_rem_len, u8 num_links, u32 *outbuf_rem_len)
447     {
448         int ret = 0, i = 0;
449         u32 all_peers_per_link_size = 0, fixed_link_stat_size = 0;
450         u8 *data_ptr = NULL;
451         u8 num_peers = 0;
452         wifi_link_stat *links_ptr = NULL;
453 
454         for (i = 0; i < num_links; i++) {
455             data_ptr = ((*data) + (*offset));
456             if (!data_ptr || !(*data_rem_len)) {
457                 ALOGE("no variable links data!! num_links %d, data_rem_len = %d, offset = %d\n",
458                     num_links, *data_rem_len, *offset);
459                 ret = WIFI_ERROR_OUT_OF_MEMORY;
460                 goto exit;
461             }
462 
463             fixed_link_stat_size = offsetof(wifi_link_stat, peer_info);
464             if (*data_rem_len < fixed_link_stat_size) {
465                 ALOGE("no fixed wifi_link_stat data!!, data_rem_len %d, fixed link stat data %d\n",
466                     *data_rem_len, fixed_link_stat_size);
467                 ret = WIFI_ERROR_INVALID_ARGS;
468                 goto exit;
469             }
470 
471             if (*outbuf_rem_len < fixed_link_stat_size) {
472                 ALOGE("No space to copy fixed link stats of index[%d]!, rem_len %d, req_len %d\n",
473                     i, *outbuf_rem_len, fixed_link_stat_size);
474                 ret = WIFI_ERROR_OUT_OF_MEMORY;
475                 goto exit;
476             }
477 
478             memcpy(*outbuf, data_ptr, fixed_link_stat_size);
479             *outbuf_rem_len -= fixed_link_stat_size;
480             *data_rem_len -= fixed_link_stat_size;
481             *outbuf += fixed_link_stat_size;
482             *offset += fixed_link_stat_size;
483 
484             links_ptr = (wifi_link_stat *)data_ptr;
485             if (!links_ptr) {
486                 ALOGE("no link_stat data!!");
487                 ret = WIFI_ERROR_INVALID_ARGS;
488                 goto exit;
489             }
490 
491             if (!links_ptr->num_peers) {
492                 ALOGI("no peers in unassoc case, skip processing peer stats\n");
493                 ret = WIFI_SUCCESS;
494                 continue;
495             }
496 
497             if (links_ptr->num_peers != NUM_PEER_AP) {
498                 ALOGE("Invalid num peer :%d\n", links_ptr->num_peers);
499                 ret = WIFI_ERROR_INVALID_ARGS;
500                 goto exit;
501             }
502 
503             num_peers = links_ptr->num_peers;
504             all_peers_per_link_size = num_peers * offsetof(wifi_peer_info, rate_stats);
505             if ((num_peers == NUM_PEER_AP) && (*data_rem_len >= all_peers_per_link_size)) {
506                 ret = convertToExternalIfaceLinkstatStructure(data, offset, outbuf,
507                     data_rem_len, num_peers, links_ptr, outbuf_rem_len);
508                 if (ret != WIFI_SUCCESS) {
509                     ALOGE(("Failed to convert it to iface link stats\n"));
510                     goto exit;
511                 }
512             } else {
513                 ALOGI("num_peers %d, Required data not found: expected len %d, data_rem_len %d\n",
514                     num_peers, all_peers_per_link_size, *data_rem_len);
515                 continue;
516             }
517         }
518     exit:
519         return ret;
520     }
521 };
522 
wifi_get_link_stats(wifi_request_id id,wifi_interface_handle iface,wifi_stats_result_handler handler)523 wifi_error wifi_get_link_stats(wifi_request_id id,
524         wifi_interface_handle iface, wifi_stats_result_handler handler)
525 {
526     GetLinkStatsCommand command(iface, handler);
527     return (wifi_error) command.requestResponse();
528 }
529 
wifi_set_link_stats(wifi_interface_handle,wifi_link_layer_params)530 wifi_error wifi_set_link_stats(
531         wifi_interface_handle /* iface */, wifi_link_layer_params /* params */)
532 {
533     /* Return success here since bcom HAL does not need set link stats. */
534     return WIFI_SUCCESS;
535 }
536 
wifi_clear_link_stats(wifi_interface_handle,u32,u32 *,u8,u8 *)537 wifi_error wifi_clear_link_stats(
538         wifi_interface_handle /* iface */, u32 /* stats_clear_req_mask */,
539         u32 * /* stats_clear_rsp_mask */, u8 /* stop_req */, u8 * /* stop_rsp */)
540 {
541     /* Return success here since bcom HAL does not support clear link stats. */
542     return WIFI_SUCCESS;
543 }
544