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