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