• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017, 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 
30 #include "sync.h"
31 
32 #define LOG_TAG  "WifiHAL"
33 
34 #include <utils/Log.h>
35 
36 #include "wifi_hal.h"
37 #include "common.h"
38 #include "cpp_bindings.h"
39 #include "wifihal_vendorcommand.h"
40 #include "vendor_definitions.h"
41 
42 //Singleton Static Instance
43 NUDStatsCommand* NUDStatsCommand::mNUDStatsCommandInstance  = NULL;
44 
45 // This function implements creation of Vendor command
46 // For NUDStats just call base Vendor command create
create()47 wifi_error NUDStatsCommand::create() {
48     wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
49     if (ret != WIFI_SUCCESS) {
50         return ret;
51     }
52     // insert the oui in the msg
53     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
54     if (ret != WIFI_SUCCESS)
55         goto out;
56 
57     // insert the subcmd in the msg
58     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
59     if (ret != WIFI_SUCCESS)
60         goto out;
61 
62 out:
63     return ret;
64 }
65 
NUDStatsCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)66 NUDStatsCommand::NUDStatsCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
67         : WifiVendorCommand(handle, id, vendor_id, subcmd)
68 {
69     memset(&mStats, 0,sizeof(nud_stats));
70 }
71 
~NUDStatsCommand()72 NUDStatsCommand::~NUDStatsCommand()
73 {
74     mNUDStatsCommandInstance = NULL;
75 }
76 
instance(wifi_handle handle)77 NUDStatsCommand* NUDStatsCommand::instance(wifi_handle handle)
78 {
79     if (handle == NULL) {
80         ALOGE("Interface Handle is invalid");
81         return NULL;
82     }
83     if (mNUDStatsCommandInstance == NULL) {
84         mNUDStatsCommandInstance = new NUDStatsCommand(handle, 0,
85                 OUI_QCA,
86                 QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET);
87         return mNUDStatsCommandInstance;
88     }
89     else
90     {
91         if (handle != getWifiHandle(mNUDStatsCommandInstance->mInfo))
92         {
93             /* upper layer must have cleaned up the handle and reinitialized,
94                so we need to update the same */
95             ALOGE("Handle different, update the handle");
96             mNUDStatsCommandInstance->mInfo = (hal_info *)handle;
97         }
98     }
99     return mNUDStatsCommandInstance;
100 }
101 
setSubCmd(u32 subcmd)102 void NUDStatsCommand::setSubCmd(u32 subcmd)
103 {
104     mSubcmd = subcmd;
105 }
106 
requestResponse()107 wifi_error NUDStatsCommand::requestResponse()
108 {
109     return WifiCommand::requestResponse(mMsg);
110 }
111 
handleResponse(WifiEvent & reply)112 int NUDStatsCommand::handleResponse(WifiEvent &reply)
113 {
114     int status = WIFI_ERROR_NONE;
115     WifiVendorCommand::handleResponse(reply);
116 
117     // Parse the vendordata and get the attribute
118 
119     switch(mSubcmd)
120     {
121         case QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET:
122         {
123             struct nlattr *tb_vendor[QCA_ATTR_NUD_STATS_GET_MAX + 1];
124             nud_stats *stats = &mStats;
125 
126             memset(stats, 0, sizeof(nud_stats));
127             nla_parse(tb_vendor, QCA_ATTR_NUD_STATS_GET_MAX,
128                       (struct nlattr *)mVendorData, mDataLen, NULL);
129 
130             if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV])
131             {
132                 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV"
133                       " not found", __FUNCTION__);
134                 status = WIFI_ERROR_INVALID_ARGS;
135                 goto cleanup;
136             }
137             stats->arp_req_count_from_netdev = nla_get_u16(tb_vendor[
138                             QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV]);
139 
140             if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC])
141             {
142                 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC"
143                       " not found", __FUNCTION__);
144                 status = WIFI_ERROR_INVALID_ARGS;
145                 goto cleanup;
146             }
147             stats->arp_req_count_to_lower_mac = nla_get_u16(tb_vendor[
148                             QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC]);
149 
150             if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC])
151             {
152                 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC"
153                       " not found", __FUNCTION__);
154                 status = WIFI_ERROR_INVALID_ARGS;
155                 goto cleanup;
156             }
157             stats->arp_req_rx_count_by_lower_mac = nla_get_u16(tb_vendor[
158                             QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC]);
159 
160             if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS])
161             {
162                 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS"
163                       " not found", __FUNCTION__);
164                 status = WIFI_ERROR_INVALID_ARGS;
165                 goto cleanup;
166             }
167             stats->arp_req_count_tx_success = nla_get_u16(tb_vendor[
168                             QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS]);
169 
170             if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC])
171             {
172                 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC"
173                       " not found", __FUNCTION__);
174                 status = WIFI_ERROR_INVALID_ARGS;
175                 goto cleanup;
176             }
177             stats->arp_rsp_rx_count_by_lower_mac = nla_get_u16(tb_vendor[
178                             QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC]);
179 
180             if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC])
181             {
182                 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC"
183                       " not found", __FUNCTION__);
184                 status = WIFI_ERROR_INVALID_ARGS;
185                 goto cleanup;
186             }
187             stats->arp_rsp_rx_count_by_upper_mac = nla_get_u16(tb_vendor[
188                             QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC]);
189 
190             if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV])
191             {
192                 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV"
193                       " not found", __FUNCTION__);
194                 status = WIFI_ERROR_INVALID_ARGS;
195                 goto cleanup;
196             }
197             stats->arp_rsp_count_to_netdev = nla_get_u16(tb_vendor[
198                             QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV]);
199 
200             if (!tb_vendor[QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP])
201             {
202                 ALOGE("%s: QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP"
203                       " not found", __FUNCTION__);
204                 status = WIFI_ERROR_INVALID_ARGS;
205                 goto cleanup;
206             }
207             stats->arp_rsp_count_out_of_order_drop = nla_get_u16(tb_vendor[
208                            QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP]);
209 
210             if (tb_vendor[QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE])
211                 stats->ap_link_active = 1;
212 
213             if (tb_vendor[QCA_ATTR_NUD_STATS_IS_DAD])
214                 stats->is_duplicate_addr_detection = 1;
215 
216             ALOGV(" req_from_netdev %d count_to_lower :%d"
217                   " count_by_lower :%d"
218                   " count_tx_succ :%d rsp_count_lower :%d"
219                   " rsp_count_upper :%d  rsp_count_netdev :%d"
220                   " out_of_order_drop :%d active_aplink %d"
221                   " DAD %d ",
222                   stats->arp_req_count_from_netdev,
223                   stats->arp_req_count_to_lower_mac,
224                   stats->arp_req_rx_count_by_lower_mac,
225                   stats->arp_req_count_tx_success,
226                   stats->arp_rsp_rx_count_by_lower_mac,
227                   stats->arp_rsp_rx_count_by_upper_mac,
228                   stats->arp_rsp_count_to_netdev,
229                   stats->arp_rsp_count_out_of_order_drop,
230                   stats->ap_link_active,
231                   stats->is_duplicate_addr_detection);
232         }
233     }
234 cleanup:
235     if (status == WIFI_ERROR_INVALID_ARGS)
236        memset(&mStats,0,sizeof(nud_stats));
237 
238     return status;
239 }
240 
copyStats(nud_stats * stats)241 void NUDStatsCommand::copyStats(nud_stats *stats)
242 {
243     memcpy(stats, &mStats, sizeof(nud_stats));
244 }
245 
wifi_set_nud_stats(wifi_interface_handle iface,u32 gw_addr)246 wifi_error wifi_set_nud_stats(wifi_interface_handle iface, u32 gw_addr)
247 {
248     wifi_error ret;
249     NUDStatsCommand *NUDCommand;
250     struct nlattr *nl_data;
251     interface_info *iinfo = getIfaceInfo(iface);
252     wifi_handle handle = getWifiHandle(iface);
253 
254     ALOGV("gw_addr : %x", gw_addr);
255     NUDCommand = NUDStatsCommand::instance(handle);
256     if (NUDCommand == NULL) {
257         ALOGE("%s: Error NUDStatsCommand NULL", __FUNCTION__);
258         return WIFI_ERROR_INVALID_ARGS;
259     }
260     NUDCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET);
261 
262     /* create the message */
263     ret = NUDCommand->create();
264     if (ret != WIFI_SUCCESS)
265         goto cleanup;
266 
267     ret = NUDCommand->set_iface_id(iinfo->name);
268     if (ret != WIFI_SUCCESS)
269         goto cleanup;
270 
271     /*add the attributes*/
272     nl_data = NUDCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
273     if (!nl_data)
274         goto cleanup;
275     /**/
276     ret = NUDCommand->put_flag(QCA_ATTR_NUD_STATS_SET_START);
277 
278     ret = NUDCommand->put_u32(QCA_ATTR_NUD_STATS_GW_IPV4, gw_addr);
279     if (ret != WIFI_SUCCESS)
280         goto cleanup;
281     /**/
282     NUDCommand->attr_end(nl_data);
283 
284     ret = NUDCommand->requestResponse();
285     if (ret != WIFI_SUCCESS) {
286         ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
287     }
288 
289 cleanup:
290     return ret;
291 }
292 
293 
wifi_get_nud_stats(wifi_interface_handle iface,nud_stats * stats)294 wifi_error wifi_get_nud_stats(wifi_interface_handle iface,
295                               nud_stats *stats)
296 {
297     wifi_error ret;
298     NUDStatsCommand *NUDCommand;
299     struct nlattr *nl_data;
300     interface_info *iinfo = getIfaceInfo(iface);
301     wifi_handle handle = getWifiHandle(iface);
302 
303     if (stats == NULL) {
304         ALOGE("%s: Error stats is NULL", __FUNCTION__);
305         return WIFI_ERROR_INVALID_ARGS;
306     }
307 
308     NUDCommand = NUDStatsCommand::instance(handle);
309     if (NUDCommand == NULL) {
310         ALOGE("%s: Error NUDStatsCommand NULL", __FUNCTION__);
311         return WIFI_ERROR_INVALID_ARGS;
312     }
313     NUDCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET);
314 
315     /* create the message */
316     ret = NUDCommand->create();
317     if (ret != WIFI_SUCCESS)
318         goto cleanup;
319 
320     ret = NUDCommand->set_iface_id(iinfo->name);
321     if (ret != WIFI_SUCCESS)
322         goto cleanup;
323     /*add the attributes*/
324     nl_data = NUDCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
325     if (!nl_data)
326         goto cleanup;
327     /**/
328     NUDCommand->attr_end(nl_data);
329 
330     ret = NUDCommand->requestResponse();
331     if (ret != WIFI_SUCCESS) {
332         ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
333         goto cleanup;
334     }
335 
336     NUDCommand->copyStats(stats);
337 
338 cleanup:
339     return ret;
340 }
341 
342 
wifi_clear_nud_stats(wifi_interface_handle iface)343 wifi_error wifi_clear_nud_stats(wifi_interface_handle iface)
344 {
345     wifi_error ret;
346     NUDStatsCommand *NUDCommand;
347     struct nlattr *nl_data;
348     interface_info *iinfo = getIfaceInfo(iface);
349     wifi_handle handle = getWifiHandle(iface);
350 
351     NUDCommand = NUDStatsCommand::instance(handle);
352     if (NUDCommand == NULL) {
353         ALOGE("%s: Error NUDStatsCommand NULL", __FUNCTION__);
354         return WIFI_ERROR_INVALID_ARGS;
355     }
356     NUDCommand->setSubCmd(QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET);
357 
358     /* create the message */
359     ret = NUDCommand->create();
360     if (ret != WIFI_SUCCESS)
361         goto cleanup;
362 
363     ret = NUDCommand->set_iface_id(iinfo->name);
364     if (ret != WIFI_SUCCESS)
365         goto cleanup;
366 
367     /*add the attributes*/
368     nl_data = NUDCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
369     if (!nl_data)
370         goto cleanup;
371 
372     NUDCommand->attr_end(nl_data);
373 
374     ret = NUDCommand->requestResponse();
375     if (ret != WIFI_SUCCESS)
376         ALOGE("%s: requestResponse Error:%d",__FUNCTION__, ret);
377 
378 cleanup:
379     return ret;
380 }
381