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