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
17#include <stdint.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <sys/socket.h>
21#include <netlink/genl/genl.h>
22#include <netlink/genl/family.h>
23#include <netlink/genl/ctrl.h>
24#include <linux/rtnetlink.h>
25#include <netpacket/packet.h>
26#include <linux/filter.h>
27#include <linux/errqueue.h>
28
29#include <linux/pkt_sched.h>
30#include <netlink/object-api.h>
31#include <netlink/netlink.h>
32#include <netlink/socket.h>
33#include <netlink-types.h>
34
35#include "nl80211_copy.h"
36
37#include <dirent.h>
38#include <net/if.h>
39#include <netinet/in.h>
40
41#include "sync.h"
42
43#define LOG_TAG  "WifiHAL"
44
45#include "hardware_legacy/wifi.h"
46
47#include "wifi_hal.h"
48#include "common.h"
49#include "cpp_bindings.h"
50#include "ifaceeventhandler.h"
51#include "wifiloggercmd.h"
52#include "vendor_definitions.h"
53
54/*
55 BUGBUG: normally, libnl allocates ports for all connections it makes; but
56 being a static library, it doesn't really know how many other netlink
57 connections are made by the same process, if connections come from different
58 shared libraries. These port assignments exist to solve that
59 problem - temporarily. We need to fix libnl to try and allocate ports across
60 the entire process.
61 */
62
63#define WIFI_HAL_CMD_SOCK_PORT       644
64#define WIFI_HAL_EVENT_SOCK_PORT     645
65
66static void internal_event_handler(wifi_handle handle, int events,
67                                   struct nl_sock *sock);
68static int internal_valid_message_handler(nl_msg *msg, void *arg);
69static int user_sock_message_handler(nl_msg *msg, void *arg);
70static int wifi_get_multicast_id(wifi_handle handle, const char *name,
71        const char *group);
72static int wifi_add_membership(wifi_handle handle, const char *group);
73static wifi_error wifi_init_interfaces(wifi_handle handle);
74static wifi_error wifi_set_packet_filter(wifi_interface_handle iface,
75                                         const u8 *program, u32 len);
76static wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
77                                              u32 *version, u32 *max_len);
78static wifi_error wifi_configure_nd_offload(wifi_interface_handle iface,
79                                            u8 enable);
80wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface,
81                             WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt);
82
83/* Initialize/Cleanup */
84
85wifi_interface_handle wifi_get_iface_handle(wifi_handle handle, char *name)
86{
87    hal_info *info = (hal_info *)handle;
88    for (int i=0;i<info->num_interfaces;i++)
89    {
90        if (!strcmp(info->interfaces[i]->name, name))
91        {
92            return ((wifi_interface_handle )(info->interfaces)[i]);
93        }
94    }
95    return NULL;
96}
97
98void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
99{
100    uint32_t pid = getpid() & 0x3FFFFF;
101
102    if (port == 0) {
103        sock->s_flags &= ~NL_OWN_PORT;
104    } else {
105        sock->s_flags |= NL_OWN_PORT;
106    }
107
108    sock->s_local.nl_pid = pid + (port << 22);
109}
110
111static nl_sock * wifi_create_nl_socket(int port, int protocol)
112{
113    // ALOGI("Creating socket");
114    struct nl_sock *sock = nl_socket_alloc();
115    if (sock == NULL) {
116        ALOGE("Failed to create NL socket");
117        return NULL;
118    }
119
120    wifi_socket_set_local_port(sock, port);
121
122    struct sockaddr_nl *addr_nl = &(sock->s_local);
123    /* ALOGI("socket address is %d:%d:%d:%d",
124       addr_nl->nl_family, addr_nl->nl_pad, addr_nl->nl_pid,
125       addr_nl->nl_groups); */
126
127    struct sockaddr *addr = NULL;
128    // ALOGI("sizeof(sockaddr) = %d, sizeof(sockaddr_nl) = %d", sizeof(*addr),
129    // sizeof(*addr_nl));
130
131    // ALOGI("Connecting socket");
132    if (nl_connect(sock, protocol)) {
133        ALOGE("Could not connect handle");
134        nl_socket_free(sock);
135        return NULL;
136    }
137
138    return sock;
139}
140
141int ack_handler(struct nl_msg *msg, void *arg)
142{
143    int *err = (int *)arg;
144    *err = 0;
145    return NL_STOP;
146}
147
148int finish_handler(struct nl_msg *msg, void *arg)
149{
150    int *ret = (int *)arg;
151    *ret = 0;
152    return NL_SKIP;
153}
154
155int error_handler(struct sockaddr_nl *nla,
156                  struct nlmsgerr *err, void *arg)
157{
158    int *ret = (int *)arg;
159    *ret = err->error;
160
161    ALOGV("%s invoked with error: %d", __func__, err->error);
162    return NL_SKIP;
163}
164static int no_seq_check(struct nl_msg *msg, void *arg)
165{
166    return NL_OK;
167}
168
169static wifi_error acquire_supported_features(wifi_interface_handle iface,
170        feature_set *set)
171{
172    int ret = 0;
173    interface_info *iinfo = getIfaceInfo(iface);
174    wifi_handle handle = getWifiHandle(iface);
175    *set = 0;
176
177    WifihalGeneric supportedFeatures(handle, 0,
178            OUI_QCA,
179            QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES);
180
181    /* create the message */
182    ret = supportedFeatures.create();
183    if (ret < 0)
184        goto cleanup;
185
186    ret = supportedFeatures.set_iface_id(iinfo->name);
187    if (ret < 0)
188        goto cleanup;
189
190    ret = supportedFeatures.requestResponse();
191    if (ret != 0) {
192        ALOGE("%s: requestResponse Error:%d",__func__, ret);
193        goto cleanup;
194    }
195
196    supportedFeatures.getResponseparams(set);
197
198cleanup:
199    return (wifi_error)ret;
200}
201
202static wifi_error get_firmware_bus_max_size_supported(
203                                                wifi_interface_handle iface)
204{
205    int ret = 0;
206    interface_info *iinfo = getIfaceInfo(iface);
207    wifi_handle handle = getWifiHandle(iface);
208    hal_info *info = (hal_info *)handle;
209
210    WifihalGeneric busSizeSupported(handle, 0,
211                                    OUI_QCA,
212                                    QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE);
213
214    /* create the message */
215    ret = busSizeSupported.create();
216    if (ret < 0)
217        goto cleanup;
218
219    ret = busSizeSupported.set_iface_id(iinfo->name);
220    if (ret < 0)
221        goto cleanup;
222
223    ret = busSizeSupported.requestResponse();
224    if (ret != 0) {
225        ALOGE("%s: requestResponse Error:%d", __FUNCTION__, ret);
226        goto cleanup;
227    }
228    info->firmware_bus_max_size = busSizeSupported.getBusSize();
229
230cleanup:
231    return (wifi_error)ret;
232}
233
234static wifi_error wifi_init_user_sock(hal_info *info)
235{
236    struct nl_sock *user_sock =
237        wifi_create_nl_socket(WIFI_HAL_USER_SOCK_PORT, NETLINK_USERSOCK);
238    if (user_sock == NULL) {
239        ALOGE("Could not create diag sock");
240        return WIFI_ERROR_UNKNOWN;
241    }
242
243    /* Set the socket buffer size */
244    if (nl_socket_set_buffer_size(user_sock, (256*1024), 0) < 0) {
245        ALOGE("Could not set size for user_sock: %s",
246                   strerror(errno));
247        /* continue anyway with the default (smaller) buffer */
248    }
249    else {
250        ALOGV("nl_socket_set_buffer_size successful for user_sock");
251    }
252
253    struct nl_cb *cb = nl_socket_get_cb(user_sock);
254    if (cb == NULL) {
255        ALOGE("Could not get cb");
256        return WIFI_ERROR_UNKNOWN;
257    }
258
259    info->user_sock_arg = 1;
260    nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
261    nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &info->user_sock_arg);
262    nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &info->user_sock_arg);
263    nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &info->user_sock_arg);
264
265    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, user_sock_message_handler, info);
266    nl_cb_put(cb);
267
268    int ret = nl_socket_add_membership(user_sock, 1);
269    if (ret < 0) {
270        ALOGE("Could not add membership");
271        return WIFI_ERROR_UNKNOWN;
272    }
273
274    info->user_sock = user_sock;
275    ALOGV("Initiialized diag sock successfully");
276    return WIFI_SUCCESS;
277}
278
279/*initialize function pointer table with Qualcomm HAL API*/
280wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn) {
281    if (fn == NULL) {
282        return WIFI_ERROR_UNKNOWN;
283    }
284
285    fn->wifi_initialize = wifi_initialize;
286    fn->wifi_cleanup = wifi_cleanup;
287    fn->wifi_event_loop = wifi_event_loop;
288    fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set;
289    fn->wifi_get_concurrency_matrix = wifi_get_concurrency_matrix;
290    fn->wifi_set_scanning_mac_oui =  wifi_set_scanning_mac_oui;
291    fn->wifi_get_ifaces = wifi_get_ifaces;
292    fn->wifi_get_iface_name = wifi_get_iface_name;
293    fn->wifi_set_iface_event_handler = wifi_set_iface_event_handler;
294    fn->wifi_reset_iface_event_handler = wifi_reset_iface_event_handler;
295    fn->wifi_start_gscan = wifi_start_gscan;
296    fn->wifi_stop_gscan = wifi_stop_gscan;
297    fn->wifi_get_cached_gscan_results = wifi_get_cached_gscan_results;
298    fn->wifi_set_bssid_hotlist = wifi_set_bssid_hotlist;
299    fn->wifi_reset_bssid_hotlist = wifi_reset_bssid_hotlist;
300    fn->wifi_set_significant_change_handler = wifi_set_significant_change_handler;
301    fn->wifi_reset_significant_change_handler = wifi_reset_significant_change_handler;
302    fn->wifi_get_gscan_capabilities = wifi_get_gscan_capabilities;
303    fn->wifi_set_link_stats = wifi_set_link_stats;
304    fn->wifi_get_link_stats = wifi_get_link_stats;
305    fn->wifi_clear_link_stats = wifi_clear_link_stats;
306    fn->wifi_get_valid_channels = wifi_get_valid_channels;
307    fn->wifi_rtt_range_request = wifi_rtt_range_request;
308    fn->wifi_rtt_range_cancel = wifi_rtt_range_cancel;
309    fn->wifi_get_rtt_capabilities = wifi_get_rtt_capabilities;
310    fn->wifi_rtt_get_responder_info = wifi_rtt_get_responder_info;
311    fn->wifi_enable_responder = wifi_enable_responder;
312    fn->wifi_disable_responder = wifi_disable_responder;
313    fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag;
314    fn->wifi_start_logging = wifi_start_logging;
315    fn->wifi_set_epno_list = wifi_set_epno_list;
316    fn->wifi_reset_epno_list = wifi_reset_epno_list;
317    fn->wifi_set_country_code = wifi_set_country_code;
318    fn->wifi_enable_tdls = wifi_enable_tdls;
319    fn->wifi_disable_tdls = wifi_disable_tdls;
320    fn->wifi_get_tdls_status = wifi_get_tdls_status;
321    fn->wifi_get_tdls_capabilities = wifi_get_tdls_capabilities;
322    fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump;
323    fn->wifi_set_log_handler = wifi_set_log_handler;
324    fn->wifi_reset_log_handler = wifi_reset_log_handler;
325    fn->wifi_set_alert_handler = wifi_set_alert_handler;
326    fn->wifi_reset_alert_handler = wifi_reset_alert_handler;
327    fn->wifi_get_firmware_version = wifi_get_firmware_version;
328    fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status;
329    fn->wifi_get_logger_supported_feature_set = wifi_get_logger_supported_feature_set;
330    fn->wifi_get_ring_data = wifi_get_ring_data;
331    fn->wifi_get_driver_version = wifi_get_driver_version;
332    fn->wifi_set_passpoint_list = wifi_set_passpoint_list;
333    fn->wifi_reset_passpoint_list = wifi_reset_passpoint_list;
334    fn->wifi_set_bssid_blacklist = wifi_set_bssid_blacklist;
335    fn->wifi_set_lci = wifi_set_lci;
336    fn->wifi_set_lcr = wifi_set_lcr;
337    fn->wifi_start_sending_offloaded_packet =
338            wifi_start_sending_offloaded_packet;
339    fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet;
340    fn->wifi_start_rssi_monitoring = wifi_start_rssi_monitoring;
341    fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring;
342    fn->wifi_nan_enable_request = nan_enable_request;
343    fn->wifi_nan_disable_request = nan_disable_request;
344    fn->wifi_nan_publish_request = nan_publish_request;
345    fn->wifi_nan_publish_cancel_request = nan_publish_cancel_request;
346    fn->wifi_nan_subscribe_request = nan_subscribe_request;
347    fn->wifi_nan_subscribe_cancel_request = nan_subscribe_cancel_request;
348    fn->wifi_nan_transmit_followup_request = nan_transmit_followup_request;
349    fn->wifi_nan_stats_request = nan_stats_request;
350    fn->wifi_nan_config_request = nan_config_request;
351    fn->wifi_nan_tca_request = nan_tca_request;
352    fn->wifi_nan_beacon_sdf_payload_request = nan_beacon_sdf_payload_request;
353    fn->wifi_nan_register_handler = nan_register_handler;
354    fn->wifi_nan_get_version = nan_get_version;
355    fn->wifi_set_packet_filter = wifi_set_packet_filter;
356    fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities;
357    fn->wifi_nan_get_capabilities = nan_get_capabilities;
358    fn->wifi_configure_nd_offload = wifi_configure_nd_offload;
359    fn->wifi_get_driver_memory_dump = wifi_get_driver_memory_dump;
360    fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;
361    fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring;
362    fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates;
363    fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates;
364
365    return WIFI_SUCCESS;
366}
367
368wifi_error wifi_initialize(wifi_handle *handle)
369{
370    int err = 0;
371    bool driver_loaded = false;
372    wifi_error ret = WIFI_SUCCESS;
373    wifi_interface_handle iface_handle;
374    struct nl_sock *cmd_sock = NULL;
375    struct nl_sock *event_sock = NULL;
376    struct nl_cb *cb = NULL;
377
378    ALOGI("Initializing wifi");
379    hal_info *info = (hal_info *)malloc(sizeof(hal_info));
380    if (info == NULL) {
381        ALOGE("Could not allocate hal_info");
382        return WIFI_ERROR_OUT_OF_MEMORY;
383    }
384
385    memset(info, 0, sizeof(*info));
386
387    cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT,
388                                                     NETLINK_GENERIC);
389    if (cmd_sock == NULL) {
390        ALOGE("Failed to create command socket port");
391        ret = WIFI_ERROR_UNKNOWN;
392        goto unload;
393    }
394
395    /* Set the socket buffer size */
396    if (nl_socket_set_buffer_size(cmd_sock, (256*1024), 0) < 0) {
397        ALOGE("Could not set nl_socket RX buffer size for cmd_sock: %s",
398                   strerror(errno));
399        /* continue anyway with the default (smaller) buffer */
400    }
401
402    event_sock =
403        wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT, NETLINK_GENERIC);
404    if (event_sock == NULL) {
405        ALOGE("Failed to create event socket port");
406        ret = WIFI_ERROR_UNKNOWN;
407        goto unload;
408    }
409
410    /* Set the socket buffer size */
411    if (nl_socket_set_buffer_size(event_sock, (256*1024), 0) < 0) {
412        ALOGE("Could not set nl_socket RX buffer size for event_sock: %s",
413                   strerror(errno));
414        /* continue anyway with the default (smaller) buffer */
415    }
416
417    cb = nl_socket_get_cb(event_sock);
418    if (cb == NULL) {
419        ALOGE("Failed to get NL control block for event socket port");
420        ret = WIFI_ERROR_UNKNOWN;
421        goto unload;
422    }
423
424    err = 1;
425    nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
426    nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
427    nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
428    nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
429
430    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler,
431            info);
432    nl_cb_put(cb);
433
434    info->cmd_sock = cmd_sock;
435    info->event_sock = event_sock;
436    info->clean_up = false;
437    info->in_event_loop = false;
438
439    info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE);
440    if (info->event_cb == NULL) {
441        ALOGE("Could not allocate event_cb");
442        ret = WIFI_ERROR_OUT_OF_MEMORY;
443        goto unload;
444    }
445    info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE;
446    info->num_event_cb = 0;
447
448    info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE);
449    if (info->cmd == NULL) {
450        ALOGE("Could not allocate cmd info");
451        ret = WIFI_ERROR_OUT_OF_MEMORY;
452        goto unload;
453    }
454    info->alloc_cmd = DEFAULT_CMD_SIZE;
455    info->num_cmd = 0;
456
457    info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211");
458    if (info->nl80211_family_id < 0) {
459        ALOGE("Could not resolve nl80211 familty id");
460        ret = WIFI_ERROR_UNKNOWN;
461        goto unload;
462    }
463
464    pthread_mutex_init(&info->cb_lock, NULL);
465    pthread_mutex_init(&info->pkt_fate_stats_lock, NULL);
466
467    *handle = (wifi_handle) info;
468
469    wifi_add_membership(*handle, "scan");
470    wifi_add_membership(*handle, "mlme");
471    wifi_add_membership(*handle, "regulatory");
472    wifi_add_membership(*handle, "vendor");
473
474    ret = wifi_init_user_sock(info);
475    if (ret != WIFI_SUCCESS) {
476        ALOGE("Failed to alloc user socket");
477        goto unload;
478    }
479
480    if (!is_wifi_driver_loaded()) {
481        ret = (wifi_error)wifi_load_driver();
482        if(ret != WIFI_SUCCESS) {
483            ALOGE("%s Failed to load wifi driver : %d\n", __func__, ret);
484            goto unload;
485        }
486        driver_loaded = true;
487    }
488
489    ret = wifi_init_interfaces(*handle);
490    if (ret != WIFI_SUCCESS) {
491        ALOGE("Failed to init interfaces");
492        goto unload;
493    }
494
495    if (info->num_interfaces == 0) {
496        ALOGE("No interfaces found");
497        ret = WIFI_ERROR_UNINITIALIZED;
498        goto unload;
499    }
500
501    iface_handle = wifi_get_iface_handle((info->interfaces[0])->handle,
502            (info->interfaces[0])->name);
503    if (iface_handle == NULL) {
504        int i;
505        for (i = 0; i < info->num_interfaces; i++)
506        {
507            free(info->interfaces[i]);
508        }
509        ALOGE("%s no iface with %s\n", __func__, info->interfaces[0]->name);
510        goto unload;
511    }
512
513    ret = acquire_supported_features(iface_handle,
514            &info->supported_feature_set);
515    if (ret != WIFI_SUCCESS) {
516        ALOGI("Failed to get supported feature set : %d", ret);
517        //acquire_supported_features failure is acceptable condition as legacy
518        //drivers might not support the required vendor command. So, do not
519        //consider it as failure of wifi_initialize
520        ret = WIFI_SUCCESS;
521    }
522
523    ret = get_firmware_bus_max_size_supported(iface_handle);
524    if (ret != WIFI_SUCCESS) {
525        ALOGE("Failed to get supported bus size, error : %d", ret);
526        info->firmware_bus_max_size = 1520;
527    }
528
529    ret = wifi_logger_ring_buffers_init(info);
530    if (ret != WIFI_SUCCESS) {
531        ALOGE("Wifi Logger Ring Initialization Failed");
532        goto unload;
533    }
534
535    info->pkt_stats = (struct pkt_stats_s *)malloc(sizeof(struct pkt_stats_s));
536    if (!info->pkt_stats) {
537        ALOGE("%s: malloc Failed for size: %zu",
538                __FUNCTION__, sizeof(struct pkt_stats_s));
539        ret = WIFI_ERROR_OUT_OF_MEMORY;
540        goto unload;
541    }
542
543    info->rx_buf_size_allocated = MAX_RXMPDUS_PER_AMPDU * MAX_MSDUS_PER_MPDU
544                                  * PKT_STATS_BUF_SIZE;
545
546    info->rx_aggr_pkts =
547        (wifi_ring_buffer_entry  *)malloc(info->rx_buf_size_allocated);
548    if (!info->rx_aggr_pkts) {
549        ALOGE("%s: malloc Failed for size: %d",
550                __FUNCTION__, info->rx_buf_size_allocated);
551        ret = WIFI_ERROR_OUT_OF_MEMORY;
552        info->rx_buf_size_allocated = 0;
553        goto unload;
554    }
555    memset(info->rx_aggr_pkts, 0, info->rx_buf_size_allocated);
556
557    info->exit_sockets[0] = -1;
558    info->exit_sockets[1] = -1;
559
560    if (socketpair(AF_UNIX, SOCK_STREAM, 0, info->exit_sockets) == -1) {
561        ALOGE("Failed to create exit socket pair");
562        ret = WIFI_ERROR_UNKNOWN;
563        goto unload;
564    }
565
566    ALOGV("Initializing Gscan Event Handlers");
567    ret = initializeGscanHandlers(info);
568    if (ret != WIFI_SUCCESS) {
569        ALOGE("Initializing Gscan Event Handlers Failed");
570        goto unload;
571    }
572
573    ALOGV("Initialized Wifi HAL Successfully; vendor cmd = %d Supported"
574            " features : %x", NL80211_CMD_VENDOR, info->supported_feature_set);
575
576unload:
577    if (ret != WIFI_SUCCESS) {
578        if (cmd_sock)
579            nl_socket_free(cmd_sock);
580        if (event_sock)
581            nl_socket_free(event_sock);
582        if (info) {
583            if (info->cmd) free(info->cmd);
584            if (info->event_cb) free(info->event_cb);
585            if (info->user_sock) nl_socket_free(info->user_sock);
586            if (info->pkt_stats) free(info->pkt_stats);
587            if (info->rx_aggr_pkts) free(info->rx_aggr_pkts);
588            cleanupGscanHandlers(info);
589            free(info);
590        }
591    }
592
593    if (driver_loaded)
594        wifi_unload_driver();
595    return ret;
596}
597
598static int wifi_add_membership(wifi_handle handle, const char *group)
599{
600    hal_info *info = getHalInfo(handle);
601
602    int id = wifi_get_multicast_id(handle, "nl80211", group);
603    if (id < 0) {
604        ALOGE("Could not find group %s", group);
605        return id;
606    }
607
608    int ret = nl_socket_add_membership(info->event_sock, id);
609    if (ret < 0) {
610        ALOGE("Could not add membership to group %s", group);
611    }
612
613    return ret;
614}
615
616static void internal_cleaned_up_handler(wifi_handle handle)
617{
618    hal_info *info = getHalInfo(handle);
619    wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler;
620
621    if (info->cmd_sock != 0) {
622        nl_socket_free(info->cmd_sock);
623        nl_socket_free(info->event_sock);
624        info->cmd_sock = NULL;
625        info->event_sock = NULL;
626    }
627
628    if (info->user_sock != 0) {
629        nl_socket_free(info->user_sock);
630        info->user_sock = NULL;
631    }
632
633    if (info->pkt_stats)
634        free(info->pkt_stats);
635    if (info->rx_aggr_pkts)
636        free(info->rx_aggr_pkts);
637    wifi_logger_ring_buffers_deinit(info);
638    cleanupGscanHandlers(info);
639
640    if (info->exit_sockets[0] >= 0) {
641        close(info->exit_sockets[0]);
642        info->exit_sockets[0] = -1;
643    }
644
645    if (info->exit_sockets[1] >= 0) {
646        close(info->exit_sockets[1]);
647        info->exit_sockets[1] = -1;
648    }
649
650    if (info->pkt_fate_stats) {
651        free(info->pkt_fate_stats);
652        info->pkt_fate_stats = NULL;
653    }
654
655    (*cleaned_up_handler)(handle);
656    pthread_mutex_destroy(&info->cb_lock);
657    pthread_mutex_destroy(&info->pkt_fate_stats_lock);
658    free(info);
659}
660
661void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
662{
663    if (!handle) {
664        ALOGE("Handle is null");
665        return;
666    }
667
668    hal_info *info = getHalInfo(handle);
669    info->cleaned_up_handler = handler;
670    info->clean_up = true;
671
672    TEMP_FAILURE_RETRY(write(info->exit_sockets[0], "E", 1));
673    ALOGI("Sent msg on exit sock to unblock poll()");
674}
675
676static int internal_pollin_handler(wifi_handle handle, struct nl_sock *sock)
677{
678    struct nl_cb *cb = nl_socket_get_cb(sock);
679
680    int res = nl_recvmsgs(sock, cb);
681    if(res)
682        ALOGE("Error :%d while reading nl msg", res);
683    nl_cb_put(cb);
684    return res;
685}
686
687static void internal_event_handler(wifi_handle handle, int events,
688                                   struct nl_sock *sock)
689{
690    if (events & POLLERR) {
691        ALOGE("Error reading from socket");
692        internal_pollin_handler(handle, sock);
693    } else if (events & POLLHUP) {
694        ALOGE("Remote side hung up");
695    } else if (events & POLLIN) {
696        //ALOGI("Found some events!!!");
697        internal_pollin_handler(handle, sock);
698    } else {
699        ALOGE("Unknown event - %0x", events);
700    }
701}
702
703/* Run event handler */
704void wifi_event_loop(wifi_handle handle)
705{
706    hal_info *info = getHalInfo(handle);
707    if (info->in_event_loop) {
708        return;
709    } else {
710        info->in_event_loop = true;
711    }
712
713    pollfd pfd[3];
714    memset(&pfd, 0, 3*sizeof(pfd[0]));
715
716    pfd[0].fd = nl_socket_get_fd(info->event_sock);
717    pfd[0].events = POLLIN;
718
719    pfd[1].fd = nl_socket_get_fd(info->user_sock);
720    pfd[1].events = POLLIN;
721
722    pfd[2].fd = info->exit_sockets[1];
723    pfd[2].events = POLLIN;
724
725    /* TODO: Add support for timeouts */
726
727    do {
728        int timeout = -1;                   /* Infinite timeout */
729        pfd[0].revents = 0;
730        pfd[1].revents = 0;
731        pfd[2].revents = 0;
732        //ALOGI("Polling sockets");
733        int result = poll(pfd, 3, -1);
734        if (result < 0) {
735            ALOGE("Error polling socket");
736        } else {
737            if (pfd[0].revents & (POLLIN | POLLHUP | POLLERR)) {
738                internal_event_handler(handle, pfd[0].revents, info->event_sock);
739            }
740            if (pfd[1].revents & (POLLIN | POLLHUP | POLLERR)) {
741                internal_event_handler(handle, pfd[1].revents, info->user_sock);
742            }
743        }
744        rb_timerhandler(info);
745    } while (!info->clean_up);
746    internal_cleaned_up_handler(handle);
747}
748
749static int user_sock_message_handler(nl_msg *msg, void *arg)
750{
751    wifi_handle handle = (wifi_handle)arg;
752    hal_info *info = getHalInfo(handle);
753
754    diag_message_handler(info, msg);
755
756    return NL_OK;
757}
758
759static int internal_valid_message_handler(nl_msg *msg, void *arg)
760{
761    wifi_handle handle = (wifi_handle)arg;
762    hal_info *info = getHalInfo(handle);
763
764    WifiEvent event(msg);
765    int res = event.parse();
766    if (res < 0) {
767        ALOGE("Failed to parse event: %d", res);
768        return NL_SKIP;
769    }
770
771    int cmd = event.get_cmd();
772    uint32_t vendor_id = 0;
773    int subcmd = 0;
774
775    if (cmd == NL80211_CMD_VENDOR) {
776        vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
777        subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
778        /* Restrict printing GSCAN_FULL_RESULT which is causing lot
779           of logs in bug report */
780        if (subcmd != QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT) {
781            ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
782                  event.get_cmdString(), vendor_id, subcmd);
783        }
784    } else {
785        ALOGV("event received %s", event.get_cmdString());
786    }
787
788    // event.log();
789
790    bool dispatched = false;
791
792    pthread_mutex_lock(&info->cb_lock);
793
794    for (int i = 0; i < info->num_event_cb; i++) {
795        if (cmd == info->event_cb[i].nl_cmd) {
796            if (cmd == NL80211_CMD_VENDOR
797                && ((vendor_id != info->event_cb[i].vendor_id)
798                || (subcmd != info->event_cb[i].vendor_subcmd)))
799            {
800                /* event for a different vendor, ignore it */
801                continue;
802            }
803
804            cb_info *cbi = &(info->event_cb[i]);
805            pthread_mutex_unlock(&info->cb_lock);
806            if (cbi->cb_func) {
807                (*(cbi->cb_func))(msg, cbi->cb_arg);
808                dispatched = true;
809            }
810            return NL_OK;
811        }
812    }
813
814#ifdef QC_HAL_DEBUG
815    if (!dispatched) {
816        ALOGI("event ignored!!");
817    }
818#endif
819
820    pthread_mutex_unlock(&info->cb_lock);
821    return NL_OK;
822}
823
824////////////////////////////////////////////////////////////////////////////////
825
826class GetMulticastIdCommand : public WifiCommand
827{
828private:
829    const char *mName;
830    const char *mGroup;
831    int   mId;
832public:
833    GetMulticastIdCommand(wifi_handle handle, const char *name,
834            const char *group) : WifiCommand(handle, 0)
835    {
836        mName = name;
837        mGroup = group;
838        mId = -1;
839    }
840
841    int getId() {
842        return mId;
843    }
844
845    virtual int create() {
846        int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
847        // ALOGI("ctrl family = %d", nlctrlFamily);
848        int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
849        if (ret < 0) {
850            return ret;
851        }
852        ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName);
853        return ret;
854    }
855
856    virtual int handleResponse(WifiEvent& reply) {
857
858        // ALOGI("handling reponse in %s", __func__);
859
860        struct nlattr **tb = reply.attributes();
861        struct genlmsghdr *gnlh = reply.header();
862        struct nlattr *mcgrp = NULL;
863        int i;
864
865        if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
866            ALOGI("No multicast groups found");
867            return NL_SKIP;
868        } else {
869            // ALOGI("Multicast groups attr size = %d",
870            // nla_len(tb[CTRL_ATTR_MCAST_GROUPS]));
871        }
872
873        for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
874
875            // ALOGI("Processing group");
876            struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
877            nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
878                nla_len(mcgrp), NULL);
879            if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID])
880            {
881                continue;
882            }
883
884            char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
885            int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
886
887            // ALOGI("Found group name %s", grpName);
888
889            if (strncmp(grpName, mGroup, grpNameLen) != 0)
890                continue;
891
892            mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
893            break;
894        }
895
896        return NL_SKIP;
897    }
898
899};
900
901static int wifi_get_multicast_id(wifi_handle handle, const char *name,
902        const char *group)
903{
904    GetMulticastIdCommand cmd(handle, name, group);
905    int res = cmd.requestResponse();
906    if (res < 0)
907        return res;
908    else
909        return cmd.getId();
910}
911
912/////////////////////////////////////////////////////////////////////////
913
914static bool is_wifi_interface(const char *name)
915{
916    if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) {
917        /* not a wifi interface; ignore it */
918        return false;
919    } else {
920        return true;
921    }
922}
923
924static int get_interface(const char *name, interface_info *info)
925{
926    strlcpy(info->name, name, (IFNAMSIZ + 1));
927    info->id = if_nametoindex(name);
928    // ALOGI("found an interface : %s, id = %d", name, info->id);
929    return WIFI_SUCCESS;
930}
931
932wifi_error wifi_init_interfaces(wifi_handle handle)
933{
934    hal_info *info = (hal_info *)handle;
935
936    struct dirent *de;
937
938    DIR *d = opendir("/sys/class/net");
939    if (d == 0)
940        return WIFI_ERROR_UNKNOWN;
941
942    int n = 0;
943    while ((de = readdir(d))) {
944        if (de->d_name[0] == '.')
945            continue;
946        if (is_wifi_interface(de->d_name) ) {
947            n++;
948        }
949    }
950
951    closedir(d);
952
953    d = opendir("/sys/class/net");
954    if (d == 0)
955        return WIFI_ERROR_UNKNOWN;
956
957    info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);
958    if (info->interfaces == NULL) {
959        ALOGE("%s: Error info->interfaces NULL", __func__);
960        return WIFI_ERROR_OUT_OF_MEMORY;
961    }
962
963    int i = 0;
964    while ((de = readdir(d))) {
965        if (de->d_name[0] == '.')
966            continue;
967        if (is_wifi_interface(de->d_name)) {
968            interface_info *ifinfo
969                = (interface_info *)malloc(sizeof(interface_info));
970            if (ifinfo == NULL) {
971                ALOGE("%s: Error ifinfo NULL", __func__);
972                while (i > 0) {
973                    free(info->interfaces[i-1]);
974                    i--;
975                }
976                free(info->interfaces);
977                return WIFI_ERROR_OUT_OF_MEMORY;
978            }
979            if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
980                free(ifinfo);
981                continue;
982            }
983            ifinfo->handle = handle;
984            info->interfaces[i] = ifinfo;
985            i++;
986        }
987    }
988
989    closedir(d);
990
991    info->num_interfaces = n;
992
993    return WIFI_SUCCESS;
994}
995
996wifi_error wifi_get_ifaces(wifi_handle handle, int *num,
997        wifi_interface_handle **interfaces)
998{
999    hal_info *info = (hal_info *)handle;
1000
1001    *interfaces = (wifi_interface_handle *)info->interfaces;
1002    *num = info->num_interfaces;
1003
1004    return WIFI_SUCCESS;
1005}
1006
1007wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name,
1008        size_t size)
1009{
1010    interface_info *info = (interface_info *)handle;
1011    strlcpy(name, info->name, size);
1012    return WIFI_SUCCESS;
1013}
1014
1015/* Get the supported Feature set */
1016wifi_error wifi_get_supported_feature_set(wifi_interface_handle iface,
1017        feature_set *set)
1018{
1019    int ret = 0;
1020    wifi_handle handle = getWifiHandle(iface);
1021    *set = 0;
1022    hal_info *info = getHalInfo(handle);
1023
1024    ret = acquire_supported_features(iface, set);
1025    if (ret != WIFI_SUCCESS) {
1026        *set = info->supported_feature_set;
1027        ALOGV("Supported feature set acquired at initialization : %x", *set);
1028    } else {
1029        info->supported_feature_set = *set;
1030        ALOGV("Supported feature set acquired : %x", *set);
1031    }
1032    return WIFI_SUCCESS;
1033}
1034
1035wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle,
1036                                       int set_size_max,
1037                                       feature_set set[], int *set_size)
1038{
1039    int ret = 0;
1040    struct nlattr *nlData;
1041    WifihalGeneric *vCommand = NULL;
1042    interface_info *ifaceInfo = getIfaceInfo(handle);
1043    wifi_handle wifiHandle = getWifiHandle(handle);
1044
1045    if (set == NULL) {
1046        ALOGE("%s: NULL set pointer provided. Exit.",
1047            __func__);
1048        return WIFI_ERROR_INVALID_ARGS;
1049    }
1050
1051    vCommand = new WifihalGeneric(wifiHandle, 0,
1052            OUI_QCA,
1053            QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX);
1054    if (vCommand == NULL) {
1055        ALOGE("%s: Error vCommand NULL", __func__);
1056        return WIFI_ERROR_OUT_OF_MEMORY;
1057    }
1058
1059    /* Create the message */
1060    ret = vCommand->create();
1061    if (ret < 0)
1062        goto cleanup;
1063
1064    ret = vCommand->set_iface_id(ifaceInfo->name);
1065    if (ret < 0)
1066        goto cleanup;
1067
1068    /* Add the vendor specific attributes for the NL command. */
1069    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1070    if (!nlData)
1071        goto cleanup;
1072
1073    if (vCommand->put_u32(
1074        QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX,
1075        set_size_max))
1076    {
1077        goto cleanup;
1078    }
1079    vCommand->attr_end(nlData);
1080
1081    /* Populate the input received from caller/framework. */
1082    vCommand->setMaxSetSize(set_size_max);
1083    vCommand->setSizePtr(set_size);
1084    vCommand->setConcurrencySet(set);
1085
1086    ret = vCommand->requestResponse();
1087    if (ret) {
1088        ALOGE("%s: requestResponse() error: %d", __func__, ret);
1089    }
1090
1091cleanup:
1092    delete vCommand;
1093    if (ret) {
1094        *set_size = 0;
1095    }
1096    return (wifi_error)ret;
1097}
1098
1099
1100wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs)
1101{
1102    int ret = 0;
1103    struct nlattr *nlData;
1104    WifiVendorCommand *vCommand = NULL;
1105    interface_info *ifaceInfo = getIfaceInfo(handle);
1106    wifi_handle wifiHandle = getWifiHandle(handle);
1107
1108    vCommand = new WifiVendorCommand(wifiHandle, 0,
1109            OUI_QCA,
1110            QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG);
1111    if (vCommand == NULL) {
1112        ALOGE("%s: Error vCommand NULL", __func__);
1113        return WIFI_ERROR_OUT_OF_MEMORY;
1114    }
1115
1116    /* Create the message */
1117    ret = vCommand->create();
1118    if (ret < 0)
1119        goto cleanup;
1120
1121    ret = vCommand->set_iface_id(ifaceInfo->name);
1122    if (ret < 0)
1123        goto cleanup;
1124
1125    /* Add the vendor specific attributes for the NL command. */
1126    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1127    if (!nlData)
1128        goto cleanup;
1129
1130    /* Add the fixed part of the mac_oui to the nl command */
1131    if (vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG, nodfs)) {
1132        goto cleanup;
1133    }
1134
1135    vCommand->attr_end(nlData);
1136
1137    ret = vCommand->requestResponse();
1138    /* Don't check response since we aren't expecting one */
1139
1140cleanup:
1141    delete vCommand;
1142    return (wifi_error)ret;
1143}
1144
1145wifi_error wifi_start_sending_offloaded_packet(wifi_request_id id,
1146                                               wifi_interface_handle iface,
1147                                               u8 *ip_packet,
1148                                               u16 ip_packet_len,
1149                                               u8 *src_mac_addr,
1150                                               u8 *dst_mac_addr,
1151                                               u32 period_msec)
1152{
1153    int ret = WIFI_SUCCESS;
1154    struct nlattr *nlData;
1155    WifiVendorCommand *vCommand = NULL;
1156
1157    ret = initialize_vendor_cmd(iface, id,
1158                                QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS,
1159                                &vCommand);
1160    if (ret != WIFI_SUCCESS) {
1161        ALOGE("%s: Initialization failed", __func__);
1162        return (wifi_error)ret;
1163    }
1164
1165    ALOGV("ip packet length : %u\nIP Packet:", ip_packet_len);
1166    hexdump(ip_packet, ip_packet_len);
1167    ALOGV("Src Mac Address: " MAC_ADDR_STR "\nDst Mac Address: " MAC_ADDR_STR
1168          "\nPeriod in msec : %u", MAC_ADDR_ARRAY(src_mac_addr),
1169          MAC_ADDR_ARRAY(dst_mac_addr), period_msec);
1170
1171    /* Add the vendor specific attributes for the NL command. */
1172    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1173    if (!nlData)
1174        goto cleanup;
1175
1176    if (vCommand->put_u32(
1177            QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL,
1178            QCA_WLAN_OFFLOADED_PACKETS_SENDING_START) ||
1179        vCommand->put_u32(
1180            QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID,
1181            id) ||
1182        vCommand->put_bytes(
1183            QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET,
1184            (const char *)ip_packet, ip_packet_len) ||
1185        vCommand->put_addr(
1186            QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR,
1187            src_mac_addr) ||
1188        vCommand->put_addr(
1189            QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR,
1190            dst_mac_addr) ||
1191        vCommand->put_u32(
1192            QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD,
1193            period_msec))
1194    {
1195        goto cleanup;
1196    }
1197
1198    vCommand->attr_end(nlData);
1199
1200    ret = vCommand->requestResponse();
1201    if (ret < 0)
1202        goto cleanup;
1203
1204cleanup:
1205    delete vCommand;
1206    return (wifi_error)ret;
1207}
1208
1209wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id id,
1210                                              wifi_interface_handle iface)
1211{
1212    int ret = WIFI_SUCCESS;
1213    struct nlattr *nlData;
1214    WifiVendorCommand *vCommand = NULL;
1215
1216    ret = initialize_vendor_cmd(iface, id,
1217                                QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS,
1218                                &vCommand);
1219    if (ret != WIFI_SUCCESS) {
1220        ALOGE("%s: Initialization failed", __func__);
1221        return (wifi_error)ret;
1222    }
1223
1224    /* Add the vendor specific attributes for the NL command. */
1225    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1226    if (!nlData)
1227        goto cleanup;
1228
1229    if (vCommand->put_u32(
1230            QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL,
1231            QCA_WLAN_OFFLOADED_PACKETS_SENDING_STOP) ||
1232        vCommand->put_u32(
1233            QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID,
1234            id))
1235    {
1236        goto cleanup;
1237    }
1238
1239
1240    vCommand->attr_end(nlData);
1241
1242    ret = vCommand->requestResponse();
1243    if (ret < 0)
1244        goto cleanup;
1245
1246cleanup:
1247    delete vCommand;
1248    return (wifi_error)ret;
1249}
1250
1251static wifi_error wifi_set_packet_filter(wifi_interface_handle iface,
1252                                         const u8 *program, u32 len)
1253{
1254    int ret = WIFI_SUCCESS;
1255    struct nlattr *nlData;
1256    WifiVendorCommand *vCommand = NULL;
1257    u32 current_offset = 0;
1258    wifi_handle wifiHandle = getWifiHandle(iface);
1259    hal_info *info = getHalInfo(wifiHandle);
1260
1261    /* len=0 clears the filters in driver/firmware */
1262    if (len != 0 && program == NULL) {
1263        ALOGE("%s: No valid program provided. Exit.",
1264            __func__);
1265        return WIFI_ERROR_INVALID_ARGS;
1266    }
1267
1268    do {
1269        ret = initialize_vendor_cmd(iface, get_requestid(),
1270                                    QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER,
1271                                    &vCommand);
1272        if (ret != WIFI_SUCCESS) {
1273            ALOGE("%s: Initialization failed", __FUNCTION__);
1274            return (wifi_error)ret;
1275        }
1276
1277        /* Add the vendor specific attributes for the NL command. */
1278        nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1279        if (!nlData)
1280            goto cleanup;
1281
1282        if (vCommand->put_u32(
1283                QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
1284                QCA_WLAN_SET_PACKET_FILTER) ||
1285            vCommand->put_u32(
1286                QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID,
1287                PACKET_FILTER_ID) ||
1288            vCommand->put_u32(
1289                QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_TOTAL_LENGTH,
1290                len) ||
1291            vCommand->put_u32(
1292                QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET,
1293                current_offset)) {
1294            ALOGE("%s: failed to put subcmd/program", __FUNCTION__);
1295            goto cleanup;
1296        }
1297
1298        if (len) {
1299            if(vCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM,
1300                                   (char *)&program[current_offset],
1301                                   min(info->firmware_bus_max_size,
1302                                   len-current_offset))) {
1303                ALOGE("%s: failed to put subcmd", __FUNCTION__);
1304                goto cleanup;
1305            }
1306        }
1307
1308        vCommand->attr_end(nlData);
1309
1310        ret = vCommand->requestResponse();
1311        if (ret < 0) {
1312            ALOGE("%s: requestResponse Error:%d",__func__, ret);
1313            goto cleanup;
1314        }
1315
1316        /* destroy the object after sending each fragment to driver */
1317        delete vCommand;
1318        vCommand = NULL;
1319
1320        current_offset += min(info->firmware_bus_max_size, len);
1321    } while (current_offset < len);
1322
1323cleanup:
1324    if (vCommand)
1325        delete vCommand;
1326    return (wifi_error)ret;
1327}
1328
1329static wifi_error wifi_get_packet_filter_capabilities(
1330                wifi_interface_handle handle, u32 *version, u32 *max_len)
1331{
1332    int ret = 0;
1333    struct nlattr *nlData;
1334    WifihalGeneric *vCommand = NULL;
1335    interface_info *ifaceInfo = getIfaceInfo(handle);
1336    wifi_handle wifiHandle = getWifiHandle(handle);
1337
1338    if (version == NULL || max_len == NULL) {
1339        ALOGE("%s: NULL version/max_len pointer provided. Exit.",
1340            __FUNCTION__);
1341        return WIFI_ERROR_INVALID_ARGS;
1342    }
1343
1344    vCommand = new WifihalGeneric(wifiHandle, 0,
1345            OUI_QCA,
1346            QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER);
1347    if (vCommand == NULL) {
1348        ALOGE("%s: Error vCommand NULL", __FUNCTION__);
1349        return WIFI_ERROR_OUT_OF_MEMORY;
1350    }
1351
1352    /* Create the message */
1353    ret = vCommand->create();
1354    if (ret < 0)
1355        goto cleanup;
1356
1357    ret = vCommand->set_iface_id(ifaceInfo->name);
1358    if (ret < 0)
1359        goto cleanup;
1360
1361    /* Add the vendor specific attributes for the NL command. */
1362    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1363    if (!nlData)
1364        goto cleanup;
1365
1366    if (vCommand->put_u32(
1367            QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SUB_CMD,
1368            QCA_WLAN_GET_PACKET_FILTER_SIZE))
1369    {
1370        goto cleanup;
1371    }
1372    vCommand->attr_end(nlData);
1373
1374    ret = vCommand->requestResponse();
1375    if (ret) {
1376        ALOGE("%s: requestResponse() error: %d", __FUNCTION__, ret);
1377        if (ret == -ENOTSUP) {
1378            /* Packet filtering is not supported currently, so return version
1379             * and length as 0
1380             */
1381            ALOGI("Packet filtering is not supprted");
1382            *version = 0;
1383            *max_len = 0;
1384            ret = WIFI_SUCCESS;
1385        }
1386        goto cleanup;
1387    }
1388
1389    *version = vCommand->getFilterVersion();
1390    *max_len = vCommand->getFilterLength();
1391cleanup:
1392    delete vCommand;
1393    return (wifi_error)ret;
1394}
1395
1396
1397static wifi_error wifi_configure_nd_offload(wifi_interface_handle iface,
1398                                            u8 enable)
1399{
1400    int ret = WIFI_SUCCESS;
1401    struct nlattr *nlData;
1402    WifiVendorCommand *vCommand = NULL;
1403
1404    ret = initialize_vendor_cmd(iface, get_requestid(),
1405                                QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD,
1406                                &vCommand);
1407    if (ret != WIFI_SUCCESS) {
1408        ALOGE("%s: Initialization failed", __func__);
1409        return (wifi_error)ret;
1410    }
1411
1412    ALOGV("ND offload : %s", enable?"Enable":"Disable");
1413
1414    /* Add the vendor specific attributes for the NL command. */
1415    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
1416    if (!nlData)
1417        goto cleanup;
1418
1419    if (vCommand->put_u8(
1420            QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG,
1421            enable))
1422    {
1423        goto cleanup;
1424    }
1425
1426    vCommand->attr_end(nlData);
1427
1428    ret = vCommand->requestResponse();
1429
1430cleanup:
1431    delete vCommand;
1432    return (wifi_error)ret;
1433}
1434