1 /*
2 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 * Changes from Qualcomm Innovation Center are provided under the following license:
30
31 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
32 * SPDX-License-Identifier: BSD-3-Clause-Clear
33 */
34
35 #include "sync.h"
36
37 #define LOG_TAG "WifiHAL"
38
39 #include <utils/Log.h>
40
41 #include <hardware_legacy/wifi_hal.h>
42 #include "common.h"
43 #include "cpp_bindings.h"
44 #include "wifihal_vendorcommand.h"
45
46 #define MAX_INFO 1
47 //Singleton Static Instance
48 NUDStatsCommand* NUDStatsCommand::mNUDStatsCommandInstance = NULL;
49
50 // This function implements creation of Vendor command
51 // For NUDStats just call base Vendor command create
create()52 wifi_error NUDStatsCommand::create() {
53 wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
54 if (ret != WIFI_SUCCESS) {
55 return ret;
56 }
57 // insert the oui in the msg
58 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
59 if (ret != WIFI_SUCCESS)
60 goto out;
61
62 // insert the subcmd in the msg
63 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
64 if (ret != WIFI_SUCCESS)
65 goto out;
66
67 out:
68 return ret;
69 }
70
NUDStatsCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)71 NUDStatsCommand::NUDStatsCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
72 : WifiVendorCommand(handle, id, vendor_id, subcmd)
73 {
74 memset(&mStats, 0,sizeof(nud_stats));
75 mpktInfo = NULL;
76 mnumStats = 0;
77 }
78
~NUDStatsCommand()79 NUDStatsCommand::~NUDStatsCommand()
80 {
81 mNUDStatsCommandInstance = NULL;
82 }
83
instance(wifi_handle handle)84 NUDStatsCommand* NUDStatsCommand::instance(wifi_handle handle)
85 {
86 if (handle == NULL) {
87 ALOGE("Interface Handle is invalid");
88 return NULL;
89 }
90 if (mNUDStatsCommandInstance == NULL) {
91 mNUDStatsCommandInstance = new NUDStatsCommand(handle, 0,
92 OUI_QCA,
93 QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET);
94 return mNUDStatsCommandInstance;
95 }
96 else
97 {
98 if (handle != getWifiHandle(mNUDStatsCommandInstance->mInfo))
99 {
100 /* upper layer must have cleaned up the handle and reinitialized,
101 so we need to update the same */
102 ALOGE("Handle different, update the handle");
103 mNUDStatsCommandInstance->mInfo = (hal_info *)handle;
104 }
105 }
106 return mNUDStatsCommandInstance;
107 }
108
setSubCmd(u32 subcmd)109 void NUDStatsCommand::setSubCmd(u32 subcmd)
110 {
111 mSubcmd = subcmd;
112 }
113
setHandler(pkt_stats_result_handler handler)114 void NUDStatsCommand::setHandler(pkt_stats_result_handler handler)
115 {
116 mHandler = handler;
117 }
118
requestResponse()119 wifi_error NUDStatsCommand::requestResponse()
120 {
121 return WifiCommand::requestResponse(mMsg);
122 }
123
notifyResponse()124 wifi_error NUDStatsCommand::notifyResponse()
125 {
126 wifi_error ret = WIFI_SUCCESS;
127
128 if (mHandler.on_pkt_stats_results) {
129 mHandler.on_pkt_stats_results(&mStats, mnumStats,
130 mpktInfo);
131 } else {
132 ret = WIFI_ERROR_INVALID_ARGS;
133 }
134 return ret;
135 }
136
handleResponse(WifiEvent & reply)137 int NUDStatsCommand::handleResponse(WifiEvent &reply)
138 {
139 wifi_error status = WIFI_ERROR_NONE;
140 WifiVendorCommand::handleResponse(reply);
141
142 // Parse the vendordata and get the attribute
143
144 switch(mSubcmd)
145 {
146 case QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET:
147 {
148 struct nlattr *tb_vendor[QCA_ATTR_NUD_STATS_GET_MAX + 1];
149 nud_stats *stats = &mStats;
150
151 memset(stats, 0, sizeof(nud_stats));
152 nla_parse(tb_vendor, QCA_ATTR_NUD_STATS_GET_MAX,
153 (struct nlattr *)mVendorData, mDataLen, NULL);
154
155 if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV])
156 {
157 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV"
158 " not found", __FUNCTION__);
159 status = WIFI_ERROR_INVALID_ARGS;
160 goto cleanup;
161 }
162 stats->arp_req_count_from_netdev = nla_get_u16(tb_vendor[
163 QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV]);
164
165 if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC])
166 {
167 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC"
168 " not found", __FUNCTION__);
169 status = WIFI_ERROR_INVALID_ARGS;
170 goto cleanup;
171 }
172 stats->arp_req_count_to_lower_mac = nla_get_u16(tb_vendor[
173 QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC]);
174
175 if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC])
176 {
177 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC"
178 " not found", __FUNCTION__);
179 status = WIFI_ERROR_INVALID_ARGS;
180 goto cleanup;
181 }
182 stats->arp_req_rx_count_by_lower_mac = nla_get_u16(tb_vendor[
183 QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC]);
184
185 if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS])
186 {
187 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS"
188 " not found", __FUNCTION__);
189 status = WIFI_ERROR_INVALID_ARGS;
190 goto cleanup;
191 }
192 stats->arp_req_count_tx_success = nla_get_u16(tb_vendor[
193 QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS]);
194
195 if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC])
196 {
197 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC"
198 " not found", __FUNCTION__);
199 status = WIFI_ERROR_INVALID_ARGS;
200 goto cleanup;
201 }
202 stats->arp_rsp_rx_count_by_lower_mac = nla_get_u16(tb_vendor[
203 QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC]);
204
205 if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC])
206 {
207 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC"
208 " not found", __FUNCTION__);
209 status = WIFI_ERROR_INVALID_ARGS;
210 goto cleanup;
211 }
212 stats->arp_rsp_rx_count_by_upper_mac = nla_get_u16(tb_vendor[
213 QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC]);
214
215 if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV])
216 {
217 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV"
218 " not found", __FUNCTION__);
219 status = WIFI_ERROR_INVALID_ARGS;
220 goto cleanup;
221 }
222 stats->arp_rsp_count_to_netdev = nla_get_u16(tb_vendor[
223 QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV]);
224
225 if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP])
226 {
227 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP"
228 " not found", __FUNCTION__);
229 status = WIFI_ERROR_INVALID_ARGS;
230 goto cleanup;
231 }
232 stats->arp_rsp_count_out_of_order_drop = nla_get_u16(tb_vendor[
233 QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP]);
234
235 if (tb_vendor[QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE])
236 stats->ap_link_active = 1;
237
238 if (tb_vendor[QCA_ATTR_NUD_STATS_IS_DAD])
239 stats->is_duplicate_addr_detection = 1;
240
241 ALOGV(" req_from_netdev %d count_to_lower :%d"
242 " count_by_lower :%d"
243 " count_tx_succ :%d rsp_count_lower :%d"
244 " rsp_count_upper :%d rsp_count_netdev :%d"
245 " out_of_order_drop :%d active_aplink %d"
246 " DAD %d ",
247 stats->arp_req_count_from_netdev,
248 stats->arp_req_count_to_lower_mac,
249 stats->arp_req_rx_count_by_lower_mac,
250 stats->arp_req_count_tx_success,
251 stats->arp_rsp_rx_count_by_lower_mac,
252 stats->arp_rsp_rx_count_by_upper_mac,
253 stats->arp_rsp_count_to_netdev,
254 stats->arp_rsp_count_out_of_order_drop,
255 stats->ap_link_active,
256 stats->is_duplicate_addr_detection);
257
258 if (tb_vendor[QCA_ATTR_NUD_STATS_DATA_PKT_STATS]) {
259 mNUDStatsCommandInstance->GetPktInfo(tb_vendor);
260 }
261 }
262 }
263 cleanup:
264 if (status == WIFI_ERROR_INVALID_ARGS)
265 memset(&mStats,0,sizeof(nud_stats));
266 if(mpktInfo != NULL)
267 free(mpktInfo);
268
269 return status;
270 }
271
GetPktInfo(struct nlattr ** tbvendor)272 void NUDStatsCommand::GetPktInfo(struct nlattr **tbvendor)
273 {
274 struct nlattr *tb;
275 int rem;
276 cmdData *pkt_stats;
277 char ipv6_address[INET6_ADDRSTRLEN];
278 cmdData pktstats;
279 int nbuff = 0;
280
281 for (tb = (struct nlattr *) nla_data(tbvendor[QCA_ATTR_NUD_STATS_DATA_PKT_STATS]),
282 rem = nla_len(tbvendor[QCA_ATTR_NUD_STATS_DATA_PKT_STATS]);
283 nla_ok(tb, rem); tb = nla_next(tb, &(rem)))
284 {
285 struct nlattr *tb2[QCA_ATTR_NUD_DATA_STATS_MAX + 1];
286 nla_parse(tb2, QCA_ATTR_NUD_DATA_STATS_MAX,
287 (struct nlattr *) nla_data(tb), nla_len(tb), NULL);
288
289 memset(&pktstats, 0, sizeof(cmdData));
290
291 if (tb2[QCA_ATTR_NUD_STATS_PKT_TYPE])
292 {
293 pktstats.pkt_Type = nla_get_u32(tb2[QCA_ATTR_NUD_STATS_PKT_TYPE]);
294 }
295
296 if (tb2[QCA_ATTR_NUD_STATS_PKT_DNS_DOMAIN_NAME])
297 {
298 pktstats.domain_name = nla_get_string(tb2[QCA_ATTR_NUD_STATS_PKT_DNS_DOMAIN_NAME]);
299 }
300
301 if (tb2[QCA_ATTR_NUD_STATS_PKT_SRC_PORT])
302 {
303 pktstats.src_port = nla_get_u32(tb2[QCA_ATTR_NUD_STATS_PKT_SRC_PORT]);
304 }
305
306 if (tb2[QCA_ATTR_NUD_STATS_PKT_DEST_PORT])
307 {
308 pktstats.dst_port = nla_get_u32(tb2[QCA_ATTR_NUD_STATS_PKT_DEST_PORT]);
309 }
310
311 if (tb2[QCA_ATTR_NUD_STATS_PKT_DEST_IPV4])
312 {
313 pktstats.ipv4_addr.s_addr = nla_get_u32(tb2[QCA_ATTR_NUD_STATS_PKT_DEST_IPV4]);
314 }
315
316 if (tb2[QCA_ATTR_NUD_STATS_PKT_DEST_IPV6])
317 {
318 memcpy(pktstats.ipv6_addr, nla_data(tb2[QCA_ATTR_NUD_STATS_PKT_DEST_IPV6]),
319 sizeof(pktstats.ipv6_addr));
320 }
321
322 if (tb2[QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_FROM_NETDEV])
323 {
324 pktstats.stats.pkt_req_count_from_netdev = nla_get_u16(tb2[
325 QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_FROM_NETDEV]);
326 }
327
328 if (tb2[QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TO_LOWER_MAC])
329 {
330 pktstats.stats.pkt_req_count_to_lower_mac = nla_get_u16(tb2[
331 QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TO_LOWER_MAC]);
332 }
333
334 if (tb2[QCA_ATTR_NUD_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC])
335 {
336 pktstats.stats.pkt_req_rx_count_by_lower_mac = nla_get_u16(tb2[
337 QCA_ATTR_NUD_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC]);
338 }
339
340 if (tb2[QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TX_SUCCESS])
341 {
342 pktstats.stats.pkt_req_count_tx_success = nla_get_u16(tb2[
343 QCA_ATTR_NUD_STATS_PKT_REQ_COUNT_TX_SUCCESS]);
344 }
345
346 if (tb2[QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC])
347 {
348 pktstats.stats.pkt_rsp_rx_count_by_lower_mac = nla_get_u16(tb2[
349 QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC]);
350 }
351
352 if (tb2[QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC])
353 {
354 pktstats.stats.pkt_rsp_rx_count_by_upper_mac = nla_get_u16(tb2[
355 QCA_ATTR_NUD_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC]);
356 }
357
358 if (tb2[QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_TO_NETDEV])
359 {
360 pktstats.stats.pkt_rsp_count_to_netdev = nla_get_u16(tb2[
361 QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_TO_NETDEV]);
362 }
363
364 if (tb2[QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP])
365 {
366 pktstats.stats.pkt_rsp_count_out_of_order_drop = nla_get_u16(tb2[
367 QCA_ATTR_NUD_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP]);
368 }
369
370 if (inet_ntop(AF_INET6, pktstats.ipv6_addr, ipv6_address,
371 INET6_ADDRSTRLEN) == NULL) {
372 ALOGE("%s: failed to convert ipv6 address format", __FUNCTION__);
373 }
374
375 ALOGV(" pkt_type %d domain_name :%s"
376 " src_port %d dst_port :%d"
377 " ipv4_address :%x ipv6_address %s"
378 " req_from_netdev %d count_to_lower :%d"
379 " count_by_lower :%d"
380 " count_tx_succ :%d rsp_count_lower :%d"
381 " rsp_count_upper :%d rsp_count_netdev :%d"
382 " out_of_order_drop :%d ",
383 pktstats.pkt_Type, pktstats.domain_name,
384 pktstats.src_port, pktstats.dst_port,
385 pktstats.ipv4_addr.s_addr, ipv6_address,
386 pktstats.stats.pkt_req_count_from_netdev,
387 pktstats.stats.pkt_req_count_to_lower_mac,
388 pktstats.stats.pkt_req_rx_count_by_lower_mac,
389 pktstats.stats.pkt_req_count_tx_success,
390 pktstats.stats.pkt_rsp_rx_count_by_lower_mac,
391 pktstats.stats.pkt_rsp_rx_count_by_upper_mac,
392 pktstats.stats.pkt_rsp_count_to_netdev,
393 pktstats.stats.pkt_rsp_count_out_of_order_drop);
394
395 if (nbuff == 0)
396 pkt_stats = (cmdData *)malloc(sizeof(cmdData));
397 else
398 pkt_stats = (cmdData *)realloc(pkt_stats,sizeof(cmdData) * (nbuff + 1));
399
400 mpktInfo = pkt_stats;
401 if (pkt_stats != NULL) {
402 memcpy(&pkt_stats[nbuff], &pktstats,sizeof(cmdData));
403 nbuff++;
404 mnumStats = nbuff;
405 }
406 }
407 }
408
copyStats(nud_stats * stats,cmdData * pktstats)409 void NUDStatsCommand::copyStats(nud_stats *stats, cmdData *pktstats)
410 {
411 memcpy(stats, &mStats, sizeof(nud_stats));
412 pktstats = mpktInfo;
413 }
414
wifi_set_nud_stats(wifi_interface_handle iface,u32 gw_addr,cmdData Data)415 wifi_error wifi_set_nud_stats(wifi_interface_handle iface,
416 u32 gw_addr, cmdData Data)
417 {
418 wifi_error ret;
419 NUDStatsCommand *NUDCommand;
420 struct nlattr *nl_data,*nl_pktInfo;
421 interface_info *iinfo = getIfaceInfo(iface);
422 wifi_handle handle = getWifiHandle(iface);
423 cmdData mData = Data;
424 cmdData pktstats = Data;
425
426 ALOGV("gw_addr : %x", gw_addr);
427 NUDCommand = NUDStatsCommand::instance(handle);
428 if (NUDCommand == NULL) {
429 ALOGE("%s: Error NUDStatsCommand NULL", __FUNCTION__);
430 return WIFI_ERROR_INVALID_ARGS;
431 }
432 NUDCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET);
433
434 /* create the message */
435 ret = NUDCommand->create();
436 if (ret != WIFI_SUCCESS)
437 goto cleanup;
438
439 ret = NUDCommand->set_iface_id(iinfo->name);
440 if (ret != WIFI_SUCCESS)
441 goto cleanup;
442
443 /*add the attributes*/
444 nl_data = NUDCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
445 if (!nl_data)
446 goto cleanup;
447 /**/
448 ret = NUDCommand->put_flag(QCA_ATTR_NUD_STATS_SET_START);
449
450 ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_GW_IPV4, gw_addr);
451 if (ret != WIFI_SUCCESS)
452 goto cleanup;
453
454 if (mData.pkt_Type) {
455 /*start the packet info attributes in nested*/
456 nl_pktInfo = NUDCommand->attr_start(QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO);
457 if (!nl_pktInfo)
458 goto cleanup;
459 else {
460 ALOGV(" pkt_type %d domain_name :%s"
461 " src_port %d dst_port :%d"
462 " ipv4_address :%x ipv6_address %s",
463 pktstats.pkt_Type, pktstats.domain_name,
464 pktstats.src_port, pktstats.dst_port,
465 pktstats.ipv4_addr.s_addr,pktstats.ipv6_addr);
466
467 for (int i=0; i < MAX_INFO ; i++) {
468 /*add the packet type attributes*/
469 struct nlattr *tb_tmp;
470 tb_tmp = NUDCommand->attr_start(i);
471
472 ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_TYPE,mData.pkt_Type);
473 if (ret != WIFI_SUCCESS)
474 goto cleanup;
475
476 if (mData.domain_name) {
477 /*add the domain name attributes*/
478 ret = NUDCommand->put_string(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DNS_DOMAIN_NAME,
479 mData.domain_name);
480 if (ret != WIFI_SUCCESS)
481 goto cleanup;
482 }
483 /*add the source port attributes*/
484 ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_SRC_PORT,
485 mData.src_port);
486 if (ret != WIFI_SUCCESS)
487 goto cleanup;
488
489 /*add the dest port attributes*/
490 ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_PORT,
491 mData.dst_port);
492 if (ret != WIFI_SUCCESS)
493 goto cleanup;
494
495 /*add the ipv4 address attributes*/
496 ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV4,
497 mData.ipv4_addr.s_addr);
498 if (ret != WIFI_SUCCESS)
499 goto cleanup;
500
501 /*add the ipv6 address attributes*/
502 ret = NUDCommand->put_ipv6_addr(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_DEST_IPV6,
503 mData.ipv6_addr);
504 if (ret != WIFI_SUCCESS)
505 goto cleanup;
506 NUDCommand->attr_end(tb_tmp);
507 }
508 }
509 NUDCommand->attr_end(nl_pktInfo);
510 }
511 NUDCommand->attr_end(nl_data);
512
513 ret = NUDCommand->requestResponse();
514 if (ret != WIFI_SUCCESS) {
515 ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
516 }
517
518 cleanup:
519 return ret;
520 }
521
522
wifi_get_nud_stats(wifi_interface_handle iface,pkt_stats_result_handler handler)523 wifi_error wifi_get_nud_stats(wifi_interface_handle iface,
524 pkt_stats_result_handler handler)
525 {
526 wifi_error ret;
527 NUDStatsCommand *NUDCommand;
528 struct nlattr *nl_data;
529 interface_info *iinfo = getIfaceInfo(iface);
530 wifi_handle handle = getWifiHandle(iface);
531
532 NUDCommand = NUDStatsCommand::instance(handle);
533 if (NUDCommand == NULL) {
534 ALOGE("%s: Error NUDStatsCommand NULL", __FUNCTION__);
535 return WIFI_ERROR_INVALID_ARGS;
536 }
537 NUDCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET);
538
539 NUDCommand->setHandler(handler);
540
541 /* create the message */
542 ret = NUDCommand->create();
543 if (ret != WIFI_SUCCESS)
544 goto cleanup;
545
546 ret = NUDCommand->set_iface_id(iinfo->name);
547 if (ret != WIFI_SUCCESS)
548 goto cleanup;
549 /*add the attributes*/
550 nl_data = NUDCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
551 if (!nl_data){
552 ret = WIFI_ERROR_UNKNOWN;
553 goto cleanup;
554 }
555 /**/
556 NUDCommand->attr_end(nl_data);
557
558 ret = NUDCommand->requestResponse();
559 if (ret != WIFI_SUCCESS) {
560 ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
561 goto cleanup;
562 }
563
564 ret = NUDCommand->notifyResponse();
565 if (ret != WIFI_SUCCESS) {
566 ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
567 goto cleanup;
568 }
569
570 cleanup:
571 return ret;
572 }
573
574
wifi_clear_nud_stats(wifi_interface_handle iface,cmdData Data)575 wifi_error wifi_clear_nud_stats(wifi_interface_handle iface,
576 cmdData Data)
577 {
578 wifi_error ret;
579 NUDStatsCommand *NUDCommand;
580 struct nlattr *nl_data,*nl_pktInfo;
581 interface_info *iinfo = getIfaceInfo(iface);
582 wifi_handle handle = getWifiHandle(iface);
583 cmdData mData = Data;
584
585 NUDCommand = NUDStatsCommand::instance(handle);
586 if (NUDCommand == NULL) {
587 ALOGE("%s: Error NUDStatsCommand NULL", __FUNCTION__);
588 return WIFI_ERROR_INVALID_ARGS;
589 }
590 NUDCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET);
591
592 /* create the message */
593 ret = NUDCommand->create();
594 if (ret != WIFI_SUCCESS)
595 goto cleanup;
596
597 ret = NUDCommand->set_iface_id(iinfo->name);
598 if (ret != WIFI_SUCCESS)
599 goto cleanup;
600
601 /*add the attributes*/
602 nl_data = NUDCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
603 if (!nl_data){
604 ret = WIFI_ERROR_UNKNOWN;
605 goto cleanup;
606 }
607 if (mData.pkt_Type) {
608 /*set the packet info attributes in nested*/
609 nl_pktInfo = NUDCommand->attr_start(QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO);
610 if (!nl_pktInfo){
611 ret = WIFI_ERROR_UNKNOWN;
612 goto cleanup;
613 }
614 else {
615 ALOGV(" %s: pkt_type %d domain_name :%s"
616 " src_port %d dst_port :%d"
617 " ipv4_address :%x ipv6_address %s",
618 __FUNCTION__,mData.pkt_Type, mData.domain_name,
619 mData.src_port, mData.dst_port,
620 mData.ipv4_addr.s_addr,mData.ipv6_addr);
621
622 for (int i=0; i < MAX_INFO ; i++) {
623 /*add the packet type attributes*/
624 struct nlattr *tb_tmp;
625 tb_tmp = NUDCommand->attr_start(i);
626
627 ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_DATA_PKT_INFO_TYPE,mData.pkt_Type);
628 if (ret != WIFI_SUCCESS)
629 goto cleanup;
630
631 NUDCommand->attr_end(tb_tmp);
632 }
633 }
634 NUDCommand->attr_end(nl_pktInfo);
635 }
636 NUDCommand->attr_end(nl_data);
637
638 ret = NUDCommand->requestResponse();
639 if (ret != WIFI_SUCCESS)
640 ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
641
642 cleanup:
643 return ret;
644 }
645