1 2 #include <stdint.h> 3 #include <fcntl.h> 4 #include <sys/socket.h> 5 #include <netlink/genl/genl.h> 6 #include <netlink/genl/family.h> 7 #include <netlink/genl/ctrl.h> 8 #include <linux/rtnetlink.h> 9 #include <netpacket/packet.h> 10 #include <linux/filter.h> 11 #include <linux/errqueue.h> 12 13 #include <linux/pkt_sched.h> 14 #include <netlink/object-api.h> 15 #include <netlink/netlink.h> 16 #include <netlink/socket.h> 17 #include <netlink/attr.h> 18 #include <netlink/handlers.h> 19 #include <netlink/msg.h> 20 21 #include <dirent.h> 22 #include <net/if.h> 23 24 #include "sync.h" 25 26 #define LOG_TAG "WifiHAL" 27 28 #include <utils/Log.h> 29 30 #include "wifi_hal.h" 31 #include "common.h" 32 #include "cpp_bindings.h" 33 34 /* 35 BUGBUG: normally, libnl allocates ports for all connections it makes; but 36 being a static library, it doesn't really know how many other netlink connections 37 are made by the same process, if connections come from different shared libraries. 38 These port assignments exist to solve that problem - temporarily. We need to fix 39 libnl to try and allocate ports across the entire process. 40 */ 41 42 #define WIFI_HAL_CMD_SOCK_PORT 644 43 #define WIFI_HAL_EVENT_SOCK_PORT 645 44 45 #define FEATURE_SET 0 46 #define FEATURE_SET_MATRIX 1 47 #define ATTR_NODFS_VALUE 3 48 49 static void internal_event_handler(wifi_handle handle, int events); 50 static int internal_no_seq_check(nl_msg *msg, void *arg); 51 static int internal_valid_message_handler(nl_msg *msg, void *arg); 52 static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group); 53 static int wifi_add_membership(wifi_handle handle, const char *group); 54 static wifi_error wifi_init_interfaces(wifi_handle handle); 55 56 typedef enum wifi_attr { 57 ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, 58 ANDR_WIFI_ATTRIBUTE_FEATURE_SET, 59 ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI 60 } wifi_attr_t; 61 62 /* Initialize/Cleanup */ 63 64 void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port) 65 { 66 uint32_t pid = getpid() & 0x3FFFFF; 67 nl_socket_set_local_port(sock, pid + (port << 22)); 68 } 69 70 static nl_sock * wifi_create_nl_socket(int port) 71 { 72 // ALOGI("Creating socket"); 73 struct nl_sock *sock = nl_socket_alloc(); 74 if (sock == NULL) { 75 ALOGE("Could not create handle"); 76 return NULL; 77 } 78 79 wifi_socket_set_local_port(sock, port); 80 81 struct sockaddr *addr = NULL; 82 // ALOGI("sizeof(sockaddr) = %d, sizeof(sockaddr_nl) = %d", sizeof(*addr), sizeof(*addr_nl)); 83 84 // ALOGI("Connecting socket"); 85 if (nl_connect(sock, NETLINK_GENERIC)) { 86 ALOGE("Could not connect handle"); 87 nl_socket_free(sock); 88 return NULL; 89 } 90 91 // ALOGI("Making socket nonblocking"); 92 /* 93 if (nl_socket_set_nonblocking(sock)) { 94 ALOGE("Could make socket non-blocking"); 95 nl_socket_free(sock); 96 return NULL; 97 } 98 */ 99 100 return sock; 101 } 102 103 wifi_error wifi_initialize(wifi_handle *handle) 104 { 105 srand(getpid()); 106 107 ALOGI("Initializing wifi"); 108 hal_info *info = (hal_info *)malloc(sizeof(hal_info)); 109 if (info == NULL) { 110 ALOGE("Could not allocate hal_info"); 111 return WIFI_ERROR_UNKNOWN; 112 } 113 114 memset(info, 0, sizeof(*info)); 115 116 ALOGI("Creating socket"); 117 struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT); 118 if (cmd_sock == NULL) { 119 ALOGE("Could not create handle"); 120 return WIFI_ERROR_UNKNOWN; 121 } 122 123 struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT); 124 if (event_sock == NULL) { 125 ALOGE("Could not create handle"); 126 nl_socket_free(cmd_sock); 127 return WIFI_ERROR_UNKNOWN; 128 } 129 130 struct nl_cb *cb = nl_socket_get_cb(event_sock); 131 if (cb == NULL) { 132 ALOGE("Could not create handle"); 133 return WIFI_ERROR_UNKNOWN; 134 } 135 136 // ALOGI("cb->refcnt = %d", cb->cb_refcnt); 137 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, internal_no_seq_check, info); 138 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info); 139 nl_cb_put(cb); 140 141 info->cmd_sock = cmd_sock; 142 info->event_sock = event_sock; 143 info->clean_up = false; 144 info->in_event_loop = false; 145 146 info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE); 147 info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE; 148 info->num_event_cb = 0; 149 150 info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE); 151 info->alloc_cmd = DEFAULT_CMD_SIZE; 152 info->num_cmd = 0; 153 154 info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211"); 155 if (info->nl80211_family_id < 0) { 156 ALOGE("Could not resolve nl80211 familty id"); 157 nl_socket_free(cmd_sock); 158 nl_socket_free(event_sock); 159 free(info); 160 return WIFI_ERROR_UNKNOWN; 161 } 162 163 pthread_mutex_init(&info->cb_lock, NULL); 164 165 *handle = (wifi_handle) info; 166 167 wifi_add_membership(*handle, "scan"); 168 wifi_add_membership(*handle, "mlme"); 169 wifi_add_membership(*handle, "regulatory"); 170 wifi_add_membership(*handle, "vendor"); 171 172 wifi_init_interfaces(*handle); 173 // ALOGI("Found %d interfaces", info->num_interfaces); 174 175 176 ALOGI("Initialized Wifi HAL Successfully; vendor cmd = %d", NL80211_CMD_VENDOR); 177 return WIFI_SUCCESS; 178 } 179 180 static int wifi_add_membership(wifi_handle handle, const char *group) 181 { 182 hal_info *info = getHalInfo(handle); 183 184 int id = wifi_get_multicast_id(handle, "nl80211", group); 185 if (id < 0) { 186 ALOGE("Could not find group %s", group); 187 return id; 188 } 189 190 int ret = nl_socket_add_membership(info->event_sock, id); 191 if (ret < 0) { 192 ALOGE("Could not add membership to group %s", group); 193 } 194 195 // ALOGI("Successfully added membership for group %s", group); 196 return ret; 197 } 198 199 static void internal_cleaned_up_handler(wifi_handle handle) 200 { 201 hal_info *info = getHalInfo(handle); 202 wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler; 203 204 if (info->cmd_sock != 0) { 205 nl_socket_free(info->cmd_sock); 206 nl_socket_free(info->event_sock); 207 info->cmd_sock = NULL; 208 info->event_sock = NULL; 209 } 210 211 (*cleaned_up_handler)(handle); 212 pthread_mutex_destroy(&info->cb_lock); 213 free(info); 214 215 ALOGI("Internal cleanup completed"); 216 } 217 218 void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler) 219 { 220 hal_info *info = getHalInfo(handle); 221 info->cleaned_up_handler = handler; 222 info->clean_up = true; 223 224 ALOGI("Wifi cleanup completed"); 225 } 226 227 static int internal_pollin_handler(wifi_handle handle) 228 { 229 hal_info *info = getHalInfo(handle); 230 struct nl_cb *cb = nl_socket_get_cb(info->event_sock); 231 int res = nl_recvmsgs(info->event_sock, cb); 232 // ALOGD("nl_recvmsgs returned %d", res); 233 nl_cb_put(cb); 234 return res; 235 } 236 237 /* Run event handler */ 238 void wifi_event_loop(wifi_handle handle) 239 { 240 hal_info *info = getHalInfo(handle); 241 if (info->in_event_loop) { 242 return; 243 } else { 244 info->in_event_loop = true; 245 } 246 247 pollfd pfd; 248 memset(&pfd, 0, sizeof(pfd)); 249 250 pfd.fd = nl_socket_get_fd(info->event_sock); 251 pfd.events = POLLIN; 252 253 /* TODO: Add support for timeouts */ 254 255 do { 256 int timeout = -1; /* Infinite timeout */ 257 pfd.revents = 0; 258 // ALOGI("Polling socket"); 259 int result = poll(&pfd, 1, -1); 260 if (result < 0) { 261 ALOGE("Error polling socket"); 262 } else if (pfd.revents & POLLERR) { 263 ALOGE("POLL Error; error no = %d", errno); 264 char buf[2048]; 265 int result2 = read(pfd.fd, buf, sizeof(buf)); 266 ALOGE("Read after POLL returned %d, error no = %d", result2, errno); 267 } else if (pfd.revents & POLLHUP) { 268 ALOGE("Remote side hung up"); 269 break; 270 } else if (pfd.revents & POLLIN) { 271 // ALOGI("Found some events!!!"); 272 internal_pollin_handler(handle); 273 } else { 274 ALOGE("Unknown event - %0x", pfd.revents); 275 } 276 } while (!info->clean_up); 277 278 279 ALOGI("Cleaning up"); 280 internal_cleaned_up_handler(handle); 281 } 282 283 /////////////////////////////////////////////////////////////////////////////////////// 284 285 static int internal_no_seq_check(struct nl_msg *msg, void *arg) 286 { 287 return NL_OK; 288 } 289 290 static int internal_valid_message_handler(nl_msg *msg, void *arg) 291 { 292 wifi_handle handle = (wifi_handle)arg; 293 hal_info *info = getHalInfo(handle); 294 295 WifiEvent event(msg); 296 int res = event.parse(); 297 if (res < 0) { 298 ALOGE("Failed to parse event: %d", res); 299 return NL_SKIP; 300 } 301 302 int cmd = event.get_cmd(); 303 uint32_t vendor_id = 0; 304 int subcmd = 0; 305 306 if (cmd == NL80211_CMD_VENDOR) { 307 vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID); 308 subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD); 309 ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x", 310 event.get_cmdString(), vendor_id, subcmd); 311 } else { 312 // ALOGI("event received %s", event.get_cmdString()); 313 } 314 315 // ALOGI("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id); 316 // event.log(); 317 318 bool dispatched = false; 319 320 pthread_mutex_lock(&info->cb_lock); 321 322 for (int i = 0; i < info->num_event_cb; i++) { 323 if (cmd == info->event_cb[i].nl_cmd) { 324 if (cmd == NL80211_CMD_VENDOR 325 && ((vendor_id != info->event_cb[i].vendor_id) 326 || (subcmd != info->event_cb[i].vendor_subcmd))) 327 { 328 /* event for a different vendor, ignore it */ 329 continue; 330 } 331 332 cb_info *cbi = &(info->event_cb[i]); 333 nl_recvmsg_msg_cb_t cb_func = cbi->cb_func; 334 void *cb_arg = cbi->cb_arg; 335 WifiCommand *cmd = (WifiCommand *)cbi->cb_arg; 336 if (cmd != NULL) { 337 cmd->addRef(); 338 } 339 340 pthread_mutex_unlock(&info->cb_lock); 341 342 (*cb_func)(msg, cb_arg); 343 if (cmd != NULL) { 344 cmd->releaseRef(); 345 } 346 347 return NL_OK; 348 } 349 } 350 351 pthread_mutex_unlock(&info->cb_lock); 352 return NL_OK; 353 } 354 355 /////////////////////////////////////////////////////////////////////////////////////// 356 357 class GetMulticastIdCommand : public WifiCommand 358 { 359 private: 360 const char *mName; 361 const char *mGroup; 362 int mId; 363 public: 364 GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group) 365 : WifiCommand(handle, 0) 366 { 367 mName = name; 368 mGroup = group; 369 mId = -1; 370 } 371 372 int getId() { 373 return mId; 374 } 375 376 virtual int create() { 377 int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl"); 378 // ALOGI("ctrl family = %d", nlctrlFamily); 379 int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0); 380 if (ret < 0) { 381 return ret; 382 } 383 ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName); 384 return ret; 385 } 386 387 virtual int handleResponse(WifiEvent& reply) { 388 389 // ALOGI("handling reponse in %s", __func__); 390 391 struct nlattr **tb = reply.attributes(); 392 struct genlmsghdr *gnlh = reply.header(); 393 struct nlattr *mcgrp = NULL; 394 int i; 395 396 if (!tb[CTRL_ATTR_MCAST_GROUPS]) { 397 ALOGI("No multicast groups found"); 398 return NL_SKIP; 399 } else { 400 // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS])); 401 } 402 403 for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) { 404 405 // ALOGI("Processing group"); 406 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1]; 407 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp), 408 nla_len(mcgrp), NULL); 409 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) { 410 continue; 411 } 412 413 char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]); 414 int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]); 415 416 // ALOGI("Found group name %s", grpName); 417 418 if (strncmp(grpName, mGroup, grpNameLen) != 0) 419 continue; 420 421 mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); 422 break; 423 } 424 425 return NL_SKIP; 426 } 427 428 }; 429 430 class SetPnoMacAddrOuiCommand : public WifiCommand { 431 432 private: 433 byte *mOui; 434 feature_set *fset; 435 feature_set *feature_matrix; 436 int *fm_size; 437 int set_size_max; 438 public: 439 SetPnoMacAddrOuiCommand(wifi_interface_handle handle, oui scan_oui) 440 : WifiCommand(handle, 0) 441 { 442 mOui = scan_oui; 443 } 444 445 int createRequest(WifiRequest& request, int subcmd, byte *scan_oui) { 446 int result = request.create(GOOGLE_OUI, subcmd); 447 if (result < 0) { 448 return result; 449 } 450 451 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA); 452 result = request.put(ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, scan_oui, DOT11_OUI_LEN); 453 if (result < 0) { 454 return result; 455 } 456 457 request.attr_end(data); 458 return WIFI_SUCCESS; 459 460 } 461 462 int start() { 463 ALOGD("Sending mac address OUI"); 464 WifiRequest request(familyId(), ifaceId()); 465 int result = createRequest(request, WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, mOui); 466 if (result != WIFI_SUCCESS) { 467 ALOGE("failed to create request; result = %d", result); 468 return result; 469 } 470 471 result = requestResponse(request); 472 if (result != WIFI_SUCCESS) { 473 ALOGE("failed to set scanning mac OUI; result = %d", result); 474 } 475 476 return result; 477 } 478 protected: 479 virtual int handleResponse(WifiEvent& reply) { 480 ALOGD("Request complete!"); 481 /* Nothing to do on response! */ 482 return NL_SKIP; 483 } 484 }; 485 486 class SetNodfsCommand : public WifiCommand { 487 488 private: 489 u32 mNoDfs; 490 public: 491 SetNodfsCommand(wifi_interface_handle handle, u32 nodfs) 492 : WifiCommand(handle, 0) { 493 mNoDfs = nodfs; 494 } 495 virtual int create() { 496 int ret; 497 498 ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_NODFS_SET); 499 if (ret < 0) { 500 ALOGE("Can't create message to send to driver - %d", ret); 501 return ret; 502 } 503 504 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA); 505 ret = mMsg.put_u32(ATTR_NODFS_VALUE, mNoDfs); 506 if (ret < 0) { 507 return ret; 508 } 509 510 mMsg.attr_end(data); 511 return WIFI_SUCCESS; 512 } 513 }; 514 515 class GetFeatureSetCommand : public WifiCommand { 516 517 private: 518 int feature_type; 519 feature_set *fset; 520 feature_set *feature_matrix; 521 int *fm_size; 522 int set_size_max; 523 public: 524 GetFeatureSetCommand(wifi_interface_handle handle, int feature, feature_set *set, 525 feature_set set_matrix[], int *size, int max_size) 526 : WifiCommand(handle, 0) 527 { 528 feature_type = feature; 529 fset = set; 530 feature_matrix = set_matrix; 531 fm_size = size; 532 set_size_max = max_size; 533 } 534 535 virtual int create() { 536 int ret; 537 538 if(feature_type == FEATURE_SET) { 539 ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET); 540 } else if (feature_type == FEATURE_SET_MATRIX) { 541 ret = mMsg.create(GOOGLE_OUI, WIFI_SUBCMD_GET_FEATURE_SET_MATRIX); 542 } else { 543 ALOGE("Unknown feature type %d", feature_type); 544 return -1; 545 } 546 547 if (ret < 0) { 548 ALOGE("Can't create message to send to driver - %d", ret); 549 } 550 551 return ret; 552 } 553 554 protected: 555 virtual int handleResponse(WifiEvent& reply) { 556 557 ALOGD("In GetFeatureSetCommand::handleResponse"); 558 559 if (reply.get_cmd() != NL80211_CMD_VENDOR) { 560 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd()); 561 return NL_SKIP; 562 } 563 564 int id = reply.get_vendor_id(); 565 int subcmd = reply.get_vendor_subcmd(); 566 567 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA); 568 int len = reply.get_vendor_data_len(); 569 570 ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len); 571 if (vendor_data == NULL || len == 0) { 572 ALOGE("no vendor data in GetFeatureSetCommand response; ignoring it"); 573 return NL_SKIP; 574 } 575 if(feature_type == FEATURE_SET) { 576 void *data = reply.get_vendor_data(); 577 if(!fset) { 578 ALOGE("Buffers pointers not set"); 579 return NL_SKIP; 580 } 581 memcpy(fset, data, min(len, (int) sizeof(*fset))); 582 } else { 583 int num_features_set = 0; 584 int i = 0; 585 586 if(!feature_matrix || !fm_size) { 587 ALOGE("Buffers pointers not set"); 588 return NL_SKIP; 589 } 590 591 for (nl_iterator it(vendor_data); it.has_next(); it.next()) { 592 if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET) { 593 num_features_set = it.get_u32(); 594 ALOGI("Got feature list with %d concurrent sets", num_features_set); 595 if(set_size_max && (num_features_set > set_size_max)) 596 num_features_set = set_size_max; 597 *fm_size = num_features_set; 598 } else if ((it.get_type() == ANDR_WIFI_ATTRIBUTE_FEATURE_SET) && 599 i < num_features_set) { 600 feature_matrix[i] = it.get_u32(); 601 i++; 602 } else { 603 ALOGW("Ignoring invalid attribute type = %d, size = %d", 604 it.get_type(), it.get_len()); 605 } 606 } 607 608 } 609 return NL_OK; 610 } 611 612 }; 613 614 static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group) 615 { 616 GetMulticastIdCommand cmd(handle, name, group); 617 int res = cmd.requestResponse(); 618 if (res < 0) 619 return res; 620 else 621 return cmd.getId(); 622 } 623 624 ///////////////////////////////////////////////////////////////////////// 625 626 static bool is_wifi_interface(const char *name) 627 { 628 if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) { 629 /* not a wifi interface; ignore it */ 630 return false; 631 } else { 632 return true; 633 } 634 } 635 636 static int get_interface(const char *name, interface_info *info) 637 { 638 strcpy(info->name, name); 639 info->id = if_nametoindex(name); 640 // ALOGI("found an interface : %s, id = %d", name, info->id); 641 return WIFI_SUCCESS; 642 } 643 644 wifi_error wifi_init_interfaces(wifi_handle handle) 645 { 646 hal_info *info = (hal_info *)handle; 647 648 struct dirent *de; 649 650 DIR *d = opendir("/sys/class/net"); 651 if (d == 0) 652 return WIFI_ERROR_UNKNOWN; 653 654 int n = 0; 655 while ((de = readdir(d))) { 656 if (de->d_name[0] == '.') 657 continue; 658 if (is_wifi_interface(de->d_name) ) { 659 n++; 660 } 661 } 662 663 closedir(d); 664 665 d = opendir("/sys/class/net"); 666 if (d == 0) 667 return WIFI_ERROR_UNKNOWN; 668 669 info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n); 670 671 int i = 0; 672 while ((de = readdir(d))) { 673 if (de->d_name[0] == '.') 674 continue; 675 if (is_wifi_interface(de->d_name)) { 676 interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info)); 677 if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) { 678 free(ifinfo); 679 continue; 680 } 681 ifinfo->handle = handle; 682 info->interfaces[i] = ifinfo; 683 i++; 684 } 685 } 686 687 closedir(d); 688 689 info->num_interfaces = n; 690 return WIFI_SUCCESS; 691 } 692 693 wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces) 694 { 695 hal_info *info = (hal_info *)handle; 696 697 *interfaces = (wifi_interface_handle *)info->interfaces; 698 *num = info->num_interfaces; 699 700 return WIFI_SUCCESS; 701 } 702 703 wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size) 704 { 705 interface_info *info = (interface_info *)handle; 706 strcpy(name, info->name); 707 return WIFI_SUCCESS; 708 } 709 710 wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set) 711 { 712 GetFeatureSetCommand command(handle, FEATURE_SET, set, NULL, NULL, 1); 713 return (wifi_error) command.requestResponse(); 714 } 715 716 wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max, 717 feature_set set[], int *set_size) 718 { 719 GetFeatureSetCommand command(handle, FEATURE_SET_MATRIX, NULL, set, set_size, set_size_max); 720 return (wifi_error) command.requestResponse(); 721 } 722 723 wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui) 724 { 725 SetPnoMacAddrOuiCommand command(handle, scan_oui); 726 return (wifi_error)command.start(); 727 728 } 729 730 wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs) 731 { 732 SetNodfsCommand command(handle, nodfs); 733 return (wifi_error) command.requestResponse(); 734 } 735 736 ///////////////////////////////////////////////////////////////////////////// 737