1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Changes from Qualcomm Innovation Center are provided under the following license:
17 *
18 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted (subject to the limitations in the
22 * disclaimer below) provided that the following conditions are met:
23 *
24 * * Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 *
27 * * Redistributions in binary form must reproduce the above
28 * copyright notice, this list of conditions and the following
29 * disclaimer in the documentation and/or other materials provided
30 * with the distribution.
31 *
32 * * Neither the name of Qualcomm Innovation Center, Inc. nor the names of its
33 * contributors may be used to endorse or promote products derived
34 * from this software without specific prior written permission.
35 *
36 * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
37 * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
38 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
39 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
42 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
44 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
46 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
47 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
48 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 */
50
51 #include <stdint.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <sys/socket.h>
55 #include <netlink/genl/genl.h>
56 #include <netlink/genl/family.h>
57 #include <netlink/genl/ctrl.h>
58 #include <linux/rtnetlink.h>
59 #include <netpacket/packet.h>
60 #include <linux/filter.h>
61 #include <linux/errqueue.h>
62 #include <linux-private/linux/fib_rules.h>
63 #include <linux/pkt_sched.h>
64 #include <netlink/object-api.h>
65 #include <netlink/netlink.h>
66 #include <netlink/socket.h>
67 #if __has_include(<netlink-private/types.h>)
68 #include <netlink-private/object-api.h>
69 #include <netlink-private/types.h>
70 #else
71 #include <nl-priv-dynamic-core/nl-core.h>
72 #endif
73
74 #include "nl80211_copy.h"
75
76 #include <dirent.h>
77 #include <net/if.h>
78 #include <netinet/in.h>
79 #include <cld80211_lib.h>
80
81 #include <sys/types.h>
82 #include "list.h"
83 #include <unistd.h>
84
85 #include "sync.h"
86
87 #define LOG_TAG "WifiHAL"
88
89 #include <hardware_legacy/wifi_hal.h>
90 #include "wifi_hal_ctrl.h"
91 #include "common.h"
92 #include "cpp_bindings.h"
93 #include "ifaceeventhandler.h"
94 #include "wifiloggercmd.h"
95 #include "tcp_params_update.h"
96
97 /*
98 BUGBUG: normally, libnl allocates ports for all connections it makes; but
99 being a static library, it doesn't really know how many other netlink
100 connections are made by the same process, if connections come from different
101 shared libraries. These port assignments exist to solve that
102 problem - temporarily. We need to fix libnl to try and allocate ports across
103 the entire process.
104 */
105
106 #define WIFI_HAL_CMD_SOCK_PORT 644
107 #define WIFI_HAL_EVENT_SOCK_PORT 645
108
109 #define MAX_HW_VER_LENGTH 100
110 /*
111 * Defines for wifi_wait_for_driver_ready()
112 * Specify durations between polls and max wait time
113 */
114 #define POLL_DRIVER_DURATION_US (100000)
115 #define POLL_DRIVER_MAX_TIME_MS (10000)
116
117 static int attach_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg);
118
119 static int dettach_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg);
120
121 static int register_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg, int attach);
122
123 static int send_nl_data(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg);
124
125 static int internal_pollin_handler(wifi_handle handle, struct nl_sock *sock);
126
127 static void internal_event_handler_app(wifi_handle handle, int events,
128 struct ctrl_sock *sock);
129
130 static void internal_event_handler(wifi_handle handle, int events,
131 struct nl_sock *sock);
132 static int internal_valid_message_handler(nl_msg *msg, void *arg);
133 static int user_sock_message_handler(nl_msg *msg, void *arg);
134 static int wifi_get_multicast_id(wifi_handle handle, const char *name,
135 const char *group);
136 static int wifi_add_membership(wifi_handle handle, const char *group);
137 static wifi_error wifi_init_interfaces(wifi_handle handle);
138 static wifi_error wifi_set_packet_filter(wifi_interface_handle iface,
139 const u8 *program, u32 len);
140 static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
141 u32 *version, u32 *max_len);
142 static wifi_error wifi_read_packet_filter(wifi_interface_handle handle,
143 u32 src_offset, u8 *host_dst, u32 length);
144 static wifi_error wifi_configure_nd_offload(wifi_interface_handle iface,
145 u8 enable);
146 wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface,
147 WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt);
148 static int wifi_is_nan_ext_cmd_supported(wifi_interface_handle handle);
149
150 wifi_error
151 wifi_init_tcp_param_change_event_handler(wifi_interface_handle iface);
152
153 wifi_error wifi_set_voip_mode(wifi_interface_handle iface, wifi_voip_mode mode);
154
155 /* Initialize/Cleanup */
156
wifi_get_iface_handle(wifi_handle handle,char * name)157 wifi_interface_handle wifi_get_iface_handle(wifi_handle handle, char *name)
158 {
159 hal_info *info = (hal_info *)handle;
160 for (int i=0;i<info->num_interfaces;i++)
161 {
162 if (!strcmp(info->interfaces[i]->name, name))
163 {
164 return ((wifi_interface_handle )(info->interfaces)[i]);
165 }
166 }
167 return NULL;
168 }
169
wifi_socket_set_local_port(struct nl_sock * sock,uint32_t port)170 void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
171 {
172 /* Release local port pool maintained by libnl and assign a own port
173 * identifier to the socket.
174 */
175 nl_socket_set_local_port(sock, ((uint32_t)getpid() & 0x3FFFFFU) | (port << 22));
176 }
177
wifi_create_nl_socket(int port,int protocol)178 static nl_sock * wifi_create_nl_socket(int port, int protocol)
179 {
180 // ALOGI("Creating socket");
181 struct nl_sock *sock = nl_socket_alloc();
182 if (sock == NULL) {
183 ALOGE("Failed to create NL socket");
184 return NULL;
185 }
186
187 wifi_socket_set_local_port(sock, port);
188
189 if (nl_connect(sock, protocol)) {
190 ALOGE("Could not connect handle");
191 nl_socket_free(sock);
192 return NULL;
193 }
194
195 return sock;
196 }
197
wifi_create_ctrl_socket(hal_info * info)198 void wifi_create_ctrl_socket(hal_info *info)
199 {
200 #ifdef ANDROID
201 struct group *grp_wifi;
202 gid_t gid_wifi;
203 struct passwd *pwd_system;
204 uid_t uid_system;
205 #endif
206
207 int flags;
208
209 info->wifihal_ctrl_sock.s = socket(PF_UNIX, SOCK_DGRAM, 0);
210
211 if (info->wifihal_ctrl_sock.s < 0) {
212 ALOGE("socket(PF_UNIX): %s", strerror(errno));
213 return;
214 }
215 memset(&info->wifihal_ctrl_sock.local, 0, sizeof(info->wifihal_ctrl_sock.local));
216
217 info->wifihal_ctrl_sock.local.sun_family = AF_UNIX;
218
219 snprintf(info->wifihal_ctrl_sock.local.sun_path,
220 sizeof(info->wifihal_ctrl_sock.local.sun_path), "%s", WIFI_HAL_CTRL_IFACE);
221
222 if (bind(info->wifihal_ctrl_sock.s, (struct sockaddr *) &info->wifihal_ctrl_sock.local,
223 sizeof(info->wifihal_ctrl_sock.local)) < 0) {
224 ALOGD("ctrl_iface bind(PF_UNIX) failed: %s",
225 strerror(errno));
226 if (connect(info->wifihal_ctrl_sock.s, (struct sockaddr *) &info->wifihal_ctrl_sock.local,
227 sizeof(info->wifihal_ctrl_sock.local)) < 0) {
228 ALOGD("ctrl_iface exists, but does not"
229 " allow connections - assuming it was left"
230 "over from forced program termination");
231 if (unlink(info->wifihal_ctrl_sock.local.sun_path) < 0) {
232 ALOGE("Could not unlink existing ctrl_iface socket '%s': %s",
233 info->wifihal_ctrl_sock.local.sun_path, strerror(errno));
234 goto out;
235
236 }
237 if (bind(info->wifihal_ctrl_sock.s ,
238 (struct sockaddr *) &info->wifihal_ctrl_sock.local,
239 sizeof(info->wifihal_ctrl_sock.local)) < 0) {
240 ALOGE("wifihal-ctrl-iface-init: bind(PF_UNIX): %s",
241 strerror(errno));
242 goto out;
243 }
244 ALOGD("Successfully replaced leftover "
245 "ctrl_iface socket '%s'", info->wifihal_ctrl_sock.local.sun_path);
246 } else {
247 ALOGI("ctrl_iface exists and seems to "
248 "be in use - cannot override it");
249 ALOGI("Delete '%s' manually if it is "
250 "not used anymore", info->wifihal_ctrl_sock.local.sun_path);
251 goto out;
252 }
253 }
254
255 /*
256 * Make socket non-blocking so that we don't hang forever if
257 * target dies unexpectedly.
258 */
259
260 #ifdef ANDROID
261 if (chmod(info->wifihal_ctrl_sock.local.sun_path, S_IRWXU | S_IRWXG) < 0)
262 {
263 ALOGE("Failed to give permissions: %s", strerror(errno));
264 }
265
266 /* Set group even if we do not have privileges to change owner */
267 grp_wifi = getgrnam("wifi");
268 gid_wifi = grp_wifi ? grp_wifi->gr_gid : 0;
269 pwd_system = getpwnam("system");
270 uid_system = pwd_system ? pwd_system->pw_uid : 0;
271 if (!gid_wifi || !uid_system) {
272 ALOGE("Failed to get grp ids");
273 unlink(info->wifihal_ctrl_sock.local.sun_path);
274 goto out;
275 }
276 chown(info->wifihal_ctrl_sock.local.sun_path, -1, gid_wifi);
277 chown(info->wifihal_ctrl_sock.local.sun_path, uid_system, gid_wifi);
278 #endif
279
280 flags = fcntl(info->wifihal_ctrl_sock.s, F_GETFL);
281 if (flags >= 0) {
282 flags |= O_NONBLOCK;
283 if (fcntl(info->wifihal_ctrl_sock.s, F_SETFL, flags) < 0) {
284 ALOGI("fcntl(ctrl, O_NONBLOCK): %s",
285 strerror(errno));
286 /* Not fatal, continue on.*/
287 }
288 }
289 return;
290
291 out:
292 close(info->wifihal_ctrl_sock.s);
293 info->wifihal_ctrl_sock.s = 0;
294 return;
295 }
296
ack_handler(struct nl_msg * msg,void * arg)297 int ack_handler(struct nl_msg *msg, void *arg)
298 {
299 int *err = (int *)arg;
300 *err = 0;
301 return NL_STOP;
302 }
303
finish_handler(struct nl_msg * msg,void * arg)304 int finish_handler(struct nl_msg *msg, void *arg)
305 {
306 int *ret = (int *)arg;
307 *ret = 0;
308 return NL_SKIP;
309 }
310
error_handler(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)311 int error_handler(struct sockaddr_nl *nla,
312 struct nlmsgerr *err, void *arg)
313 {
314 int *ret = (int *)arg;
315 *ret = err->error;
316
317 ALOGV("%s invoked with error: %d", __func__, err->error);
318 return NL_SKIP;
319 }
no_seq_check(struct nl_msg * msg,void * arg)320 static int no_seq_check(struct nl_msg *msg, void *arg)
321 {
322 return NL_OK;
323 }
324
acquire_supported_features(wifi_interface_handle iface,feature_set * set)325 static wifi_error acquire_supported_features(wifi_interface_handle iface,
326 feature_set *set)
327 {
328 wifi_error ret;
329 interface_info *iinfo = getIfaceInfo(iface);
330 wifi_handle handle = getWifiHandle(iface);
331 *set = 0;
332
333 WifihalGeneric supportedFeatures(handle, 0,
334 OUI_QCA,
335 QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES);
336
337 /* create the message */
338 ret = supportedFeatures.create();
339 if (ret != WIFI_SUCCESS)
340 goto cleanup;
341
342 ret = supportedFeatures.set_iface_id(iinfo->name);
343 if (ret != WIFI_SUCCESS)
344 goto cleanup;
345
346 ret = supportedFeatures.requestResponse();
347 if (ret != WIFI_SUCCESS) {
348 ALOGE("%s: requestResponse Error:%d",__func__, ret);
349 goto cleanup;
350 }
351
352 supportedFeatures.getResponseparams(set);
353
354 cleanup:
355 return ret;
356 }
357
acquire_driver_supported_features(wifi_interface_handle iface,features_info * driver_features)358 static wifi_error acquire_driver_supported_features(wifi_interface_handle iface,
359 features_info *driver_features)
360 {
361 wifi_error ret;
362 interface_info *iinfo = getIfaceInfo(iface);
363 wifi_handle handle = getWifiHandle(iface);
364
365 WifihalGeneric driverFeatures(handle, 0,
366 OUI_QCA,
367 QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES);
368
369 /* create the message */
370 ret = driverFeatures.create();
371 if (ret != WIFI_SUCCESS)
372 goto cleanup;
373
374 ret = driverFeatures.set_iface_id(iinfo->name);
375 if (ret != WIFI_SUCCESS)
376 goto cleanup;
377
378 ret = driverFeatures.requestResponse();
379 if (ret != WIFI_SUCCESS) {
380 ALOGE("%s: requestResponse Error:%d",__func__, ret);
381 goto cleanup;
382 }
383
384 driverFeatures.getDriverFeatures(driver_features);
385
386 cleanup:
387 return mapKernelErrortoWifiHalError(ret);
388 }
389
wifi_get_capabilities(wifi_interface_handle handle)390 static wifi_error wifi_get_capabilities(wifi_interface_handle handle)
391 {
392 wifi_error ret;
393 int requestId;
394 WifihalGeneric *wifihalGeneric;
395 wifi_handle wifiHandle = getWifiHandle(handle);
396 hal_info *info = getHalInfo(wifiHandle);
397
398 if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
399 ALOGE("%s: GSCAN is not supported by driver", __FUNCTION__);
400 return WIFI_ERROR_NOT_SUPPORTED;
401 }
402
403 /* No request id from caller, so generate one and pass it on to the driver.
404 * Generate it randomly.
405 */
406 requestId = get_requestid();
407
408 wifihalGeneric = new WifihalGeneric(
409 wifiHandle,
410 requestId,
411 OUI_QCA,
412 QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CAPABILITIES);
413 if (!wifihalGeneric) {
414 ALOGE("%s: Failed to create object of WifihalGeneric class", __FUNCTION__);
415 return WIFI_ERROR_OUT_OF_MEMORY;
416 }
417
418 ret = wifihalGeneric->wifiGetCapabilities(handle);
419
420 delete wifihalGeneric;
421 return ret;
422 }
423
wifi_get_sar_version(wifi_interface_handle handle)424 static wifi_error wifi_get_sar_version(wifi_interface_handle handle)
425 {
426 wifi_error ret;
427 wifi_handle wifiHandle = getWifiHandle(handle);
428
429 WifihalGeneric *sarVersion = new WifihalGeneric(
430 wifiHandle,
431 0,
432 OUI_QCA,
433 QCA_NL80211_VENDOR_SUBCMD_GET_SAR_CAPABILITY);
434 if (!sarVersion) {
435 ALOGE("%s: Failed to create object of WifihalGeneric class", __FUNCTION__);
436 return WIFI_ERROR_OUT_OF_MEMORY;
437 }
438
439
440 ret = sarVersion->getSarVersion(handle);
441
442 delete sarVersion;
443 return ret;
444 }
445
get_firmware_bus_max_size_supported(wifi_interface_handle iface)446 static wifi_error get_firmware_bus_max_size_supported(
447 wifi_interface_handle iface)
448 {
449 wifi_error ret;
450 interface_info *iinfo = getIfaceInfo(iface);
451 wifi_handle handle = getWifiHandle(iface);
452 hal_info *info = (hal_info *)handle;
453
454 WifihalGeneric busSizeSupported(handle, 0,
455 OUI_QCA,
456 QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE);
457
458 /* create the message */
459 ret = busSizeSupported.create();
460 if (ret != WIFI_SUCCESS)
461 goto cleanup;
462
463 ret = busSizeSupported.set_iface_id(iinfo->name);
464 if (ret != WIFI_SUCCESS)
465 goto cleanup;
466
467 ret = busSizeSupported.requestResponse();
468 if (ret != WIFI_SUCCESS) {
469 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
470 goto cleanup;
471 }
472 info->firmware_bus_max_size = busSizeSupported.getBusSize();
473
474 cleanup:
475 return ret;
476 }
477
wifi_init_user_sock(hal_info * info)478 static wifi_error wifi_init_user_sock(hal_info *info)
479 {
480 struct nl_sock *user_sock =
481 wifi_create_nl_socket(WIFI_HAL_USER_SOCK_PORT, NETLINK_USERSOCK);
482 if (user_sock == NULL) {
483 ALOGE("Could not create diag sock");
484 return WIFI_ERROR_UNKNOWN;
485 }
486
487 /* Set the socket buffer size */
488 if (nl_socket_set_buffer_size(user_sock, (256*1024), 0) < 0) {
489 ALOGE("Could not set size for user_sock: %s",
490 strerror(errno));
491 /* continue anyway with the default (smaller) buffer */
492 }
493 else {
494 ALOGV("nl_socket_set_buffer_size successful for user_sock");
495 }
496
497 struct nl_cb *cb = nl_socket_get_cb(user_sock);
498 if (cb == NULL) {
499 ALOGE("Could not get cb");
500 return WIFI_ERROR_UNKNOWN;
501 }
502
503 info->user_sock_arg = 1;
504 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
505 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &info->user_sock_arg);
506 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &info->user_sock_arg);
507 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &info->user_sock_arg);
508
509 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, user_sock_message_handler, info);
510 nl_cb_put(cb);
511
512 int ret = nl_socket_add_membership(user_sock, 1);
513 if (ret < 0) {
514 ALOGE("Could not add membership");
515 return WIFI_ERROR_UNKNOWN;
516 }
517
518 info->user_sock = user_sock;
519 ALOGV("Initiialized diag sock successfully");
520 return WIFI_SUCCESS;
521 }
522
wifi_init_cld80211_sock_cb(hal_info * info)523 static wifi_error wifi_init_cld80211_sock_cb(hal_info *info)
524 {
525 struct nl_cb *cb = nl_socket_get_cb(info->cldctx->sock);
526 if (cb == NULL) {
527 ALOGE("Could not get cb");
528 return WIFI_ERROR_UNKNOWN;
529 }
530
531 info->user_sock_arg = 1;
532 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
533 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &info->user_sock_arg);
534 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &info->user_sock_arg);
535 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &info->user_sock_arg);
536
537 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, user_sock_message_handler, info);
538 nl_cb_put(cb);
539
540 return WIFI_SUCCESS;
541 }
542
get_frequency_from_channel(uint32_t channel,wlan_mac_band band)543 static uint32_t get_frequency_from_channel(uint32_t channel, wlan_mac_band band)
544 {
545 uint32_t freq = 0;
546
547 switch (band)
548 {
549 case WLAN_MAC_2_4_BAND:
550 if (!(channel >= 1 && channel <= 14))
551 goto failure;
552 //special handling for channel 14 by filling freq here
553 if (channel == 14)
554 freq = 2484;
555 else
556 freq = 2407 + (channel * 5);
557 break;
558 case WLAN_MAC_5_0_BAND:
559 if (!((channel >= 34 && channel < 65) ||
560 (channel > 99 && channel <= 196)))
561 goto failure;
562 freq = 5000 + (channel * 5);
563 break;
564 case WLAN_MAC_6_0_BAND:
565 if (!(channel >= 1 && channel <= 233))
566 goto failure;
567 freq = 5950 + (channel * 5);
568 break;
569 default:
570 break;
571 }
572
573 failure:
574 return freq;
575 }
576
get_nl_ifmask_from_coex_restriction_mask(u32 in_mask)577 static u32 get_nl_ifmask_from_coex_restriction_mask(u32 in_mask)
578 {
579 u32 op_mask = 0;
580
581 if (!in_mask)
582 return op_mask;
583 if (in_mask & SOFTAP)
584 op_mask |= BIT(NL80211_IFTYPE_AP);
585 if (in_mask & WIFI_DIRECT)
586 op_mask |= BIT(NL80211_IFTYPE_P2P_GO);
587 if (in_mask & WIFI_AWARE)
588 op_mask |= BIT(NL80211_IFTYPE_NAN);
589
590 return op_mask;
591 }
592
wifi_set_coex_unsafe_channels(wifi_handle handle,u32 num_channels,wifi_coex_unsafe_channel * unsafeChannels,u32 restrictions)593 wifi_error wifi_set_coex_unsafe_channels(wifi_handle handle, u32 num_channels,
594 wifi_coex_unsafe_channel *unsafeChannels,
595 u32 restrictions)
596 {
597 wifi_error ret = WIFI_ERROR_UNKNOWN;
598 WifihalGeneric *cmd = NULL;
599 struct nlattr *nl_data = NULL;
600 struct nlattr *nl_attr_unsafe_chan = NULL;
601 struct nlattr *unsafe_channels_attr = NULL;
602 hal_info *info = NULL;
603 int freq_cnt = 0;
604 u32 *freq = (u32 *) malloc(sizeof(u32) * num_channels);
605 u32 *power_cap_dbm = (u32 *) malloc(sizeof(u32) * num_channels);
606
607 if (!freq || !power_cap_dbm) {
608 ALOGE("%s: Failed to allocate memory", __FUNCTION__);
609 ret = WIFI_ERROR_OUT_OF_MEMORY;
610 goto cleanup;
611 }
612
613 if (!handle) {
614 ALOGE("%s: Error, wifi_handle NULL", __FUNCTION__);
615 goto cleanup;
616 }
617
618 info = getHalInfo(handle);
619 if (!info || info->num_interfaces < 1) {
620 ALOGE("%s: Error, wifi_handle NULL or base wlan interface not present",
621 __FUNCTION__);
622 goto cleanup;
623 }
624
625 cmd = new WifihalGeneric(handle, get_requestid(), OUI_QCA,
626 QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT);
627 if (cmd == NULL) {
628 ALOGE("%s: Error, created command NULL", __FUNCTION__);
629 ret = WIFI_ERROR_OUT_OF_MEMORY;
630 goto cleanup;
631 }
632
633 /* Create the NL message. */
634 ret = cmd->create();
635 if (ret < 0) {
636 ALOGE("%s: failed to create NL msg due to error: (%d)",
637 __FUNCTION__, ret);
638 goto cleanup;
639 }
640
641 /* Add the vendor specific attributes for the NL command. */
642 nl_data = cmd->attr_start(NL80211_ATTR_VENDOR_DATA);
643 if (!nl_data) {
644 ALOGE("%s: failed attr_start for NL80211_ATTR_VENDOR_DATA",
645 __FUNCTION__);
646 ret = WIFI_ERROR_OUT_OF_MEMORY;
647 goto cleanup;
648 }
649
650 nl_attr_unsafe_chan = cmd->attr_start(
651 QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE);
652 if (!nl_attr_unsafe_chan) {
653 ALOGE("%s: failed attr_start for"
654 " QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE", __FUNCTION__);
655 ret = WIFI_ERROR_OUT_OF_MEMORY;
656 goto cleanup;
657 }
658 ALOGD("%s: num_channels:%d, restrictions:%x", __FUNCTION__, num_channels,
659 restrictions);
660 for (int i = 0; i < num_channels; i++)
661 {
662 u32 frequency = get_frequency_from_channel(unsafeChannels[i].channel,
663 unsafeChannels[i].band);
664 if (frequency != 0)
665 {
666 freq[freq_cnt] = frequency;
667 power_cap_dbm[freq_cnt] = unsafeChannels[i].power_cap_dbm;
668 freq_cnt++;
669 ALOGV("%s: channel:%d, freq:%d, power_cap_dbm:%d, band:%d",
670 __FUNCTION__, unsafeChannels[i].channel, frequency,
671 unsafeChannels[i].power_cap_dbm, unsafeChannels[i].band);
672 }
673 else {
674 ALOGV("%s: Invalid channel found, channel:%d, power_cap_dbm:%d, band:%d",
675 __FUNCTION__, unsafeChannels[i].channel,
676 unsafeChannels[i].power_cap_dbm, unsafeChannels[i].band);
677 }
678 }
679 if (num_channels == 0) {
680 unsafe_channels_attr = cmd->attr_start(0);
681 if (!unsafe_channels_attr) {
682 ALOGE("%s: failed attr_start for unsafe_channels_attr when"
683 " trying to clear usafe channels clear", __FUNCTION__);
684 ret = WIFI_ERROR_OUT_OF_MEMORY;
685 goto cleanup;
686 }
687 ret = cmd->put_u32(
688 QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START, 0);
689 if (ret != WIFI_SUCCESS) {
690 ALOGE("%s: Failed to put frequency start, ret:%d",
691 __FUNCTION__, ret);
692 goto cleanup;
693 }
694 ret = cmd->put_u32(
695 QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END, 0);
696 if (ret != WIFI_SUCCESS) {
697 ALOGE("%s: Failed to put frequency end, ret:%d",
698 __FUNCTION__, ret);
699 goto cleanup;
700 }
701 cmd->attr_end(unsafe_channels_attr);
702 }
703 else {
704 if (!unsafeChannels) {
705 ALOGE("%s: unsafe channels buffer should not be NULL when"
706 " there are unsafe channels", __FUNCTION__);
707 ret = WIFI_ERROR_INVALID_ARGS;
708 goto cleanup;
709 }
710
711 if(freq_cnt == 0)
712 {
713 ALOGE("%s: No valid frequency, ignore channel list", __FUNCTION__);
714 ret = WIFI_ERROR_INVALID_ARGS;
715 goto cleanup;
716 }
717 for (int i = 0; i < freq_cnt; i++) {
718 unsafe_channels_attr = cmd->attr_start(i);
719 if (!unsafe_channels_attr) {
720 ALOGE("%s: failed attr_start for unsafe_channels_attr of"
721 " index:%d", __FUNCTION__, i);
722 ret = WIFI_ERROR_OUT_OF_MEMORY;
723 goto cleanup;
724 }
725
726 ret = cmd->put_u32(
727 QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START, freq[i]);
728 if (ret != WIFI_SUCCESS) {
729 ALOGE("%s: Failed to put frequency start, ret:%d",
730 __FUNCTION__, ret);
731 goto cleanup;
732 }
733 ret = cmd->put_u32(
734 QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END, freq[i]);
735 if (ret != WIFI_SUCCESS) {
736 ALOGE("%s: Failed to put frequency end, ret:%d",
737 __FUNCTION__, ret);
738 goto cleanup;
739 }
740 /**
741 * WIFI_COEX_NO_POWER_CAP (0x7FFFFFF) is specific to android
742 * framework, this value denotes that framework/wifihal is not
743 * providing any power cap and allow driver/firmware to operate on
744 * current power cap dbm. As driver is supposed to work on with
745 * LA/LE etc, we are skipping to send 0x7FFFFFF down to driver,
746 * hence driver will be operating as per current power cap calculated
747 * based on regulatory or other constraints.
748 */
749 if (power_cap_dbm[i] != WIFI_COEX_NO_POWER_CAP) {
750 ret = cmd->put_s32(
751 QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM,
752 power_cap_dbm[i]);
753 if (ret != WIFI_SUCCESS) {
754 ALOGE("%s: Failed to put power_cap_dbm, ret:%d",
755 __FUNCTION__, ret);
756 goto cleanup;
757 }
758 }
759 ALOGD("%s: freq:%d, power_cap_dbm:%d",
760 __FUNCTION__, freq[i], power_cap_dbm[i]);
761 cmd->attr_end(unsafe_channels_attr);
762 }
763 }
764 cmd->attr_end(nl_attr_unsafe_chan);
765 if (num_channels > 0) {
766 ret = cmd->put_u32(QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFACES_BITMASK,
767 get_nl_ifmask_from_coex_restriction_mask(restrictions));
768 if (ret != WIFI_SUCCESS) {
769 ALOGE("%s: Failed to put restrictions mask, ret:%d",
770 __FUNCTION__, ret);
771 goto cleanup;
772 }
773 }
774 cmd->attr_end(nl_data);
775
776 /* Send the msg and wait for a response. */
777 ret = cmd->requestResponse();
778 if (ret != WIFI_SUCCESS) {
779 ALOGE("%s: Error %d waiting for response.", __FUNCTION__, ret);
780 goto cleanup;
781 }
782
783 cleanup:
784 if (cmd)
785 delete cmd;
786 if (freq)
787 free (freq);
788 if (power_cap_dbm)
789 free (power_cap_dbm);
790 return ret;
791 }
792
wifi_set_dtim_config(wifi_interface_handle handle,u32 multiplier)793 wifi_error wifi_set_dtim_config(wifi_interface_handle handle, u32 multiplier)
794 {
795 wifi_error ret = WIFI_ERROR_INVALID_ARGS;
796 WifihalGeneric *cmd = NULL;
797 struct nlattr *nlData = NULL;
798 interface_info *ifaceInfo = NULL;
799 wifi_handle wifiHandle = NULL;
800
801 if (!handle) {
802 ALOGE("%s: Error, wifi_interface_handle NULL", __FUNCTION__);
803 goto cleanup;
804 }
805 ALOGD("%s: multiplier:%d", __FUNCTION__, multiplier);
806 wifiHandle = getWifiHandle(handle);
807 cmd = new WifihalGeneric(wifiHandle, get_requestid(), OUI_QCA,
808 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
809 if (cmd == NULL) {
810 ALOGE("%s: Error WifihalGeneric NULL", __FUNCTION__);
811 ret = WIFI_ERROR_OUT_OF_MEMORY;
812 goto cleanup;
813 }
814
815 /* Create the NL message. */
816 ret = cmd->create();
817 if (ret != WIFI_SUCCESS) {
818 ALOGE("%s: failed to create NL msg. Error:%d", __FUNCTION__, ret);
819 goto cleanup;
820 }
821 ifaceInfo = getIfaceInfo(handle);
822 if (!ifaceInfo) {
823 ALOGE("%s: getIfaceInfo is NULL", __FUNCTION__);
824 ret = WIFI_ERROR_OUT_OF_MEMORY;
825 goto cleanup;
826 }
827
828 /* Set the interface Id of the message. */
829 ret = cmd->set_iface_id(ifaceInfo->name);
830 if (ret != WIFI_SUCCESS) {
831 ALOGE("%s: failed to set iface id. Error:%d", __FUNCTION__, ret);
832 goto cleanup;
833 }
834
835 /* Add the vendor specific attributes for the NL command. */
836 nlData = cmd->attr_start(NL80211_ATTR_VENDOR_DATA);
837 if (!nlData) {
838 ALOGE("%s: failed attr_start for VENDOR_DATA", __FUNCTION__);
839 ret = WIFI_ERROR_OUT_OF_MEMORY;
840 goto cleanup;
841 }
842
843 ret = cmd->put_u32(QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_DTIM, multiplier);
844 if (ret != WIFI_SUCCESS) {
845 ALOGE("%s: failed to put vendor data. Error:%d", __FUNCTION__, ret);
846 goto cleanup;
847 }
848 cmd->attr_end(nlData);
849
850 /* Send the NL msg. */
851 ret = cmd->requestResponse();
852 if (ret != WIFI_SUCCESS) {
853 ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
854 goto cleanup;
855 }
856
857 cleanup:
858 if (cmd)
859 delete cmd;
860 return ret;
861 }
862
get_nl_band_mask(u32 in_mask)863 static u32 get_nl_band_mask(u32 in_mask)
864 {
865 u32 op_mask = 0;
866
867 if (in_mask & WLAN_MAC_2_4_BAND)
868 op_mask |= BIT(NL80211_BAND_2GHZ);
869 if (in_mask & WLAN_MAC_5_0_BAND)
870 op_mask |= BIT(NL80211_BAND_5GHZ);
871 if (in_mask & WLAN_MAC_6_0_BAND)
872 op_mask |= BIT(NL80211_BAND_6GHZ);
873 if (in_mask & WLAN_MAC_60_0_BAND)
874 op_mask |= BIT(NL80211_BAND_60GHZ);
875
876 return op_mask;
877 }
878
get_nl_iftype_mode_masks(u32 in_mask)879 static u32 get_nl_iftype_mode_masks(u32 in_mask)
880 {
881 u32 op_mask = 0;
882
883 if (in_mask & BIT(WIFI_INTERFACE_STA) ||
884 in_mask & BIT(WIFI_INTERFACE_TDLS))
885 op_mask |= BIT(NL80211_IFTYPE_STATION);
886 if (in_mask & BIT(WIFI_INTERFACE_SOFTAP))
887 op_mask |= BIT(NL80211_IFTYPE_AP);
888 if (in_mask & BIT(WIFI_INTERFACE_P2P_CLIENT))
889 op_mask |= BIT(NL80211_IFTYPE_P2P_CLIENT);
890 if (in_mask & BIT(WIFI_INTERFACE_P2P_GO))
891 op_mask |= BIT(NL80211_IFTYPE_P2P_GO);
892 if (in_mask & BIT(WIFI_INTERFACE_NAN))
893 op_mask |= BIT(NL80211_IFTYPE_NAN);
894
895 return op_mask;
896 }
897
get_vendor_filter_mask(u32 in_mask)898 static u32 get_vendor_filter_mask(u32 in_mask)
899 {
900 u32 op_mask = 0;
901
902 if (in_mask & WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE)
903 op_mask |= BIT(QCA_WLAN_VENDOR_FILTER_CELLULAR_COEX);
904 if (in_mask & WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY)
905 op_mask |= BIT(QCA_WLAN_VENDOR_FILTER_WLAN_CONCURRENCY);
906
907 return op_mask;
908 }
909
wifi_get_usable_channels(wifi_handle handle,u32 band_mask,u32 iface_mode_mask,u32 filter_mask,u32 max_size,u32 * size,wifi_usable_channel * channels)910 wifi_error wifi_get_usable_channels(wifi_handle handle, u32 band_mask,
911 u32 iface_mode_mask, u32 filter_mask,
912 u32 max_size, u32* size,
913 wifi_usable_channel* channels)
914 {
915 wifi_error ret = WIFI_ERROR_UNKNOWN;
916 WifihalGeneric *cmd = NULL;
917 struct nlattr *nl_data = NULL;
918 hal_info *info = NULL;
919 u32 band = 0, iface_mask = 0, filter = 0;
920
921 if (!handle) {
922 ALOGE("%s: Error, wifi_handle NULL", __FUNCTION__);
923 goto cleanup;
924 }
925
926 info = getHalInfo(handle);
927 if (!info || info->num_interfaces < 1) {
928 ALOGE("%s: Error, wifi_handle NULL or base wlan interface not present",
929 __FUNCTION__);
930 goto cleanup;
931 }
932
933 if (!max_size) {
934 ALOGE("%s: max channel size is zero", __FUNCTION__);
935 ret = WIFI_ERROR_INVALID_ARGS;
936 goto cleanup;
937 }
938
939 if (!channels) {
940 ALOGE("%s: user input channel buffer NULL", __FUNCTION__);
941 ret = WIFI_ERROR_INVALID_ARGS;
942 goto cleanup;
943 }
944
945 cmd = new WifihalGeneric(handle, get_requestid(), OUI_QCA,
946 QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS);
947 if (cmd == NULL) {
948 ALOGE("%s: Error, created command NULL", __FUNCTION__);
949 ret = WIFI_ERROR_OUT_OF_MEMORY;
950 goto cleanup;
951 }
952
953 /* Create the NL message. */
954 ret = cmd->create();
955 if (ret < 0) {
956 ALOGE("%s: failed to create NL msg due to error: (%d)",
957 __FUNCTION__, ret);
958 goto cleanup;
959 }
960
961 /* Add the vendor specific attributes for the NL command. */
962 nl_data = cmd->attr_start(NL80211_ATTR_VENDOR_DATA);
963 if (!nl_data) {
964 ALOGE("%s: failed attr_start for VENDOR_DATA due to error",
965 __FUNCTION__);
966 ret = WIFI_ERROR_OUT_OF_MEMORY;
967 goto cleanup;
968 }
969
970 band = get_nl_band_mask(band_mask);
971 ret = cmd->put_u32(QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_BAND_MASK,
972 band);
973 if (ret != WIFI_SUCCESS) {
974 ALOGE("%s: failed to put vendor data due to error:%d",
975 __FUNCTION__, ret);
976 goto cleanup;
977 }
978
979 iface_mask = get_nl_iftype_mode_masks(iface_mode_mask);
980 ret = cmd->put_u32(QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_IFACE_MODE_MASK,
981 iface_mask);
982 if (ret != WIFI_SUCCESS) {
983 ALOGE("%s: failed to put vendor data due to error:%d",
984 __FUNCTION__, ret);
985 goto cleanup;
986 }
987
988 filter = get_vendor_filter_mask(filter_mask);
989 ret = cmd->put_u32(QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_FILTER_MASK,
990 filter);
991 if (ret != WIFI_SUCCESS) {
992 ALOGE("%s: failed to put vendor data due to error:%d",
993 __FUNCTION__, ret);
994 goto cleanup;
995 }
996
997 cmd->attr_end(nl_data);
998
999 /* Populate the input received from caller/framework. */
1000 cmd->setMaxSetSize(max_size);
1001 cmd->set_channels_buff(channels);
1002
1003 /* Send the msg and wait for a response. */
1004 ret = cmd->requestResponse();
1005 if (ret != WIFI_SUCCESS) {
1006 ALOGE("%s: Error %d waiting for response.", __FUNCTION__, ret);
1007 goto cleanup;
1008 }
1009
1010 *size = cmd->get_results_size();
1011
1012 cleanup:
1013 if (cmd)
1014 delete cmd;
1015 return ret;
1016 }
1017
1018 /*initialize function pointer table with Qualcomm HAL API*/
init_wifi_vendor_hal_func_table(wifi_hal_fn * fn)1019 wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn) {
1020 if (fn == NULL) {
1021 return WIFI_ERROR_UNKNOWN;
1022 }
1023
1024 fn->wifi_initialize = wifi_initialize;
1025 fn->wifi_wait_for_driver_ready = wifi_wait_for_driver_ready;
1026 fn->wifi_cleanup = wifi_cleanup;
1027 fn->wifi_event_loop = wifi_event_loop;
1028 fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set;
1029 fn->wifi_get_concurrency_matrix = wifi_get_concurrency_matrix;
1030 fn->wifi_set_scanning_mac_oui = wifi_set_scanning_mac_oui;
1031 fn->wifi_get_ifaces = wifi_get_ifaces;
1032 fn->wifi_get_iface_name = wifi_get_iface_name;
1033 fn->wifi_set_iface_event_handler = wifi_set_iface_event_handler;
1034 fn->wifi_reset_iface_event_handler = wifi_reset_iface_event_handler;
1035 fn->wifi_start_gscan = wifi_start_gscan;
1036 fn->wifi_stop_gscan = wifi_stop_gscan;
1037 fn->wifi_get_cached_gscan_results = wifi_get_cached_gscan_results;
1038 fn->wifi_set_bssid_hotlist = wifi_set_bssid_hotlist;
1039 fn->wifi_reset_bssid_hotlist = wifi_reset_bssid_hotlist;
1040 fn->wifi_set_significant_change_handler = wifi_set_significant_change_handler;
1041 fn->wifi_reset_significant_change_handler = wifi_reset_significant_change_handler;
1042 fn->wifi_get_gscan_capabilities = wifi_get_gscan_capabilities;
1043 fn->wifi_set_link_stats = wifi_set_link_stats;
1044 fn->wifi_get_link_stats = wifi_get_link_stats;
1045 fn->wifi_clear_link_stats = wifi_clear_link_stats;
1046 fn->wifi_get_valid_channels = wifi_get_valid_channels;
1047 fn->wifi_rtt_range_request = wifi_rtt_range_request;
1048 fn->wifi_rtt_range_cancel = wifi_rtt_range_cancel;
1049 fn->wifi_get_rtt_capabilities = wifi_get_rtt_capabilities;
1050 fn->wifi_rtt_get_responder_info = wifi_rtt_get_responder_info;
1051 fn->wifi_enable_responder = wifi_enable_responder;
1052 fn->wifi_disable_responder = wifi_disable_responder;
1053 fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag;
1054 fn->wifi_start_logging = wifi_start_logging;
1055 fn->wifi_set_epno_list = wifi_set_epno_list;
1056 fn->wifi_reset_epno_list = wifi_reset_epno_list;
1057 fn->wifi_set_country_code = wifi_set_country_code;
1058 fn->wifi_enable_tdls = wifi_enable_tdls;
1059 fn->wifi_disable_tdls = wifi_disable_tdls;
1060 fn->wifi_get_tdls_status = wifi_get_tdls_status;
1061 fn->wifi_get_tdls_capabilities = wifi_get_tdls_capabilities;
1062 fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump;
1063 fn->wifi_set_log_handler = wifi_set_log_handler;
1064 fn->wifi_reset_log_handler = wifi_reset_log_handler;
1065 fn->wifi_set_alert_handler = wifi_set_alert_handler;
1066 fn->wifi_reset_alert_handler = wifi_reset_alert_handler;
1067 fn->wifi_get_firmware_version = wifi_get_firmware_version;
1068 fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status;
1069 fn->wifi_get_logger_supported_feature_set = wifi_get_logger_supported_feature_set;
1070 fn->wifi_get_ring_data = wifi_get_ring_data;
1071 fn->wifi_get_driver_version = wifi_get_driver_version;
1072 fn->wifi_set_passpoint_list = wifi_set_passpoint_list;
1073 fn->wifi_reset_passpoint_list = wifi_reset_passpoint_list;
1074 fn->wifi_set_lci = wifi_set_lci;
1075 fn->wifi_set_lcr = wifi_set_lcr;
1076 fn->wifi_start_sending_offloaded_packet =
1077 wifi_start_sending_offloaded_packet;
1078 fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet;
1079 fn->wifi_start_rssi_monitoring = wifi_start_rssi_monitoring;
1080 fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring;
1081 fn->wifi_nan_enable_request = nan_enable_request;
1082 fn->wifi_nan_disable_request = nan_disable_request;
1083 fn->wifi_nan_publish_request = nan_publish_request;
1084 fn->wifi_nan_publish_cancel_request = nan_publish_cancel_request;
1085 fn->wifi_nan_subscribe_request = nan_subscribe_request;
1086 fn->wifi_nan_subscribe_cancel_request = nan_subscribe_cancel_request;
1087 fn->wifi_nan_transmit_followup_request = nan_transmit_followup_request;
1088 fn->wifi_nan_stats_request = nan_stats_request;
1089 fn->wifi_nan_config_request = nan_config_request;
1090 fn->wifi_nan_tca_request = nan_tca_request;
1091 fn->wifi_nan_beacon_sdf_payload_request = nan_beacon_sdf_payload_request;
1092 fn->wifi_nan_register_handler = nan_register_handler;
1093 fn->wifi_nan_get_version = nan_get_version;
1094 fn->wifi_set_packet_filter = wifi_set_packet_filter;
1095 fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities;
1096 fn->wifi_read_packet_filter = wifi_read_packet_filter;
1097 fn->wifi_nan_get_capabilities = nan_get_capabilities;
1098 fn->wifi_nan_data_interface_create = nan_data_interface_create;
1099 fn->wifi_nan_data_interface_delete = nan_data_interface_delete;
1100 fn->wifi_nan_data_request_initiator = nan_data_request_initiator;
1101 fn->wifi_nan_data_indication_response = nan_data_indication_response;
1102 fn->wifi_nan_data_end = nan_data_end;
1103 fn->wifi_configure_nd_offload = wifi_configure_nd_offload;
1104 fn->wifi_get_driver_memory_dump = wifi_get_driver_memory_dump;
1105 fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;
1106 fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring;
1107 fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates;
1108 fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates;
1109 fn->wifi_get_roaming_capabilities = wifi_get_roaming_capabilities;
1110 fn->wifi_configure_roaming = wifi_configure_roaming;
1111 fn->wifi_enable_firmware_roaming = wifi_enable_firmware_roaming;
1112 fn->wifi_select_tx_power_scenario = wifi_select_tx_power_scenario;
1113 fn->wifi_reset_tx_power_scenario = wifi_reset_tx_power_scenario;
1114 fn->wifi_set_radio_mode_change_handler = wifi_set_radio_mode_change_handler;
1115 /* Customers will uncomment when they want to set qpower*/
1116 //fn->wifi_set_qpower = wifi_set_qpower;
1117 fn->wifi_virtual_interface_create = wifi_virtual_interface_create;
1118 fn->wifi_virtual_interface_delete = wifi_virtual_interface_delete;
1119 fn->wifi_set_latency_mode = wifi_set_latency_mode;
1120 fn->wifi_set_thermal_mitigation_mode = wifi_set_thermal_mitigation_mode;
1121 fn->wifi_multi_sta_set_primary_connection = wifi_multi_sta_set_primary_connection;
1122 fn->wifi_multi_sta_set_use_case = wifi_multi_sta_set_use_case;
1123 fn->wifi_set_coex_unsafe_channels = wifi_set_coex_unsafe_channels;
1124 fn->wifi_set_dtim_config = wifi_set_dtim_config;
1125 fn->wifi_set_voip_mode = wifi_set_voip_mode;
1126 fn->wifi_get_usable_channels = wifi_get_usable_channels;
1127
1128 return WIFI_SUCCESS;
1129 }
1130
cld80211lib_cleanup(hal_info * info)1131 static void cld80211lib_cleanup(hal_info *info)
1132 {
1133 if (!info->cldctx)
1134 return;
1135 cld80211_remove_mcast_group(info->cldctx, "host_logs");
1136 cld80211_remove_mcast_group(info->cldctx, "fw_logs");
1137 cld80211_remove_mcast_group(info->cldctx, "per_pkt_stats");
1138 cld80211_remove_mcast_group(info->cldctx, "diag_events");
1139 cld80211_remove_mcast_group(info->cldctx, "fatal_events");
1140 cld80211_remove_mcast_group(info->cldctx, "oem_msgs");
1141 exit_cld80211_recv(info->cldctx);
1142 cld80211_deinit(info->cldctx);
1143 info->cldctx = NULL;
1144 }
1145
wifi_get_iface_id(hal_info * info,const char * iface)1146 static int wifi_get_iface_id(hal_info *info, const char *iface)
1147 {
1148 int i;
1149 for (i = 0; i < info->num_interfaces; i++)
1150 if (!strcmp(info->interfaces[i]->name, iface))
1151 return i;
1152 return -1;
1153 }
1154
wifi_initialize(wifi_handle * handle)1155 wifi_error wifi_initialize(wifi_handle *handle)
1156 {
1157 wifi_error ret = WIFI_ERROR_UNKNOWN;
1158 wifi_interface_handle iface_handle;
1159 struct nl_sock *cmd_sock = NULL;
1160 struct nl_sock *event_sock = NULL;
1161 struct nl_cb *cb = NULL;
1162 int status = 0;
1163 int index;
1164 char hw_ver_type[MAX_HW_VER_LENGTH];
1165 char *hw_name = NULL;
1166
1167 ALOGI("Initializing wifi");
1168 hal_info *info = (hal_info *)malloc(sizeof(hal_info));
1169 if (info == NULL) {
1170 ALOGE("Could not allocate hal_info");
1171 return WIFI_ERROR_OUT_OF_MEMORY;
1172 }
1173
1174 memset(info, 0, sizeof(*info));
1175
1176 cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT,
1177 NETLINK_GENERIC);
1178 if (cmd_sock == NULL) {
1179 ALOGE("Failed to create command socket port");
1180 ret = WIFI_ERROR_UNKNOWN;
1181 goto unload;
1182 }
1183
1184 /* Set the socket buffer size */
1185 if (nl_socket_set_buffer_size(cmd_sock, (256*1024), 0) < 0) {
1186 ALOGE("Could not set nl_socket RX buffer size for cmd_sock: %s",
1187 strerror(errno));
1188 /* continue anyway with the default (smaller) buffer */
1189 }
1190
1191 event_sock =
1192 wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT, NETLINK_GENERIC);
1193 if (event_sock == NULL) {
1194 ALOGE("Failed to create event socket port");
1195 ret = WIFI_ERROR_UNKNOWN;
1196 goto unload;
1197 }
1198
1199 /* Set the socket buffer size */
1200 if (nl_socket_set_buffer_size(event_sock, (256*1024), 0) < 0) {
1201 ALOGE("Could not set nl_socket RX buffer size for event_sock: %s",
1202 strerror(errno));
1203 /* continue anyway with the default (smaller) buffer */
1204 }
1205
1206 cb = nl_socket_get_cb(event_sock);
1207 if (cb == NULL) {
1208 ALOGE("Failed to get NL control block for event socket port");
1209 ret = WIFI_ERROR_UNKNOWN;
1210 goto unload;
1211 }
1212
1213 info->event_sock_arg = 1;
1214 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
1215 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &info->event_sock_arg);
1216 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &info->event_sock_arg);
1217 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &info->event_sock_arg);
1218
1219 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler,
1220 info);
1221 nl_cb_put(cb);
1222
1223 info->cmd_sock = cmd_sock;
1224 info->event_sock = event_sock;
1225 info->clean_up = false;
1226 info->in_event_loop = false;
1227
1228 info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE);
1229 if (info->event_cb == NULL) {
1230 ALOGE("Could not allocate event_cb");
1231 ret = WIFI_ERROR_OUT_OF_MEMORY;
1232 goto unload;
1233 }
1234 info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE;
1235 info->num_event_cb = 0;
1236
1237 info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211");
1238 if (info->nl80211_family_id < 0) {
1239 ALOGE("Could not resolve nl80211 familty id");
1240 ret = WIFI_ERROR_UNKNOWN;
1241 goto unload;
1242 }
1243
1244 pthread_mutex_init(&info->cb_lock, NULL);
1245 pthread_mutex_init(&info->pkt_fate_stats_lock, NULL);
1246
1247 *handle = (wifi_handle) info;
1248
1249 wifi_add_membership(*handle, "scan");
1250 wifi_add_membership(*handle, "mlme");
1251 wifi_add_membership(*handle, "regulatory");
1252 wifi_add_membership(*handle, "vendor");
1253
1254 info->wifihal_ctrl_sock.s = 0;
1255
1256 wifi_create_ctrl_socket(info);
1257
1258 //! Initailise the monitoring clients list
1259 INITIALISE_LIST(&info->monitor_sockets);
1260
1261 info->cldctx = cld80211_init();
1262 if (info->cldctx != NULL) {
1263 info->user_sock = info->cldctx->sock;
1264 ret = wifi_init_cld80211_sock_cb(info);
1265 if (ret != WIFI_SUCCESS) {
1266 ALOGE("Could not set cb for CLD80211 family");
1267 goto cld80211_cleanup;
1268 }
1269
1270 status = cld80211_add_mcast_group(info->cldctx, "host_logs");
1271 if (status) {
1272 ALOGE("Failed to add mcast group host_logs :%d", status);
1273 goto cld80211_cleanup;
1274 }
1275 status = cld80211_add_mcast_group(info->cldctx, "fw_logs");
1276 if (status) {
1277 ALOGE("Failed to add mcast group fw_logs :%d", status);
1278 goto cld80211_cleanup;
1279 }
1280 status = cld80211_add_mcast_group(info->cldctx, "per_pkt_stats");
1281 if (status) {
1282 ALOGE("Failed to add mcast group per_pkt_stats :%d", status);
1283 goto cld80211_cleanup;
1284 }
1285 status = cld80211_add_mcast_group(info->cldctx, "diag_events");
1286 if (status) {
1287 ALOGE("Failed to add mcast group diag_events :%d", status);
1288 goto cld80211_cleanup;
1289 }
1290 status = cld80211_add_mcast_group(info->cldctx, "fatal_events");
1291 if (status) {
1292 ALOGE("Failed to add mcast group fatal_events :%d", status);
1293 goto cld80211_cleanup;
1294 }
1295
1296 if(info->wifihal_ctrl_sock.s > 0)
1297 {
1298 status = cld80211_add_mcast_group(info->cldctx, "oem_msgs");
1299 if (status) {
1300 ALOGE("Failed to add mcast group oem_msgs :%d", status);
1301 goto cld80211_cleanup;
1302 }
1303 }
1304 } else {
1305 ret = wifi_init_user_sock(info);
1306 if (ret != WIFI_SUCCESS) {
1307 ALOGE("Failed to alloc user socket");
1308 goto unload;
1309 }
1310 }
1311
1312 ret = wifi_init_interfaces(*handle);
1313 if (ret != WIFI_SUCCESS) {
1314 ALOGE("Failed to init interfaces");
1315 goto unload;
1316 }
1317
1318 if (info->num_interfaces == 0) {
1319 ALOGE("No interfaces found");
1320 ret = WIFI_ERROR_UNINITIALIZED;
1321 goto unload;
1322 }
1323
1324 index = wifi_get_iface_id(info, "wlan0");
1325 if (index == -1) {
1326 int i;
1327 for (i = 0; i < info->num_interfaces; i++)
1328 {
1329 free(info->interfaces[i]);
1330 }
1331 ALOGE("%s no iface with wlan0", __func__);
1332 ret = WIFI_ERROR_UNKNOWN;
1333 goto unload;
1334 }
1335 iface_handle = (wifi_interface_handle)info->interfaces[index];
1336
1337 ret = acquire_supported_features(iface_handle,
1338 &info->supported_feature_set);
1339 if (ret != WIFI_SUCCESS) {
1340 ALOGI("Failed to get supported feature set : %d", ret);
1341 //acquire_supported_features failure is acceptable condition as legacy
1342 //drivers might not support the required vendor command. So, do not
1343 //consider it as failure of wifi_initialize
1344 ret = WIFI_SUCCESS;
1345 }
1346
1347 ret = acquire_driver_supported_features(iface_handle,
1348 &info->driver_supported_features);
1349 if (ret != WIFI_SUCCESS) {
1350 ALOGI("Failed to get vendor feature set : %d", ret);
1351 ret = WIFI_SUCCESS;
1352 }
1353
1354 ret = wifi_get_logger_supported_feature_set(iface_handle,
1355 &info->supported_logger_feature_set);
1356 if (ret != WIFI_SUCCESS)
1357 ALOGE("Failed to get supported logger feature set: %d", ret);
1358
1359 ret = wifi_get_firmware_version(iface_handle, hw_ver_type,
1360 MAX_HW_VER_LENGTH);
1361 if (ret == WIFI_SUCCESS) {
1362 hw_name = strstr(hw_ver_type, "HW:");
1363 if (hw_name) {
1364 hw_name += strlen("HW:");
1365 if (strncmp(hw_name, "QCA6174", 7) == 0)
1366 info->pkt_log_ver = PKT_LOG_V1;
1367 else
1368 info->pkt_log_ver = PKT_LOG_V2;
1369 } else {
1370 info->pkt_log_ver = PKT_LOG_V0;
1371 }
1372 ALOGV("%s: hardware version type %d", __func__, info->pkt_log_ver);
1373 } else {
1374 ALOGE("Failed to get firmware version: %d", ret);
1375 }
1376
1377 ret = get_firmware_bus_max_size_supported(iface_handle);
1378 if (ret != WIFI_SUCCESS) {
1379 ALOGE("Failed to get supported bus size, error : %d", ret);
1380 info->firmware_bus_max_size = 1520;
1381 }
1382
1383 ret = wifi_logger_ring_buffers_init(info);
1384 if (ret != WIFI_SUCCESS)
1385 ALOGE("Wifi Logger Ring Initialization Failed");
1386
1387 ret = wifi_get_capabilities(iface_handle);
1388 if (ret != WIFI_SUCCESS)
1389 ALOGE("Failed to get wifi Capabilities, error: %d", ret);
1390
1391 info->pkt_stats = (struct pkt_stats_s *)malloc(sizeof(struct pkt_stats_s));
1392 if (!info->pkt_stats) {
1393 ALOGE("%s: malloc Failed for size: %zu",
1394 __FUNCTION__, sizeof(struct pkt_stats_s));
1395 ret = WIFI_ERROR_OUT_OF_MEMORY;
1396 goto unload;
1397 }
1398
1399 info->rx_buf_size_allocated = MAX_RXMPDUS_PER_AMPDU * MAX_MSDUS_PER_MPDU
1400 * PKT_STATS_BUF_SIZE;
1401
1402 info->rx_aggr_pkts =
1403 (wifi_ring_buffer_entry *)malloc(info->rx_buf_size_allocated);
1404 if (!info->rx_aggr_pkts) {
1405 ALOGE("%s: malloc Failed for size: %d",
1406 __FUNCTION__, info->rx_buf_size_allocated);
1407 ret = WIFI_ERROR_OUT_OF_MEMORY;
1408 info->rx_buf_size_allocated = 0;
1409 goto unload;
1410 }
1411 memset(info->rx_aggr_pkts, 0, info->rx_buf_size_allocated);
1412
1413 info->exit_sockets[0] = -1;
1414 info->exit_sockets[1] = -1;
1415
1416 if (socketpair(AF_UNIX, SOCK_STREAM, 0, info->exit_sockets) == -1) {
1417 ALOGE("Failed to create exit socket pair");
1418 ret = WIFI_ERROR_UNKNOWN;
1419 goto unload;
1420 }
1421
1422 ALOGV("Initializing Gscan Event Handlers");
1423 ret = initializeGscanHandlers(info);
1424 if (ret != WIFI_SUCCESS) {
1425 ALOGE("Initializing Gscan Event Handlers Failed");
1426 goto unload;
1427 }
1428
1429 ret = initializeRSSIMonitorHandler(info);
1430 if (ret != WIFI_SUCCESS) {
1431 ALOGE("Initializing RSSI Event Handler Failed");
1432 goto unload;
1433 }
1434
1435 ret = initializeRadioHandler(info);
1436 if (ret != WIFI_SUCCESS) {
1437 ALOGE("Initializing Radio Event handler Failed");
1438 goto unload;
1439 }
1440
1441 ret = wifi_init_tcp_param_change_event_handler(iface_handle);
1442 if (ret != WIFI_SUCCESS) {
1443 ALOGE("Initializing TCP param change event Handler Failed");
1444 goto unload;
1445 }
1446
1447 ALOGV("Initialized Wifi HAL Successfully; vendor cmd = %d Supported"
1448 " features : %" PRIx64, NL80211_CMD_VENDOR, info->supported_feature_set);
1449
1450 if (wifi_is_nan_ext_cmd_supported(iface_handle))
1451 info->support_nan_ext_cmd = true;
1452 else
1453 info->support_nan_ext_cmd = false;
1454
1455 ALOGV("support_nan_ext_cmd is %d",
1456 info->support_nan_ext_cmd);
1457
1458 ret = wifi_get_sar_version(iface_handle);
1459 if (ret != WIFI_SUCCESS) {
1460 ALOGE("Failed to get SAR Version, Setting it to default.");
1461 info->sar_version = QCA_WLAN_VENDOR_SAR_VERSION_1;
1462 ret = WIFI_SUCCESS;
1463 }
1464
1465 cld80211_cleanup:
1466 if (status != 0 || ret != WIFI_SUCCESS) {
1467 ret = WIFI_ERROR_UNKNOWN;
1468 cld80211lib_cleanup(info);
1469 }
1470 unload:
1471 if (ret != WIFI_SUCCESS) {
1472 if (cmd_sock)
1473 nl_socket_free(cmd_sock);
1474 if (event_sock)
1475 nl_socket_free(event_sock);
1476 if (info) {
1477 if (info->cldctx) {
1478 cld80211lib_cleanup(info);
1479 } else if (info->user_sock) {
1480 nl_socket_free(info->user_sock);
1481 }
1482 if (info->pkt_stats) free(info->pkt_stats);
1483 if (info->rx_aggr_pkts) free(info->rx_aggr_pkts);
1484 if (info->wifihal_ctrl_sock.s) close(info->wifihal_ctrl_sock.s);
1485 wifi_logger_ring_buffers_deinit(info);
1486 cleanupGscanHandlers(info);
1487 cleanupRSSIMonitorHandler(info);
1488 cleanupRadioHandler(info);
1489 cleanupTCPParamCommand(info);
1490 free(info->event_cb);
1491 if (info->driver_supported_features.flags) {
1492 free(info->driver_supported_features.flags);
1493 info->driver_supported_features.flags = NULL;
1494 }
1495 free(info);
1496 }
1497 }
1498
1499 return ret;
1500 }
1501
1502 #ifdef WIFI_DRIVER_STATE_CTRL_PARAM
wifi_update_driver_state(const char * state)1503 static int wifi_update_driver_state(const char *state) {
1504 struct timespec ts;
1505 int len, fd, ret = 0, count = 5;
1506 ts.tv_sec = 0;
1507 ts.tv_nsec = 200 * 1000000L;
1508 do {
1509 if (access(WIFI_DRIVER_STATE_CTRL_PARAM, W_OK) == 0)
1510 break;
1511 nanosleep(&ts, (struct timespec *)NULL);
1512 } while (--count > 0); /* wait at most 1 second for completion. */
1513 if (count == 0) {
1514 ALOGE("Failed to access driver state control param %s, %d at %s",
1515 strerror(errno), errno, WIFI_DRIVER_STATE_CTRL_PARAM);
1516 return -1;
1517 }
1518 fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_STATE_CTRL_PARAM, O_WRONLY));
1519 if (fd < 0) {
1520 ALOGE("Failed to open driver state control param at %s",
1521 WIFI_DRIVER_STATE_CTRL_PARAM);
1522 close(fd);
1523 return -1;
1524 }
1525 len = strlen(state) + 1;
1526 if (TEMP_FAILURE_RETRY(write(fd, state, len)) != len) {
1527 ALOGE("Failed to write driver state control param at %s",
1528 WIFI_DRIVER_STATE_CTRL_PARAM);
1529 close(fd);
1530 ret = -1;
1531 }
1532 close(fd);
1533 return ret;
1534 }
1535 #endif
1536
wifi_wait_for_driver_ready(void)1537 wifi_error wifi_wait_for_driver_ready(void)
1538 {
1539 // This function will wait to make sure basic client netdev is created
1540 // Function times out after 10 seconds
1541 int count = (POLL_DRIVER_MAX_TIME_MS * 1000) / POLL_DRIVER_DURATION_US;
1542 FILE *fd;
1543
1544 #if defined(WIFI_DRIVER_STATE_CTRL_PARAM) && defined(WIFI_DRIVER_STATE_ON)
1545 if (wifi_update_driver_state(WIFI_DRIVER_STATE_ON) < 0) {
1546 return WIFI_ERROR_UNKNOWN;
1547 }
1548 #endif
1549
1550 do {
1551 if ((fd = fopen("/sys/class/net/wlan0", "r")) != NULL) {
1552 fclose(fd);
1553 return WIFI_SUCCESS;
1554 }
1555 usleep(POLL_DRIVER_DURATION_US);
1556 } while(--count > 0);
1557
1558 ALOGE("Timed out wating on Driver ready ... ");
1559 return WIFI_ERROR_TIMED_OUT;
1560 }
1561
wifi_add_membership(wifi_handle handle,const char * group)1562 static int wifi_add_membership(wifi_handle handle, const char *group)
1563 {
1564 hal_info *info = getHalInfo(handle);
1565
1566 int id = wifi_get_multicast_id(handle, "nl80211", group);
1567 if (id < 0) {
1568 ALOGE("Could not find group %s", group);
1569 return id;
1570 }
1571
1572 int ret = nl_socket_add_membership(info->event_sock, id);
1573 if (ret < 0) {
1574 ALOGE("Could not add membership to group %s", group);
1575 }
1576
1577 return ret;
1578 }
1579
internal_cleaned_up_handler(wifi_handle handle)1580 static void internal_cleaned_up_handler(wifi_handle handle)
1581 {
1582 hal_info *info = getHalInfo(handle);
1583 wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler;
1584 wifihal_mon_sock_t *reg, *tmp;
1585
1586 if (info->cmd_sock != 0) {
1587 nl_socket_free(info->cmd_sock);
1588 nl_socket_free(info->event_sock);
1589 info->cmd_sock = NULL;
1590 info->event_sock = NULL;
1591 }
1592
1593 if (info->wifihal_ctrl_sock.s != 0) {
1594 close(info->wifihal_ctrl_sock.s);
1595 unlink(info->wifihal_ctrl_sock.local.sun_path);
1596 info->wifihal_ctrl_sock.s = 0;
1597 }
1598
1599 list_for_each_entry_safe(reg, tmp, &info->monitor_sockets, list) {
1600 del_from_list(®->list);
1601 free(reg);
1602 }
1603
1604 if (info->interfaces) {
1605 for (int i = 0; i < info->num_interfaces; i++)
1606 free(info->interfaces[i]);
1607 free(info->interfaces);
1608 }
1609
1610 if (info->cldctx != NULL) {
1611 cld80211lib_cleanup(info);
1612 } else if (info->user_sock != 0) {
1613 nl_socket_free(info->user_sock);
1614 info->user_sock = NULL;
1615 }
1616
1617 if (info->pkt_stats)
1618 free(info->pkt_stats);
1619 if (info->rx_aggr_pkts)
1620 free(info->rx_aggr_pkts);
1621 wifi_logger_ring_buffers_deinit(info);
1622 cleanupGscanHandlers(info);
1623 cleanupRSSIMonitorHandler(info);
1624 cleanupRadioHandler(info);
1625 cleanupTCPParamCommand(info);
1626
1627 if (info->num_event_cb)
1628 ALOGE("%d events were leftover without being freed",
1629 info->num_event_cb);
1630 free(info->event_cb);
1631
1632 if (info->exit_sockets[0] >= 0) {
1633 close(info->exit_sockets[0]);
1634 info->exit_sockets[0] = -1;
1635 }
1636
1637 if (info->exit_sockets[1] >= 0) {
1638 close(info->exit_sockets[1]);
1639 info->exit_sockets[1] = -1;
1640 }
1641
1642 if (info->pkt_fate_stats) {
1643 free(info->pkt_fate_stats);
1644 info->pkt_fate_stats = NULL;
1645 }
1646
1647 if (info->driver_supported_features.flags) {
1648 free(info->driver_supported_features.flags);
1649 info->driver_supported_features.flags = NULL;
1650 }
1651
1652 (*cleaned_up_handler)(handle);
1653 pthread_mutex_destroy(&info->cb_lock);
1654 pthread_mutex_destroy(&info->pkt_fate_stats_lock);
1655 free(info);
1656 }
1657
wifi_cleanup(wifi_handle handle,wifi_cleaned_up_handler handler)1658 void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
1659 {
1660 if (!handle) {
1661 ALOGE("Handle is null");
1662 return;
1663 }
1664
1665 hal_info *info = getHalInfo(handle);
1666 info->cleaned_up_handler = handler;
1667 // Remove the dynamically created interface during wifi cleanup.
1668 wifi_cleanup_dynamic_ifaces(handle);
1669
1670 TEMP_FAILURE_RETRY(write(info->exit_sockets[0], "E", 1));
1671
1672 // Ensure wifi_event_loop() exits by setting clean_up to true.
1673 info->clean_up = true;
1674 ALOGI("Sent msg on exit sock to unblock poll()");
1675 }
1676
1677
1678
validate_cld80211_msg(nlmsghdr * nlh,int family,int cmd)1679 static int validate_cld80211_msg(nlmsghdr *nlh, int family, int cmd)
1680 {
1681 //! Enhance this API
1682 struct genlmsghdr *hdr;
1683 hdr = (genlmsghdr *)nlmsg_data(nlh);
1684
1685 if (nlh->nlmsg_len > DEFAULT_PAGE_SIZE - sizeof(wifihal_ctrl_req_t))
1686 {
1687 ALOGE("%s: Invalid nlmsg length", __FUNCTION__);
1688 return -1;
1689 }
1690 if(hdr->cmd == WLAN_NL_MSG_OEM)
1691 {
1692 ALOGV("%s: FAMILY ID : %d ,NL CMD : %d received", __FUNCTION__,
1693 nlh->nlmsg_type, hdr->cmd);
1694
1695 //! Update pid with the wifihal pid
1696 nlh->nlmsg_pid = getpid();
1697 return 0;
1698 }
1699 else
1700 {
1701 ALOGE("%s: NL CMD : %d received is not allowed", __FUNCTION__, hdr->cmd);
1702 return -1;
1703 }
1704 }
1705
1706
validate_genl_msg(nlmsghdr * nlh,int family,int cmd)1707 static int validate_genl_msg(nlmsghdr *nlh, int family, int cmd)
1708 {
1709 //! Enhance this API
1710 struct genlmsghdr *hdr;
1711 hdr = (genlmsghdr *)nlmsg_data(nlh);
1712
1713 if (nlh->nlmsg_len > DEFAULT_PAGE_SIZE - sizeof(wifihal_ctrl_req_t))
1714 {
1715 ALOGE("%s: Invalid nlmsg length", __FUNCTION__);
1716 return -1;
1717 }
1718 if(hdr->cmd == NL80211_CMD_FRAME ||
1719 hdr->cmd == NL80211_CMD_REGISTER_ACTION)
1720 {
1721 ALOGV("%s: FAMILY ID : %d ,NL CMD : %d received", __FUNCTION__,
1722 nlh->nlmsg_type, hdr->cmd);
1723 return 0;
1724 }
1725 else
1726 {
1727 ALOGE("%s: NL CMD : %d received is not allowed", __FUNCTION__, hdr->cmd);
1728 return -1;
1729 }
1730 }
1731
send_nl_data(wifi_handle handle,wifihal_ctrl_req_t * ctrl_msg)1732 static int send_nl_data(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg)
1733 {
1734 hal_info *info = getHalInfo(handle);
1735 struct nl_msg *msg = NULL;
1736 int retval = -1;
1737
1738 //! attach monitor socket if it was not it the list
1739 if(ctrl_msg->monsock_len)
1740 {
1741 retval = attach_monitor_sock(handle, ctrl_msg);
1742 if(retval)
1743 goto nl_out;
1744 }
1745
1746 msg = nlmsg_alloc();
1747 if (!msg)
1748 {
1749 ALOGE("%s: Memory allocation failed \n", __FUNCTION__);
1750 goto nl_out;
1751 }
1752
1753 if (ctrl_msg->data_len > nlmsg_get_max_size(msg))
1754 {
1755 ALOGE("%s: Invalid ctrl msg length \n", __FUNCTION__);
1756 retval = -1;
1757 goto nl_out;
1758 }
1759 memcpy((char *)msg->nm_nlh, (char *)ctrl_msg->data, ctrl_msg->data_len);
1760
1761 if(ctrl_msg->family_name == GENERIC_NL_FAMILY)
1762 {
1763 //! Before sending the received gennlmsg to kernel,
1764 //! better to have checks for allowed commands
1765 retval = validate_genl_msg(msg->nm_nlh, ctrl_msg->family_name, ctrl_msg->cmd_id);
1766 if (retval < 0)
1767 goto nl_out;
1768
1769 retval = nl_send_auto_complete(info->event_sock, msg); /* send message */
1770 if (retval < 0)
1771 {
1772 ALOGE("%s: nl_send_auto_complete - failed : %d \n", __FUNCTION__, retval);
1773 goto nl_out;
1774 }
1775 ALOGI("%s: sent gennl msg of len: %d to driver\n", __FUNCTION__, ctrl_msg->data_len);
1776 retval = internal_pollin_handler(handle, info->event_sock);
1777 }
1778 else if (ctrl_msg->family_name == CLD80211_FAMILY)
1779 {
1780 if (info->cldctx != NULL)
1781 {
1782 //! Before sending the received cld80211 msg to kernel,
1783 //! better to have checks for allowed commands
1784 retval = validate_cld80211_msg(msg->nm_nlh, ctrl_msg->family_name, ctrl_msg->cmd_id);
1785 if (retval < 0)
1786 goto nl_out;
1787
1788 retval = cld80211_send_msg(info->cldctx, msg);
1789 if (retval != 0)
1790 {
1791 ALOGE("%s: send cld80211 message - failed\n", __FUNCTION__);
1792 goto nl_out;
1793 }
1794 ALOGI("%s: sent cld80211 msg of len: %d to driver\n", __FUNCTION__, ctrl_msg->data_len);
1795 }
1796 else
1797 {
1798 ALOGE("%s: cld80211 ctx not present \n", __FUNCTION__);
1799 }
1800 }
1801 else
1802 {
1803 ALOGE("%s: Unknown family name : %d \n", __FUNCTION__, ctrl_msg->family_name);
1804 retval = -1;
1805 }
1806 nl_out:
1807 if (msg)
1808 {
1809 nlmsg_free(msg);
1810 }
1811 return retval;
1812 }
1813
register_monitor_sock(wifi_handle handle,wifihal_ctrl_req_t * ctrl_msg,int attach)1814 static int register_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg, int attach)
1815 {
1816 hal_info *info = getHalInfo(handle);
1817
1818 wifihal_mon_sock_t *reg, *nreg;
1819 char *match = NULL;
1820 unsigned int match_len = 0;
1821 unsigned int type;
1822
1823 //! For Register Action frames, compare the match length and match buffer.
1824 //! For other registrations such as oem messages,
1825 //! diag messages check for respective commands
1826
1827 if((ctrl_msg->family_name == GENERIC_NL_FAMILY) &&
1828 (ctrl_msg->cmd_id == NL80211_CMD_REGISTER_ACTION))
1829 {
1830 struct genlmsghdr *genlh;
1831 struct nlmsghdr *nlh = (struct nlmsghdr *)ctrl_msg->data;
1832 genlh = (struct genlmsghdr *)nlmsg_data(nlh);
1833 struct nlattr *nlattrs[NL80211_ATTR_MAX + 1];
1834
1835 if (nlh->nlmsg_len > DEFAULT_PAGE_SIZE - sizeof(*ctrl_msg))
1836 {
1837 ALOGE("%s: Invalid nlmsg length", __FUNCTION__);
1838 return -1;
1839 }
1840 if (nla_parse(nlattrs, NL80211_ATTR_MAX, genlmsg_attrdata(genlh, 0),
1841 genlmsg_attrlen(genlh, 0), NULL))
1842 {
1843 ALOGE("unable to parse nl attributes");
1844 return -1;
1845 }
1846 if (!nlattrs[NL80211_ATTR_FRAME_TYPE])
1847 {
1848 ALOGD("No Valid frame type");
1849 }
1850 else
1851 {
1852 type = nla_get_u16(nlattrs[NL80211_ATTR_FRAME_TYPE]);
1853 }
1854 if (!nlattrs[NL80211_ATTR_FRAME_MATCH])
1855 {
1856 ALOGE("No Frame Match");
1857 return -1;
1858 }
1859 else
1860 {
1861 match_len = nla_len(nlattrs[NL80211_ATTR_FRAME_MATCH]);
1862 match = (char *)nla_data(nlattrs[NL80211_ATTR_FRAME_MATCH]);
1863
1864 list_for_each_entry(reg, &info->monitor_sockets, list) {
1865
1866 int mlen = min(match_len, reg->match_len);
1867
1868 if (reg->match_len == 0)
1869 continue;
1870
1871 if (memcmp(reg->match, match, mlen) == 0) {
1872
1873 if((ctrl_msg->monsock_len == reg->monsock_len) &&
1874 (memcmp((char *)®->monsock, (char *)&ctrl_msg->monsock, ctrl_msg->monsock_len) == 0))
1875 {
1876 if(attach)
1877 {
1878 ALOGE(" %s :Action frame already registered for this client ", __FUNCTION__);
1879 return -2;
1880 }
1881 else
1882 {
1883 del_from_list(®->list);
1884 free(reg);
1885 return 0;
1886 }
1887 }
1888 else
1889 {
1890 //! when action frame registered for other client,
1891 //! you can't attach or dettach for new client
1892 ALOGE(" %s :Action frame registered for other client ", __FUNCTION__);
1893 return -2;
1894 }
1895 }
1896 }
1897 }
1898 }
1899 else
1900 {
1901 list_for_each_entry(reg, &info->monitor_sockets, list) {
1902
1903 //! Checking for monitor sock in the list :
1904
1905 //! For attach request :
1906 //! if sock is not present, then it is a new entry , so add to list.
1907 //! if sock is present, and cmd_id does not match, add another entry to list.
1908 //! if sock is present, and cmd_id matches, return 0.
1909
1910 //! For dettach req :
1911 //! if sock is not present, return error -2.
1912 //! if sock is present, and cmd_id does not match, return error -2.
1913 //! if sock is present, and cmd_id matches, delete entry and return 0.
1914
1915 if (ctrl_msg->monsock_len != reg->monsock_len)
1916 continue;
1917
1918 if (memcmp((char *)®->monsock, (char *)&ctrl_msg->monsock, ctrl_msg->monsock_len) == 0) {
1919
1920 if((reg->family_name == ctrl_msg->family_name) && (reg->cmd_id == ctrl_msg->cmd_id))
1921 {
1922 if(!attach)
1923 {
1924 del_from_list(®->list);
1925 free(reg);
1926 }
1927 return 0;
1928 }
1929 }
1930 }
1931 }
1932
1933 if(attach)
1934 {
1935 if (ctrl_msg->monsock_len > sizeof(struct sockaddr_un))
1936 {
1937 ALOGE("%s: Invalid monitor socket length \n", __FUNCTION__);
1938 return -3;
1939 }
1940
1941 nreg = (wifihal_mon_sock_t *)malloc(sizeof(*reg) + match_len);
1942 if (!nreg)
1943 return -1;
1944
1945 memset((char *)nreg, 0, sizeof(*reg) + match_len);
1946 nreg->family_name = ctrl_msg->family_name;
1947 nreg->cmd_id = ctrl_msg->cmd_id;
1948 nreg->monsock_len = ctrl_msg->monsock_len;
1949 memcpy((char *)&nreg->monsock, (char *)&ctrl_msg->monsock, ctrl_msg->monsock_len);
1950
1951 if(match_len && match)
1952 {
1953 nreg->match_len = match_len;
1954 memcpy(nreg->match, match, match_len);
1955 }
1956 add_to_list(&nreg->list, &info->monitor_sockets);
1957 }
1958 else
1959 {
1960 //! Not attached, so cant be dettached
1961 ALOGE("%s: Dettaching the unregistered socket \n", __FUNCTION__);
1962 return -2;
1963 }
1964
1965 return 0;
1966 }
1967
attach_monitor_sock(wifi_handle handle,wifihal_ctrl_req_t * ctrl_msg)1968 static int attach_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg)
1969 {
1970 return register_monitor_sock(handle, ctrl_msg, 1);
1971 }
1972
dettach_monitor_sock(wifi_handle handle,wifihal_ctrl_req_t * ctrl_msg)1973 static int dettach_monitor_sock(wifi_handle handle, wifihal_ctrl_req_t *ctrl_msg)
1974 {
1975 return register_monitor_sock(handle, ctrl_msg, 0);
1976 }
1977
internal_pollin_handler_app(wifi_handle handle,struct ctrl_sock * sock)1978 static int internal_pollin_handler_app(wifi_handle handle, struct ctrl_sock *sock)
1979 {
1980 int retval = -1;
1981 int res;
1982 struct sockaddr_un from;
1983 socklen_t fromlen = sizeof(from);
1984 wifihal_ctrl_req_t *ctrl_msg;
1985 wifihal_ctrl_sync_rsp_t ctrl_reply;
1986
1987 ctrl_msg = (wifihal_ctrl_req_t *)malloc(DEFAULT_PAGE_SIZE);
1988 if(ctrl_msg == NULL)
1989 {
1990 ALOGE ("Memory allocation failure");
1991 return -1;
1992 }
1993
1994 memset((char *)ctrl_msg, 0, DEFAULT_PAGE_SIZE);
1995
1996 res = recvfrom(sock->s, (char *)ctrl_msg, DEFAULT_PAGE_SIZE, 0,
1997 (struct sockaddr *)&from, &fromlen);
1998 if (res < 0) {
1999 ALOGE("recvfrom(ctrl_iface): %s",
2000 strerror(errno));
2001 if(ctrl_msg)
2002 free(ctrl_msg);
2003
2004 return 0;
2005 }
2006 switch(ctrl_msg->ctrl_cmd)
2007 {
2008 case WIFIHAL_CTRL_MONITOR_ATTACH:
2009 retval = attach_monitor_sock(handle, ctrl_msg);
2010 break;
2011 case WIFIHAL_CTRL_MONITOR_DETTACH:
2012 retval = dettach_monitor_sock(handle, ctrl_msg);
2013 break;
2014 case WIFIHAL_CTRL_SEND_NL_DATA:
2015 retval = send_nl_data(handle, ctrl_msg);
2016 break;
2017 default:
2018 break;
2019 }
2020
2021 ctrl_reply.ctrl_cmd = ctrl_msg->ctrl_cmd;
2022 ctrl_reply.family_name = ctrl_msg->family_name;
2023 ctrl_reply.cmd_id = ctrl_msg->cmd_id;
2024 ctrl_reply.status = retval;
2025
2026 if(ctrl_msg)
2027 free(ctrl_msg);
2028
2029 if (sendto(sock->s, (char *)&ctrl_reply, sizeof(ctrl_reply), 0, (struct sockaddr *)&from,
2030 fromlen) < 0) {
2031 int _errno = errno;
2032 ALOGE("socket send failed : %d",_errno);
2033
2034 if (_errno == ENOBUFS || _errno == EAGAIN) {
2035 /*
2036 * The socket send buffer could be full. This
2037 * may happen if client programs are not
2038 * receiving their pending messages. Close and
2039 * reopen the socket as a workaround to avoid
2040 * getting stuck being unable to send any new
2041 * responses.
2042 */
2043 }
2044 }
2045 return res;
2046 }
2047
internal_pollin_handler(wifi_handle handle,struct nl_sock * sock)2048 static int internal_pollin_handler(wifi_handle handle, struct nl_sock *sock)
2049 {
2050 struct nl_cb *cb = nl_socket_get_cb(sock);
2051
2052 int res = nl_recvmsgs(sock, cb);
2053 if(res)
2054 ALOGE("Error :%d while reading nl msg", res);
2055 nl_cb_put(cb);
2056 return res;
2057 }
2058
internal_event_handler_app(wifi_handle handle,int events,struct ctrl_sock * sock)2059 static void internal_event_handler_app(wifi_handle handle, int events,
2060 struct ctrl_sock *sock)
2061 {
2062 if (events & POLLERR) {
2063 ALOGE("Error reading from wifi_hal ctrl socket");
2064 internal_pollin_handler_app(handle, sock);
2065 } else if (events & POLLHUP) {
2066 ALOGE("Remote side hung up");
2067 } else if (events & POLLIN) {
2068 //ALOGI("Found some events!!!");
2069 internal_pollin_handler_app(handle, sock);
2070 } else {
2071 ALOGE("Unknown event - %0x", events);
2072 }
2073 }
2074
internal_event_handler(wifi_handle handle,int events,struct nl_sock * sock)2075 static void internal_event_handler(wifi_handle handle, int events,
2076 struct nl_sock *sock)
2077 {
2078 if (events & POLLERR) {
2079 ALOGE("Error reading from socket");
2080 internal_pollin_handler(handle, sock);
2081 } else if (events & POLLHUP) {
2082 ALOGE("Remote side hung up");
2083 } else if (events & POLLIN) {
2084 //ALOGI("Found some events!!!");
2085 internal_pollin_handler(handle, sock);
2086 } else {
2087 ALOGE("Unknown event - %0x", events);
2088 }
2089 }
2090
exit_event_handler(int fd)2091 static bool exit_event_handler(int fd) {
2092 char buf[4];
2093 memset(buf, 0, sizeof(buf));
2094
2095 TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)));
2096 ALOGI("exit_event_handler, buf=%s", buf);
2097 if (strncmp(buf, "E", 1) == 0) {
2098 return true;
2099 }
2100
2101 return false;
2102 }
2103
2104 /* Run event handler */
wifi_event_loop(wifi_handle handle)2105 void wifi_event_loop(wifi_handle handle)
2106 {
2107 hal_info *info = getHalInfo(handle);
2108 if (info->in_event_loop) {
2109 return;
2110 } else {
2111 info->in_event_loop = true;
2112 }
2113
2114 pollfd pfd[4];
2115 memset(&pfd, 0, 4*sizeof(pfd[0]));
2116
2117 pfd[0].fd = nl_socket_get_fd(info->event_sock);
2118 pfd[0].events = POLLIN;
2119
2120 pfd[1].fd = nl_socket_get_fd(info->user_sock);
2121 pfd[1].events = POLLIN;
2122
2123 pfd[2].fd = info->exit_sockets[1];
2124 pfd[2].events = POLLIN;
2125
2126 if(info->wifihal_ctrl_sock.s > 0) {
2127 pfd[3].fd = info->wifihal_ctrl_sock.s ;
2128 pfd[3].events = POLLIN;
2129 }
2130 /* TODO: Add support for timeouts */
2131
2132 do {
2133 pfd[0].revents = 0;
2134 pfd[1].revents = 0;
2135 pfd[2].revents = 0;
2136 pfd[3].revents = 0;
2137 //ALOGI("Polling sockets");
2138 int result = poll(pfd, 4, -1);
2139 if (result < 0) {
2140 ALOGE("Error polling socket");
2141 } else {
2142 if (pfd[0].revents & (POLLIN | POLLHUP | POLLERR)) {
2143 internal_event_handler(handle, pfd[0].revents, info->event_sock);
2144 }
2145 if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) {
2146 internal_event_handler(handle, pfd[1].revents, info->user_sock);
2147 }
2148 if ((info->wifihal_ctrl_sock.s > 0) && (pfd[3].revents & (POLLIN | POLLHUP | POLLERR))) {
2149 internal_event_handler_app(handle, pfd[3].revents, &info->wifihal_ctrl_sock);
2150 }
2151 if (pfd[2].revents & POLLIN) {
2152 if (exit_event_handler(pfd[2].fd)) {
2153 break;
2154 }
2155 }
2156 }
2157 rb_timerhandler(info);
2158 } while (!info->clean_up);
2159 internal_cleaned_up_handler(handle);
2160 ALOGI("wifi_event_loop() exits success");
2161 }
2162
user_sock_message_handler(nl_msg * msg,void * arg)2163 static int user_sock_message_handler(nl_msg *msg, void *arg)
2164 {
2165 wifi_handle handle = (wifi_handle)arg;
2166 hal_info *info = getHalInfo(handle);
2167
2168 diag_message_handler(info, msg);
2169
2170 return NL_OK;
2171 }
2172
internal_valid_message_handler(nl_msg * msg,void * arg)2173 static int internal_valid_message_handler(nl_msg *msg, void *arg)
2174 {
2175 wifi_handle handle = (wifi_handle)arg;
2176 hal_info *info = getHalInfo(handle);
2177
2178 WifiEvent event(msg);
2179 int res = event.parse();
2180 if (res < 0) {
2181 ALOGE("Failed to parse event: %d", res);
2182 return NL_SKIP;
2183 }
2184
2185 int cmd = event.get_cmd();
2186 uint32_t vendor_id = 0;
2187 int subcmd = 0;
2188
2189 if (cmd == NL80211_CMD_VENDOR) {
2190 vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
2191 subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
2192 /* Restrict printing GSCAN_FULL_RESULT which is causing lot
2193 of logs in bug report */
2194 if (subcmd != QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT) {
2195 ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
2196 event.get_cmdString(), vendor_id, subcmd);
2197 }
2198 }
2199 else if((info->wifihal_ctrl_sock.s > 0) && (cmd == NL80211_CMD_FRAME))
2200 {
2201 struct genlmsghdr *genlh;
2202 struct nlmsghdr *nlh = nlmsg_hdr(msg);
2203 genlh = (struct genlmsghdr *)nlmsg_data(nlh);
2204 struct nlattr *nlattrs[NL80211_ATTR_MAX + 1];
2205
2206 wifihal_ctrl_event_t *ctrl_evt;
2207 char *buff;
2208 wifihal_mon_sock_t *reg;
2209
2210 nla_parse(nlattrs, NL80211_ATTR_MAX, genlmsg_attrdata(genlh, 0),
2211 genlmsg_attrlen(genlh, 0), NULL);
2212
2213 if (!nlattrs[NL80211_ATTR_FRAME])
2214 {
2215 ALOGD("No Frame body");
2216 return WIFI_SUCCESS;
2217 }
2218 ctrl_evt = (wifihal_ctrl_event_t *)malloc(sizeof(*ctrl_evt) + nlh->nlmsg_len);
2219 if(ctrl_evt == NULL)
2220 {
2221 ALOGE("Memory allocation failure");
2222 return -1;
2223 }
2224 memset((char *)ctrl_evt, 0, sizeof(*ctrl_evt) + nlh->nlmsg_len);
2225 ctrl_evt->family_name = GENERIC_NL_FAMILY;
2226 ctrl_evt->cmd_id = cmd;
2227 ctrl_evt->data_len = nlh->nlmsg_len;
2228 memcpy(ctrl_evt->data, (char *)nlh, ctrl_evt->data_len);
2229
2230
2231 buff = (char *)nla_data(nlattrs[NL80211_ATTR_FRAME]) + 24; //! Size of Wlan80211FrameHeader
2232
2233 list_for_each_entry(reg, &info->monitor_sockets, list) {
2234
2235 if (memcmp(reg->match, buff, reg->match_len))
2236 continue;
2237
2238 /* found match! */
2239 /* Indicate the received Action frame to respective client */
2240 ALOGI("send gennl msg of len : %d to apps", ctrl_evt->data_len);
2241 if (sendto(info->wifihal_ctrl_sock.s, (char *)ctrl_evt,
2242 sizeof(*ctrl_evt) + ctrl_evt->data_len,
2243 0, (struct sockaddr *)®->monsock, reg->monsock_len) < 0)
2244 {
2245 int _errno = errno;
2246 ALOGE("socket send failed : %d",_errno);
2247
2248 if (_errno == ENOBUFS || _errno == EAGAIN) {
2249 }
2250 }
2251
2252 }
2253 free(ctrl_evt);
2254 }
2255
2256 else {
2257 ALOGV("event received %s", event.get_cmdString());
2258 }
2259
2260 // event.log();
2261
2262 bool dispatched = false;
2263
2264 pthread_mutex_lock(&info->cb_lock);
2265
2266 for (int i = 0; i < info->num_event_cb; i++) {
2267 if (cmd == info->event_cb[i].nl_cmd) {
2268 if (cmd == NL80211_CMD_VENDOR
2269 && ((vendor_id != info->event_cb[i].vendor_id)
2270 || (subcmd != info->event_cb[i].vendor_subcmd)))
2271 {
2272 /* event for a different vendor, ignore it */
2273 continue;
2274 }
2275
2276 cb_info *cbi = &(info->event_cb[i]);
2277 pthread_mutex_unlock(&info->cb_lock);
2278 if (cbi->cb_func) {
2279 (*(cbi->cb_func))(msg, cbi->cb_arg);
2280 dispatched = true;
2281 }
2282 return NL_OK;
2283 }
2284 }
2285
2286 #ifdef QC_HAL_DEBUG
2287 if (!dispatched) {
2288 ALOGI("event ignored!!");
2289 }
2290 #endif
2291
2292 pthread_mutex_unlock(&info->cb_lock);
2293 return NL_OK;
2294 }
2295
2296 ////////////////////////////////////////////////////////////////////////////////
2297
2298 class GetMulticastIdCommand : public WifiCommand
2299 {
2300 private:
2301 const char *mName;
2302 const char *mGroup;
2303 int mId;
2304 public:
GetMulticastIdCommand(wifi_handle handle,const char * name,const char * group)2305 GetMulticastIdCommand(wifi_handle handle, const char *name,
2306 const char *group) : WifiCommand(handle, 0)
2307 {
2308 mName = name;
2309 mGroup = group;
2310 mId = -1;
2311 }
2312
getId()2313 int getId() {
2314 return mId;
2315 }
2316
create()2317 virtual wifi_error create() {
2318 int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
2319 // ALOGI("ctrl family = %d", nlctrlFamily);
2320 wifi_error ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
2321 if (ret != WIFI_SUCCESS)
2322 return ret;
2323
2324 ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName);
2325 return ret;
2326 }
2327
handleResponse(WifiEvent & reply)2328 virtual int handleResponse(WifiEvent& reply) {
2329
2330 // ALOGI("handling reponse in %s", __func__);
2331
2332 struct nlattr **tb = reply.attributes();
2333 struct nlattr *mcgrp = NULL;
2334 int i;
2335
2336 if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
2337 ALOGI("No multicast groups found");
2338 return NL_SKIP;
2339 } else {
2340 // ALOGI("Multicast groups attr size = %d",
2341 // nla_len(tb[CTRL_ATTR_MCAST_GROUPS]));
2342 }
2343
2344 for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
2345
2346 // ALOGI("Processing group");
2347 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
2348 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
2349 nla_len(mcgrp), NULL);
2350 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID])
2351 {
2352 continue;
2353 }
2354
2355 char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
2356 int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
2357
2358 // ALOGI("Found group name %s", grpName);
2359
2360 if (strncmp(grpName, mGroup, grpNameLen) != 0)
2361 continue;
2362
2363 mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
2364 break;
2365 }
2366
2367 return NL_SKIP;
2368 }
2369
2370 };
2371
wifi_get_multicast_id(wifi_handle handle,const char * name,const char * group)2372 static int wifi_get_multicast_id(wifi_handle handle, const char *name,
2373 const char *group)
2374 {
2375 GetMulticastIdCommand cmd(handle, name, group);
2376 int res = cmd.requestResponse();
2377 if (res < 0)
2378 return res;
2379 else
2380 return cmd.getId();
2381 }
2382
2383 /////////////////////////////////////////////////////////////////////////
2384
is_wifi_interface(const char * name)2385 static bool is_wifi_interface(const char *name)
2386 {
2387 // filter out bridge interface
2388 if (strstr(name, "br") != NULL) {
2389 return false;
2390 }
2391
2392 if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0
2393 && strncmp(name, "wifi", 4) != 0
2394 && strncmp(name, "swlan", 5) != 0) {
2395 /* not a wifi interface; ignore it */
2396 return false;
2397 } else {
2398 return true;
2399 }
2400 }
2401
get_interface(const char * name,interface_info * info)2402 static int get_interface(const char *name, interface_info *info)
2403 {
2404 strlcpy(info->name, name, (IFNAMSIZ + 1));
2405 info->id = if_nametoindex(name);
2406 // ALOGI("found an interface : %s, id = %d", name, info->id);
2407 return WIFI_SUCCESS;
2408 }
2409
wifi_init_interfaces(wifi_handle handle)2410 wifi_error wifi_init_interfaces(wifi_handle handle)
2411 {
2412 hal_info *info = (hal_info *)handle;
2413
2414 struct dirent *de;
2415
2416 DIR *d = opendir("/sys/class/net");
2417 if (d == 0)
2418 return WIFI_ERROR_UNKNOWN;
2419
2420 int n = 0;
2421 while ((de = readdir(d))) {
2422 if (de->d_name[0] == '.')
2423 continue;
2424 if (is_wifi_interface(de->d_name) ) {
2425 n++;
2426 }
2427 }
2428
2429 closedir(d);
2430
2431 d = opendir("/sys/class/net");
2432 if (d == 0)
2433 return WIFI_ERROR_UNKNOWN;
2434
2435 info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);
2436 if (info->interfaces == NULL) {
2437 ALOGE("%s: Error info->interfaces NULL", __func__);
2438 return WIFI_ERROR_OUT_OF_MEMORY;
2439 }
2440
2441 int i = 0;
2442 while ((de = readdir(d))) {
2443 if (de->d_name[0] == '.')
2444 continue;
2445 if (is_wifi_interface(de->d_name)) {
2446 interface_info *ifinfo
2447 = (interface_info *)malloc(sizeof(interface_info));
2448 if (ifinfo == NULL) {
2449 ALOGE("%s: Error ifinfo NULL", __func__);
2450 while (i > 0) {
2451 free(info->interfaces[i-1]);
2452 i--;
2453 }
2454 free(info->interfaces);
2455 return WIFI_ERROR_OUT_OF_MEMORY;
2456 }
2457 if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
2458 free(ifinfo);
2459 continue;
2460 }
2461 ifinfo->handle = handle;
2462 info->interfaces[i] = ifinfo;
2463 i++;
2464 }
2465 }
2466
2467 closedir(d);
2468
2469 info->num_interfaces = n;
2470
2471 return WIFI_SUCCESS;
2472 }
2473
wifi_get_ifaces(wifi_handle handle,int * num,wifi_interface_handle ** interfaces)2474 wifi_error wifi_get_ifaces(wifi_handle handle, int *num,
2475 wifi_interface_handle **interfaces)
2476 {
2477 hal_info *info = (hal_info *)handle;
2478
2479 /* In case of dynamic interface add/remove, interface handles need to be
2480 * updated so that, interface specific APIs could be instantiated.
2481 * Reload here to get interfaces which are dynamically added. */
2482
2483 if (info->num_interfaces > 0) {
2484 for (int i = 0; i < info->num_interfaces; i++)
2485 free(info->interfaces[i]);
2486 free(info->interfaces);
2487 }
2488
2489 wifi_error ret = wifi_init_interfaces(handle);
2490 if (ret != WIFI_SUCCESS) {
2491 ALOGE("Failed to init interfaces while wifi_get_ifaces");
2492 return ret;
2493 }
2494
2495 *interfaces = (wifi_interface_handle *)info->interfaces;
2496 *num = info->num_interfaces;
2497
2498 return WIFI_SUCCESS;
2499 }
2500
wifi_get_iface_name(wifi_interface_handle handle,char * name,size_t size)2501 wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name,
2502 size_t size)
2503 {
2504 interface_info *info = (interface_info *)handle;
2505 strlcpy(name, info->name, size);
2506 return WIFI_SUCCESS;
2507 }
2508
2509 /* Get the supported Feature set */
wifi_get_supported_feature_set(wifi_interface_handle iface,feature_set * set)2510 wifi_error wifi_get_supported_feature_set(wifi_interface_handle iface,
2511 feature_set *set)
2512 {
2513 int ret = 0;
2514 wifi_handle handle = getWifiHandle(iface);
2515 *set = 0;
2516 hal_info *info = getHalInfo(handle);
2517
2518 ret = acquire_supported_features(iface, set);
2519 if (ret != WIFI_SUCCESS) {
2520 *set = info->supported_feature_set;
2521 ALOGV("Supported feature set acquired at initialization : %" PRIx64, *set);
2522 } else {
2523 info->supported_feature_set = *set;
2524 ALOGV("Supported feature set acquired : %" PRIx64, *set);
2525 }
2526 return WIFI_SUCCESS;
2527 }
2528
wifi_get_concurrency_matrix(wifi_interface_handle handle,int set_size_max,feature_set set[],int * set_size)2529 wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle,
2530 int set_size_max,
2531 feature_set set[], int *set_size)
2532 {
2533 wifi_error ret;
2534 struct nlattr *nlData;
2535 WifihalGeneric *vCommand = NULL;
2536 interface_info *ifaceInfo = getIfaceInfo(handle);
2537 wifi_handle wifiHandle = getWifiHandle(handle);
2538
2539 if (set == NULL) {
2540 ALOGE("%s: NULL set pointer provided. Exit.",
2541 __func__);
2542 return WIFI_ERROR_INVALID_ARGS;
2543 }
2544
2545 vCommand = new WifihalGeneric(wifiHandle, 0,
2546 OUI_QCA,
2547 QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX);
2548 if (vCommand == NULL) {
2549 ALOGE("%s: Error vCommand NULL", __func__);
2550 return WIFI_ERROR_OUT_OF_MEMORY;
2551 }
2552
2553 /* Create the message */
2554 ret = vCommand->create();
2555 if (ret != WIFI_SUCCESS)
2556 goto cleanup;
2557
2558 ret = vCommand->set_iface_id(ifaceInfo->name);
2559 if (ret != WIFI_SUCCESS)
2560 goto cleanup;
2561
2562 /* Add the vendor specific attributes for the NL command. */
2563 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2564 if (!nlData){
2565 ret = WIFI_ERROR_UNKNOWN;
2566 goto cleanup;
2567 }
2568
2569 ret = vCommand->put_u32(
2570 QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX,
2571 set_size_max);
2572 if (ret != WIFI_SUCCESS)
2573 goto cleanup;
2574
2575 vCommand->attr_end(nlData);
2576
2577 /* Populate the input received from caller/framework. */
2578 vCommand->setMaxSetSize(set_size_max);
2579 vCommand->setSizePtr(set_size);
2580 vCommand->setConcurrencySet(set);
2581
2582 ret = vCommand->requestResponse();
2583 if (ret != WIFI_SUCCESS)
2584 ALOGE("%s: requestResponse() error: %d", __func__, ret);
2585
2586 cleanup:
2587 delete vCommand;
2588 if (ret)
2589 *set_size = 0;
2590 return ret;
2591 }
2592
2593
wifi_set_nodfs_flag(wifi_interface_handle handle,u32 nodfs)2594 wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs)
2595 {
2596 wifi_error ret;
2597 struct nlattr *nlData;
2598 WifiVendorCommand *vCommand = NULL;
2599 interface_info *ifaceInfo = getIfaceInfo(handle);
2600 wifi_handle wifiHandle = getWifiHandle(handle);
2601
2602 vCommand = new WifiVendorCommand(wifiHandle, 0,
2603 OUI_QCA,
2604 QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG);
2605 if (vCommand == NULL) {
2606 ALOGE("%s: Error vCommand NULL", __func__);
2607 return WIFI_ERROR_OUT_OF_MEMORY;
2608 }
2609
2610 /* Create the message */
2611 ret = vCommand->create();
2612 if (ret != WIFI_SUCCESS)
2613 goto cleanup;
2614
2615 ret = vCommand->set_iface_id(ifaceInfo->name);
2616 if (ret != WIFI_SUCCESS)
2617 goto cleanup;
2618
2619 /* Add the vendor specific attributes for the NL command. */
2620 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2621 if (!nlData){
2622 ret = WIFI_ERROR_UNKNOWN;
2623 goto cleanup;
2624 }
2625
2626 /* Add the fixed part of the mac_oui to the nl command */
2627 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG, nodfs);
2628 if (ret != WIFI_SUCCESS)
2629 goto cleanup;
2630
2631 vCommand->attr_end(nlData);
2632
2633 ret = vCommand->requestResponse();
2634 /* Don't check response since we aren't expecting one */
2635
2636 cleanup:
2637 delete vCommand;
2638 return ret;
2639 }
2640
wifi_start_sending_offloaded_packet(wifi_request_id id,wifi_interface_handle iface,u16 ether_type,u8 * ip_packet,u16 ip_packet_len,u8 * src_mac_addr,u8 * dst_mac_addr,u32 period_msec)2641 wifi_error wifi_start_sending_offloaded_packet(wifi_request_id id,
2642 wifi_interface_handle iface,
2643 u16 ether_type,
2644 u8 *ip_packet,
2645 u16 ip_packet_len,
2646 u8 *src_mac_addr,
2647 u8 *dst_mac_addr,
2648 u32 period_msec)
2649 {
2650 wifi_error ret;
2651 struct nlattr *nlData;
2652 WifiVendorCommand *vCommand = NULL;
2653
2654 ret = initialize_vendor_cmd(iface, id,
2655 QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS,
2656 &vCommand);
2657 if (ret != WIFI_SUCCESS) {
2658 ALOGE("%s: Initialization failed", __func__);
2659 return ret;
2660 }
2661
2662 ALOGV("ether type 0x%04x\n", ether_type);
2663 ALOGV("ip packet length : %u\nIP Packet:", ip_packet_len);
2664 hexdump(ip_packet, ip_packet_len);
2665 ALOGV("Src Mac Address: " MAC_ADDR_STR "\nDst Mac Address: " MAC_ADDR_STR
2666 "\nPeriod in msec : %u", MAC_ADDR_ARRAY(src_mac_addr),
2667 MAC_ADDR_ARRAY(dst_mac_addr), period_msec);
2668
2669 /* Add the vendor specific attributes for the NL command. */
2670 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2671 if (!nlData){
2672 ret = WIFI_ERROR_UNKNOWN;
2673 goto cleanup;
2674 }
2675
2676 ret = vCommand->put_u32(
2677 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL,
2678 QCA_WLAN_OFFLOADED_PACKETS_SENDING_START);
2679 if (ret != WIFI_SUCCESS)
2680 goto cleanup;
2681
2682 ret = vCommand->put_u32(
2683 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID,
2684 id);
2685 if (ret != WIFI_SUCCESS)
2686 goto cleanup;
2687
2688 ret = vCommand->put_u16(
2689 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_ETHER_PROTO_TYPE,
2690 ether_type);
2691 if (ret != WIFI_SUCCESS)
2692 goto cleanup;
2693
2694 ret = vCommand->put_bytes(
2695 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA,
2696 (const char *)ip_packet, ip_packet_len);
2697 if (ret != WIFI_SUCCESS)
2698 goto cleanup;
2699
2700 ret = vCommand->put_addr(
2701 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR,
2702 src_mac_addr);
2703 if (ret != WIFI_SUCCESS)
2704 goto cleanup;
2705
2706 ret = vCommand->put_addr(
2707 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR,
2708 dst_mac_addr);
2709 if (ret != WIFI_SUCCESS)
2710 goto cleanup;
2711
2712 ret = vCommand->put_u32(
2713 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD,
2714 period_msec);
2715 if (ret != WIFI_SUCCESS)
2716 goto cleanup;
2717
2718 vCommand->attr_end(nlData);
2719
2720 ret = vCommand->requestResponse();
2721 if (ret != WIFI_SUCCESS)
2722 goto cleanup;
2723
2724 cleanup:
2725 delete vCommand;
2726 return ret;
2727 }
2728
wifi_stop_sending_offloaded_packet(wifi_request_id id,wifi_interface_handle iface)2729 wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id id,
2730 wifi_interface_handle iface)
2731 {
2732 wifi_error ret;
2733 struct nlattr *nlData;
2734 WifiVendorCommand *vCommand = NULL;
2735
2736 ret = initialize_vendor_cmd(iface, id,
2737 QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS,
2738 &vCommand);
2739 if (ret != WIFI_SUCCESS) {
2740 ALOGE("%s: Initialization failed", __func__);
2741 return ret;
2742 }
2743
2744 /* Add the vendor specific attributes for the NL command. */
2745 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2746 if (!nlData){
2747 ret = WIFI_ERROR_UNKNOWN;
2748 goto cleanup;
2749 }
2750
2751 ret = vCommand->put_u32(
2752 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL,
2753 QCA_WLAN_OFFLOADED_PACKETS_SENDING_STOP);
2754 if (ret != WIFI_SUCCESS)
2755 goto cleanup;
2756
2757 ret = vCommand->put_u32(
2758 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID,
2759 id);
2760 if (ret != WIFI_SUCCESS)
2761 goto cleanup;
2762
2763 vCommand->attr_end(nlData);
2764
2765 ret = vCommand->requestResponse();
2766 if (ret != WIFI_SUCCESS)
2767 goto cleanup;
2768
2769 cleanup:
2770 delete vCommand;
2771 return ret;
2772 }
2773
2774 #define PACKET_FILTER_ID 0
2775
wifi_set_packet_filter(wifi_interface_handle iface,const u8 * program,u32 len)2776 static wifi_error wifi_set_packet_filter(wifi_interface_handle iface,
2777 const u8 *program, u32 len)
2778 {
2779 wifi_error ret;
2780 struct nlattr *nlData;
2781 WifiVendorCommand *vCommand = NULL;
2782 u32 current_offset = 0;
2783 wifi_handle wifiHandle = getWifiHandle(iface);
2784 hal_info *info = getHalInfo(wifiHandle);
2785
2786 /* len=0 clears the filters in driver/firmware */
2787 if (len != 0 && program == NULL) {
2788 ALOGE("%s: No valid program provided. Exit.",
2789 __func__);
2790 return WIFI_ERROR_INVALID_ARGS;
2791 }
2792
2793 do {
2794 ret = initialize_vendor_cmd(iface, get_requestid(),
2795 QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER,
2796 &vCommand);
2797 if (ret != WIFI_SUCCESS) {
2798 ALOGE("%s: Initialization failed", __FUNCTION__);
2799 return ret;
2800 }
2801
2802 /* Add the vendor specific attributes for the NL command. */
2803 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2804 if (!nlData){
2805 ret = WIFI_ERROR_UNKNOWN;
2806 goto cleanup;
2807 }
2808
2809 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
2810 QCA_WLAN_SET_PACKET_FILTER);
2811 if (ret != WIFI_SUCCESS)
2812 goto cleanup;
2813 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID,
2814 PACKET_FILTER_ID);
2815 if (ret != WIFI_SUCCESS)
2816 goto cleanup;
2817 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE,
2818 len);
2819 if (ret != WIFI_SUCCESS)
2820 goto cleanup;
2821 ret = vCommand->put_u32(
2822 QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET,
2823 current_offset);
2824 if (ret != WIFI_SUCCESS)
2825 goto cleanup;
2826
2827 if (len) {
2828 ret = vCommand->put_bytes(
2829 QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM,
2830 (char *)&program[current_offset],
2831 min(info->firmware_bus_max_size,
2832 len-current_offset));
2833 if (ret!= WIFI_SUCCESS) {
2834 ALOGE("%s: failed to put program", __FUNCTION__);
2835 goto cleanup;
2836 }
2837 }
2838
2839 vCommand->attr_end(nlData);
2840
2841 ret = vCommand->requestResponse();
2842 if (ret != WIFI_SUCCESS) {
2843 ALOGE("%s: requestResponse Error:%d",__func__, ret);
2844 goto cleanup;
2845 }
2846
2847 /* destroy the object after sending each fragment to driver */
2848 delete vCommand;
2849 vCommand = NULL;
2850
2851 current_offset += min(info->firmware_bus_max_size, len);
2852 } while (current_offset < len);
2853
2854 info->apf_enabled = !!len;
2855
2856 cleanup:
2857 if (vCommand)
2858 delete vCommand;
2859 return ret;
2860 }
2861
wifi_get_packet_filter_capabilities(wifi_interface_handle handle,u32 * version,u32 * max_len)2862 static wifi_error wifi_get_packet_filter_capabilities(
2863 wifi_interface_handle handle, u32 *version, u32 *max_len)
2864 {
2865 wifi_error ret;
2866 struct nlattr *nlData;
2867 WifihalGeneric *vCommand = NULL;
2868 interface_info *ifaceInfo = getIfaceInfo(handle);
2869 wifi_handle wifiHandle = getWifiHandle(handle);
2870
2871 if (version == NULL || max_len == NULL) {
2872 ALOGE("%s: NULL version/max_len pointer provided. Exit.",
2873 __FUNCTION__);
2874 return WIFI_ERROR_INVALID_ARGS;
2875 }
2876
2877 vCommand = new WifihalGeneric(wifiHandle, 0,
2878 OUI_QCA,
2879 QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER);
2880 if (vCommand == NULL) {
2881 ALOGE("%s: Error vCommand NULL", __FUNCTION__);
2882 return WIFI_ERROR_OUT_OF_MEMORY;
2883 }
2884
2885 /* Create the message */
2886 ret = vCommand->create();
2887 if (ret != WIFI_SUCCESS)
2888 goto cleanup;
2889
2890 ret = vCommand->set_iface_id(ifaceInfo->name);
2891 if (ret != WIFI_SUCCESS)
2892 goto cleanup;
2893
2894 /* Add the vendor specific attributes for the NL command. */
2895 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2896 if (!nlData){
2897 ret = WIFI_ERROR_UNKNOWN;
2898 goto cleanup;
2899 }
2900
2901 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
2902 QCA_WLAN_GET_PACKET_FILTER);
2903 if (ret != WIFI_SUCCESS)
2904 goto cleanup;
2905
2906 vCommand->attr_end(nlData);
2907
2908 ret = vCommand->requestResponse();
2909 if (ret != WIFI_SUCCESS) {
2910 ALOGE("%s: requestResponse() error: %d", __FUNCTION__, ret);
2911 if (ret == WIFI_ERROR_NOT_SUPPORTED) {
2912 /* Packet filtering is not supported currently, so return version
2913 * and length as 0
2914 */
2915 ALOGI("Packet filtering is not supprted");
2916 *version = 0;
2917 *max_len = 0;
2918 ret = WIFI_SUCCESS;
2919 }
2920 goto cleanup;
2921 }
2922
2923 *version = vCommand->getFilterVersion();
2924 *max_len = vCommand->getFilterLength();
2925 cleanup:
2926 delete vCommand;
2927 return ret;
2928 }
2929
2930
wifi_configure_nd_offload(wifi_interface_handle iface,u8 enable)2931 static wifi_error wifi_configure_nd_offload(wifi_interface_handle iface,
2932 u8 enable)
2933 {
2934 wifi_error ret;
2935 struct nlattr *nlData;
2936 WifiVendorCommand *vCommand = NULL;
2937
2938 ret = initialize_vendor_cmd(iface, get_requestid(),
2939 QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD,
2940 &vCommand);
2941 if (ret != WIFI_SUCCESS) {
2942 ALOGE("%s: Initialization failed", __func__);
2943 return ret;
2944 }
2945
2946 ALOGV("ND offload : %s", enable?"Enable":"Disable");
2947
2948 /* Add the vendor specific attributes for the NL command. */
2949 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
2950 if (!nlData){
2951 ret = WIFI_ERROR_UNKNOWN;
2952 goto cleanup;
2953 }
2954
2955 ret = vCommand->put_u8(QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG, enable);
2956 if (ret != WIFI_SUCCESS)
2957 goto cleanup;
2958
2959 vCommand->attr_end(nlData);
2960
2961 ret = vCommand->requestResponse();
2962
2963 cleanup:
2964 delete vCommand;
2965 return ret;
2966 }
2967
2968 /**
2969 * Copy 'len' bytes of raw data from host memory at source address 'program'
2970 * to APF (Android Packet Filter) working memory starting at offset 'dst_offset'.
2971 * The size of the program lenght passed to the interpreter is set to
2972 * 'progaram_lenght'
2973 *
2974 * The implementation is allowed to tranlate this wrtie into a series of smaller
2975 * writes,but this function is not allowed to return untill all write operations
2976 * have been completed
2977 * additionally visible memory not targeted by this function must remain
2978 * unchanged
2979
2980 * @param dst_offset write offset in bytes relative to the beginning of the APF
2981 * working memory with logical address 0X000. Must be a multiple of 4
2982 *
2983 * @param program host memory to copy bytes from. Must be 4B aligned
2984 *
2985 * @param len the number of bytes to copy from the bost into the APF working
2986 * memory
2987 *
2988 * @param program_length new length of the program instructions in bytes to pass
2989 * to the interpreter
2990 */
2991
wifi_write_packet_filter(wifi_interface_handle iface,u32 dst_offset,const u8 * program,u32 len,u32 program_length)2992 wifi_error wifi_write_packet_filter(wifi_interface_handle iface,
2993 u32 dst_offset, const u8 *program,
2994 u32 len, u32 program_length)
2995 {
2996 wifi_error ret;
2997 struct nlattr *nlData;
2998 WifiVendorCommand *vCommand = NULL;
2999 u32 current_offset = 0;
3000 wifi_handle wifiHandle = getWifiHandle(iface);
3001 hal_info *info = getHalInfo(wifiHandle);
3002
3003 /* len=0 clears the filters in driver/firmware */
3004 if (len != 0 && program == NULL) {
3005 ALOGE("%s: No valid program provided. Exit.",
3006 __func__);
3007 return WIFI_ERROR_INVALID_ARGS;
3008 }
3009
3010 do {
3011 ret = initialize_vendor_cmd(iface, get_requestid(),
3012 QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER,
3013 &vCommand);
3014 if (ret != WIFI_SUCCESS) {
3015 ALOGE("%s: Initialization failed", __FUNCTION__);
3016 return ret;
3017 }
3018
3019 /* Add the vendor specific attributes for the NL command. */
3020 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
3021 if (!nlData){
3022 ret = WIFI_ERROR_UNKNOWN;
3023 goto cleanup;
3024 }
3025
3026 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
3027 QCA_WLAN_WRITE_PACKET_FILTER);
3028 if (ret != WIFI_SUCCESS)
3029 goto cleanup;
3030 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID,
3031 PACKET_FILTER_ID);
3032 if (ret != WIFI_SUCCESS)
3033 goto cleanup;
3034 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE,
3035 len);
3036 if (ret != WIFI_SUCCESS)
3037 goto cleanup;
3038 ret = vCommand->put_u32(
3039 QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET,
3040 dst_offset + current_offset);
3041 if (ret != WIFI_SUCCESS)
3042 goto cleanup;
3043 ret = vCommand->put_u32(
3044 QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH,
3045 program_length);
3046 if (ret != WIFI_SUCCESS)
3047 goto cleanup;
3048
3049 ret = vCommand->put_bytes(
3050 QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM,
3051 (char *)&program[current_offset],
3052 min(info->firmware_bus_max_size,
3053 len - current_offset));
3054 if (ret!= WIFI_SUCCESS) {
3055 ALOGE("%s: failed to put program", __FUNCTION__);
3056 goto cleanup;
3057 }
3058
3059 vCommand->attr_end(nlData);
3060
3061 ret = vCommand->requestResponse();
3062 if (ret != WIFI_SUCCESS) {
3063 ALOGE("%s: requestResponse Error:%d",__func__, ret);
3064 goto cleanup;
3065 }
3066
3067 /* destroy the object after sending each fragment to driver */
3068 delete vCommand;
3069 vCommand = NULL;
3070
3071 current_offset += min(info->firmware_bus_max_size,
3072 len - current_offset);
3073 } while (current_offset < len);
3074
3075 cleanup:
3076 if (vCommand)
3077 delete vCommand;
3078 return ret;
3079 }
3080
wifi_enable_packet_filter(wifi_interface_handle handle,u32 enable)3081 wifi_error wifi_enable_packet_filter(wifi_interface_handle handle,
3082 u32 enable)
3083 {
3084 wifi_error ret;
3085 struct nlattr *nlData;
3086 WifiVendorCommand *vCommand = NULL;
3087 u32 subcmd;
3088 wifi_handle wifiHandle = getWifiHandle(handle);
3089 hal_info *info = getHalInfo(wifiHandle);
3090
3091 ret = initialize_vendor_cmd(handle, get_requestid(),
3092 QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER,
3093 &vCommand);
3094
3095 if (ret != WIFI_SUCCESS) {
3096 ALOGE("%s: Initialization failed", __func__);
3097 return ret;
3098 }
3099 /* Add the vendor specific attributes for the NL command. */
3100 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
3101 if (!nlData){
3102 ret = WIFI_ERROR_UNKNOWN;
3103 goto cleanup;
3104 }
3105
3106 subcmd = enable ? QCA_WLAN_ENABLE_PACKET_FILTER :
3107 QCA_WLAN_DISABLE_PACKET_FILTER;
3108 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
3109 subcmd);
3110 if (ret != WIFI_SUCCESS)
3111 goto cleanup;
3112
3113 vCommand->attr_end(nlData);
3114 ret = vCommand->requestResponse();
3115
3116 if (ret != WIFI_SUCCESS) {
3117 ALOGE("%s: requestResponse() error: %d", __FUNCTION__, ret);
3118 goto cleanup;
3119 }
3120
3121 info->apf_enabled = !!enable;
3122
3123 cleanup:
3124 delete vCommand;
3125 return ret;
3126
3127 }
3128
3129 /**
3130 * Copy 'length' bytes of raw data from APF (Android Packet Filter) working
3131 * memory to host memory starting at offset src_offset into host memory
3132 * pointed to by host_dst.
3133 * Memory can be text, data or some combination of the two. The implementiion is
3134 * allowed to translate this read into a series of smaller reads, but this
3135 * function is not allowed to return untill all the reads operations
3136 * into host_dst have been completed.
3137 *
3138 * @param src_offset offset in bytes of destination memory within APF working
3139 * memory
3140 *
3141 * @param host_dst host memory to copy into. Must be 4B aligned.
3142 *
3143 * @param length the number of bytes to copy from the APF working memory to the
3144 * host.
3145 */
3146
wifi_read_packet_filter(wifi_interface_handle handle,u32 src_offset,u8 * host_dst,u32 length)3147 static wifi_error wifi_read_packet_filter(wifi_interface_handle handle,
3148 u32 src_offset, u8 *host_dst, u32 length)
3149 {
3150 wifi_error ret = WIFI_ERROR_UNKNOWN;
3151 struct nlattr *nlData;
3152 WifihalGeneric *vCommand = NULL;
3153 interface_info *ifaceInfo = getIfaceInfo(handle);
3154 wifi_handle wifiHandle = getWifiHandle(handle);
3155 hal_info *info = getHalInfo(wifiHandle);
3156
3157 /* Length to be passed to this function should be non-zero
3158 * Return invalid argument if length is passed as zero
3159 */
3160 if (length == 0)
3161 return WIFI_ERROR_INVALID_ARGS;
3162
3163 /*Temporary varibles to support the read complete length in chunks */
3164 u8 *temp_host_dst;
3165 u32 remainingLengthToBeRead, currentLength;
3166 u8 apf_locally_disabled = 0;
3167
3168 /*Initializing the temporary variables*/
3169 temp_host_dst = host_dst;
3170 remainingLengthToBeRead = length;
3171
3172 if (info->apf_enabled) {
3173 /* Disable APF only when not disabled by framework before calling
3174 * wifi_read_packet_filter()
3175 */
3176 ret = wifi_enable_packet_filter(handle, 0);
3177 if (ret != WIFI_SUCCESS) {
3178 ALOGE("%s: Failed to disable APF", __FUNCTION__);
3179 return ret;
3180 }
3181 apf_locally_disabled = 1;
3182 }
3183 /**
3184 * Read the complete length in chunks of size less or equal to firmware bus
3185 * max size
3186 */
3187 while (remainingLengthToBeRead)
3188 {
3189 vCommand = new WifihalGeneric(wifiHandle, 0, OUI_QCA,
3190 QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER);
3191
3192 if (vCommand == NULL) {
3193 ALOGE("%s: Error vCommand NULL", __FUNCTION__);
3194 ret = WIFI_ERROR_OUT_OF_MEMORY;
3195 break;
3196 }
3197
3198 /* Create the message */
3199 ret = vCommand->create();
3200 if (ret != WIFI_SUCCESS)
3201 break;
3202 ret = vCommand->set_iface_id(ifaceInfo->name);
3203 if (ret != WIFI_SUCCESS)
3204 break;
3205 /* Add the vendor specific attributes for the NL command. */
3206 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
3207 if (!nlData)
3208 break;
3209 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
3210 QCA_WLAN_READ_PACKET_FILTER);
3211 if (ret != WIFI_SUCCESS)
3212 break;
3213
3214 currentLength = min(remainingLengthToBeRead, info->firmware_bus_max_size);
3215
3216 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE,
3217 currentLength);
3218 if (ret != WIFI_SUCCESS)
3219 break;
3220 ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET,
3221 src_offset);
3222 if (ret != WIFI_SUCCESS)
3223 break;
3224
3225 vCommand->setPacketBufferParams(temp_host_dst, currentLength);
3226 vCommand->attr_end(nlData);
3227 ret = vCommand->requestResponse();
3228
3229 if (ret != WIFI_SUCCESS) {
3230 ALOGE("%s: requestResponse() error: %d current_len = %u, src_offset = %u",
3231 __FUNCTION__, ret, currentLength, src_offset);
3232 break;
3233 }
3234
3235 remainingLengthToBeRead -= currentLength;
3236 temp_host_dst += currentLength;
3237 src_offset += currentLength;
3238 delete vCommand;
3239 vCommand = NULL;
3240 }
3241
3242 /* Re enable APF only when disabled above within this API */
3243 if (apf_locally_disabled) {
3244 wifi_error status;
3245 status = wifi_enable_packet_filter(handle, 1);
3246 if (status != WIFI_SUCCESS)
3247 ALOGE("%s: Failed to enable APF", __FUNCTION__);
3248 /* Prefer to return read status if read fails */
3249 if (ret == WIFI_SUCCESS)
3250 ret = status;
3251 }
3252
3253 delete vCommand;
3254 return ret;
3255 }
3256
3257 class GetSupportedVendorCmd : public WifiCommand
3258 {
3259 private:
3260 u32 mVendorCmds[256];
3261 int mNumOfVendorCmds;
3262
3263 public:
GetSupportedVendorCmd(wifi_handle handle)3264 GetSupportedVendorCmd(wifi_handle handle) : WifiCommand(handle, 0)
3265 {
3266 mNumOfVendorCmds = 0;
3267 memset(mVendorCmds, 0, 256);
3268 }
3269
create()3270 virtual wifi_error create() {
3271 int nl80211_id = genl_ctrl_resolve(mInfo->cmd_sock, "nl80211");
3272 wifi_error ret = mMsg.create(nl80211_id, NL80211_CMD_GET_WIPHY, NLM_F_DUMP, 0);
3273 mMsg.put_flag(NL80211_ATTR_SPLIT_WIPHY_DUMP);
3274
3275 return ret;
3276 }
3277
requestResponse()3278 virtual wifi_error requestResponse() {
3279 return WifiCommand::requestResponse(mMsg);
3280 }
set_iface_id(const char * name)3281 virtual wifi_error set_iface_id(const char* name) {
3282 unsigned ifindex = if_nametoindex(name);
3283 return mMsg.set_iface_id(ifindex);
3284 }
3285
handleResponse(WifiEvent & reply)3286 virtual int handleResponse(WifiEvent& reply) {
3287 struct nlattr **tb = reply.attributes();
3288
3289 if (tb[NL80211_ATTR_VENDOR_DATA]) {
3290 struct nlattr *nl;
3291 int rem, i = 0;
3292
3293 for_each_attr(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
3294 struct nl80211_vendor_cmd_info *vinfo;
3295 if (nla_len(nl) != sizeof(*vinfo)) {
3296 ALOGE("Unexpected vendor data info found in attribute");
3297 continue;
3298 }
3299 vinfo = (struct nl80211_vendor_cmd_info *)nla_data(nl);
3300 if (vinfo->vendor_id == OUI_QCA) {
3301 mVendorCmds[i] = vinfo->subcmd;
3302 i++;
3303 }
3304 }
3305 mNumOfVendorCmds = i;
3306 }
3307 return NL_SKIP;
3308 }
3309
isVendorCmdSupported(u32 cmdId)3310 int isVendorCmdSupported(u32 cmdId) {
3311 int i, ret;
3312
3313 ret = 0;
3314 for (i = 0; i < mNumOfVendorCmds; i++) {
3315 if (cmdId == mVendorCmds[i]) {
3316 ret = 1;
3317 break;
3318 }
3319 }
3320
3321 return ret;
3322 }
3323 };
3324
wifi_is_nan_ext_cmd_supported(wifi_interface_handle iface_handle)3325 static int wifi_is_nan_ext_cmd_supported(wifi_interface_handle iface_handle)
3326 {
3327 wifi_error ret;
3328 wifi_handle handle = getWifiHandle(iface_handle);
3329 interface_info *info = getIfaceInfo(iface_handle);
3330 GetSupportedVendorCmd cmd(handle);
3331
3332 ret = cmd.create();
3333 if (ret != WIFI_SUCCESS) {
3334 ALOGE("%s: create command failed", __func__);
3335 return 0;
3336 }
3337
3338 ret = cmd.set_iface_id(info->name);
3339 if (ret != WIFI_SUCCESS) {
3340 ALOGE("%s: set iface id failed", __func__);
3341 return 0;
3342 }
3343
3344 ret = cmd.requestResponse();
3345 if (ret != WIFI_SUCCESS) {
3346 ALOGE("Failed to query nan_ext command support, ret=%d", ret);
3347 return 0;
3348 } else {
3349 return cmd.isVendorCmdSupported(QCA_NL80211_VENDOR_SUBCMD_NAN_EXT);
3350 }
3351 }
3352
wifi_get_radar_history(wifi_interface_handle handle,radar_history_result * resultBuf,int resultBufSize,int * numResults)3353 wifi_error wifi_get_radar_history(wifi_interface_handle handle,
3354 radar_history_result *resultBuf, int resultBufSize, int *numResults)
3355 {
3356 wifi_error ret;
3357 struct nlattr *nlData;
3358 WifihalGeneric *vCommand = NULL;
3359 interface_info *ifaceInfo = NULL;
3360 wifi_handle wifiHandle = NULL;
3361
3362 ALOGI("%s: enter", __FUNCTION__);
3363
3364 if (!handle) {
3365 ALOGE("%s: Error, wifi_interface_handle NULL", __FUNCTION__);
3366 return WIFI_ERROR_UNKNOWN;
3367 }
3368
3369 ifaceInfo = getIfaceInfo(handle);
3370 if (!ifaceInfo) {
3371 ALOGE("%s: Error, interface_info NULL", __FUNCTION__);
3372 return WIFI_ERROR_UNKNOWN;
3373 }
3374
3375 wifiHandle = getWifiHandle(handle);
3376 if (!wifiHandle) {
3377 ALOGE("%s: Error, wifi_handle NULL", __FUNCTION__);
3378 return WIFI_ERROR_UNKNOWN;
3379 }
3380
3381 if (resultBuf == NULL || numResults == NULL) {
3382 ALOGE("%s: Error, resultsBuf/numResults NULL pointer", __FUNCTION__);
3383 return WIFI_ERROR_INVALID_ARGS;
3384 }
3385
3386 vCommand = new WifihalGeneric(wifiHandle, 0,
3387 OUI_QCA,
3388 QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY);
3389 if (vCommand == NULL) {
3390 ALOGE("%s: Error vCommand NULL", __FUNCTION__);
3391 return WIFI_ERROR_OUT_OF_MEMORY;
3392 }
3393
3394 /* Create the message */
3395 ret = vCommand->create();
3396 if (ret != WIFI_SUCCESS)
3397 goto cleanup;
3398
3399 ret = vCommand->set_iface_id(ifaceInfo->name);
3400 if (ret != WIFI_SUCCESS)
3401 goto cleanup;
3402
3403 /* Add the vendor specific attributes for the NL command. */
3404 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
3405 if (!nlData){
3406 ret = WIFI_ERROR_UNKNOWN;
3407 goto cleanup;
3408 }
3409
3410 vCommand->attr_end(nlData);
3411
3412 ret = vCommand->requestResponse();
3413 if (ret != WIFI_SUCCESS) {
3414 ALOGE("%s: requestResponse() error: %d", __FUNCTION__, ret);
3415 goto cleanup;
3416 }
3417
3418 /* No more data, copy the parsed results into the caller's results buffer */
3419 ret = vCommand->copyCachedRadarHistory(
3420 resultBuf, resultBufSize, numResults);
3421
3422 cleanup:
3423 vCommand->freeCachedRadarHistory();
3424 delete vCommand;
3425 return ret;
3426 }
3427
3428 #define SIZEOF_TLV_HDR 4
3429 #define OEM_DATA_TLV_TYPE_HEADER 1
3430 #define OEM_DATA_CMD_SET_SKIP_CAC 18
3431
3432 struct oem_data_header {
3433 u16 cmd_id;
3434 u16 request_idx;
3435 };
3436
wifi_add_oem_data_head(int cmd_id,u8 * oem_buf,size_t max)3437 static int wifi_add_oem_data_head(int cmd_id, u8* oem_buf, size_t max)
3438 {
3439 struct oem_data_header oem_hdr;
3440 oem_hdr.cmd_id = cmd_id;
3441 oem_hdr.request_idx = 0;
3442
3443 if ((SIZEOF_TLV_HDR + sizeof(oem_hdr)) > max) {
3444 return 0;
3445 }
3446
3447 wifi_put_le16(oem_buf, OEM_DATA_TLV_TYPE_HEADER);
3448 oem_buf += 2;
3449 wifi_put_le16(oem_buf, sizeof(oem_hdr));
3450 oem_buf += 2;
3451 memcpy(oem_buf, (u8 *)&oem_hdr, sizeof(oem_hdr));
3452 oem_buf += sizeof(oem_hdr);
3453
3454 return (SIZEOF_TLV_HDR + sizeof(oem_hdr));
3455 }
3456
3457
3458 /**
3459 * This cmd takes effect on the interface the cmd is sent to.
3460 * This cmd loses effect when interface is down. (i.e. set mac addr)
3461 */
wifi_disable_next_cac(wifi_interface_handle handle)3462 wifi_error wifi_disable_next_cac(wifi_interface_handle handle) {
3463 wifi_error ret;
3464 interface_info *ifaceInfo = NULL;
3465 struct nlattr *nlData;
3466 WifiVendorCommand *vCommand = NULL;
3467 u8 oem_buf[16];
3468 int oem_buf_len = 0;
3469
3470 if (!handle) {
3471 ALOGE("%s: Error, wifi_interface_handle NULL", __FUNCTION__);
3472 return WIFI_ERROR_UNKNOWN;
3473 }
3474
3475 ifaceInfo = getIfaceInfo(handle);
3476 if (!ifaceInfo) {
3477 ALOGE("%s: Error, interface_info NULL", __FUNCTION__);
3478 return WIFI_ERROR_UNKNOWN;
3479 }
3480
3481 ALOGI("%s: enter - iface=%s", __FUNCTION__, ifaceInfo->name);
3482 oem_buf_len = wifi_add_oem_data_head(
3483 OEM_DATA_CMD_SET_SKIP_CAC, oem_buf, sizeof(oem_buf));
3484 if (oem_buf_len <= 0) {
3485 ALOGE("%s: fill oem data head failed, cmd=%d", __func__,
3486 OEM_DATA_CMD_SET_SKIP_CAC);
3487 return WIFI_ERROR_UNKNOWN;
3488 }
3489
3490 ret = initialize_vendor_cmd(handle, get_requestid(),
3491 QCA_NL80211_VENDOR_SUBCMD_OEM_DATA,
3492 &vCommand);
3493
3494 if (ret != WIFI_SUCCESS) {
3495 ALOGE("%s: Initialization failed", __func__);
3496 return ret;
3497 }
3498
3499 /* Add the vendor specific attributes for the NL command. */
3500 nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
3501 if (!nlData) {
3502 ret = WIFI_ERROR_OUT_OF_MEMORY;
3503 goto cleanup;
3504 }
3505
3506 ret = vCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA,
3507 (char *)oem_buf, oem_buf_len);
3508 if (ret != WIFI_SUCCESS)
3509 goto cleanup;
3510
3511 vCommand->attr_end(nlData);
3512 ret = vCommand->requestResponse();
3513
3514 if (ret != WIFI_SUCCESS) {
3515 ALOGE("%s: requestResponse() error: %d", __FUNCTION__, ret);
3516 goto cleanup;
3517 }
3518
3519 cleanup:
3520 delete vCommand;
3521 return ret;
3522 }
3523