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