wifi.c revision 5a8a2d2b130644f0f4abad8586f0a245e4c15be8
1/* 2 * Copyright 2008, 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 <stdlib.h> 18#include <fcntl.h> 19#include <errno.h> 20#include <string.h> 21#include <dirent.h> 22 23#include "hardware_legacy/wifi.h" 24#include "libwpa_client/wpa_ctrl.h" 25 26#define LOG_TAG "WifiHW" 27#include "cutils/log.h" 28#include "cutils/memory.h" 29#include "cutils/misc.h" 30#include "cutils/properties.h" 31#include "private/android_filesystem_config.h" 32#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 33#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 34#include <sys/_system_properties.h> 35#endif 36 37static struct wpa_ctrl *ctrl_conn; 38static struct wpa_ctrl *monitor_conn; 39 40extern int do_dhcp(); 41extern int ifc_init(); 42extern void ifc_close(); 43extern char *dhcp_lasterror(); 44extern void get_dhcp_info(); 45extern int init_module(void *, unsigned long, const char *); 46extern int delete_module(const char *, unsigned int); 47 48static char iface[PROPERTY_VALUE_MAX]; 49// TODO: use new ANDROID_SOCKET mechanism, once support for multiple 50// sockets is in 51 52#ifndef WIFI_DRIVER_MODULE_ARG 53#define WIFI_DRIVER_MODULE_ARG "" 54#endif 55#ifndef WIFI_FIRMWARE_LOADER 56#define WIFI_FIRMWARE_LOADER "" 57#endif 58#define WIFI_TEST_INTERFACE "sta" 59 60#ifndef WIFI_DRIVER_FW_PATH_STA 61#define WIFI_DRIVER_FW_PATH_STA NULL 62#endif 63#ifndef WIFI_DRIVER_FW_PATH_AP 64#define WIFI_DRIVER_FW_PATH_AP NULL 65#endif 66#ifndef WIFI_DRIVER_FW_PATH_P2P 67#define WIFI_DRIVER_FW_PATH_P2P NULL 68#endif 69 70#ifndef WIFI_DRIVER_FW_PATH_PARAM 71#define WIFI_DRIVER_FW_PATH_PARAM "/sys/module/wlan/parameters/fwpath" 72#endif 73 74#define WIFI_DRIVER_LOADER_DELAY 1000000 75 76static const char IFACE_DIR[] = "/data/system/wpa_supplicant"; 77#ifdef WIFI_DRIVER_MODULE_PATH 78static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME; 79static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " "; 80static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH; 81static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG; 82#endif 83static const char FIRMWARE_LOADER[] = WIFI_FIRMWARE_LOADER; 84static const char DRIVER_PROP_NAME[] = "wlan.driver.status"; 85static const char SUPPLICANT_NAME[] = "wpa_supplicant"; 86static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant"; 87static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf"; 88static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf"; 89static const char MODULE_FILE[] = "/proc/modules"; 90 91static const char SUPP_ENTROPY_FILE[] = WIFI_ENTROPY_FILE; 92static unsigned char dummy_key[20] = { 0x11, 0xbe, 0x33, 0x43, 0x35, 93 0x68, 0x47, 0x84, 0x99, 0xa9, 94 0x2b, 0x1c, 0xd3, 0xee, 0xff, 95 0xf1, 0xe2, 0xf3, 0xf4, 0xf5 }; 96 97static int insmod(const char *filename, const char *args) 98{ 99 void *module; 100 unsigned int size; 101 int ret; 102 103 module = load_file(filename, &size); 104 if (!module) 105 return -1; 106 107 ret = init_module(module, size, args); 108 109 free(module); 110 111 return ret; 112} 113 114static int rmmod(const char *modname) 115{ 116 int ret = -1; 117 int maxtry = 10; 118 119 while (maxtry-- > 0) { 120 ret = delete_module(modname, O_NONBLOCK | O_EXCL); 121 if (ret < 0 && errno == EAGAIN) 122 usleep(500000); 123 else 124 break; 125 } 126 127 if (ret != 0) 128 LOGD("Unable to unload driver module \"%s\": %s\n", 129 modname, strerror(errno)); 130 return ret; 131} 132 133int do_dhcp_request(int *ipaddr, int *gateway, int *mask, 134 int *dns1, int *dns2, int *server, int *lease) { 135 /* For test driver, always report success */ 136 if (strcmp(iface, WIFI_TEST_INTERFACE) == 0) 137 return 0; 138 139 if (ifc_init() < 0) 140 return -1; 141 142 if (do_dhcp(iface) < 0) { 143 ifc_close(); 144 return -1; 145 } 146 ifc_close(); 147 get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease); 148 return 0; 149} 150 151const char *get_dhcp_error_string() { 152 return dhcp_lasterror(); 153} 154 155int is_wifi_driver_loaded() { 156 char driver_status[PROPERTY_VALUE_MAX]; 157#ifdef WIFI_DRIVER_MODULE_PATH 158 FILE *proc; 159 char line[sizeof(DRIVER_MODULE_TAG)+10]; 160#endif 161 162 if (!property_get(DRIVER_PROP_NAME, driver_status, NULL) 163 || strcmp(driver_status, "ok") != 0) { 164 return 0; /* driver not loaded */ 165 } 166#ifdef WIFI_DRIVER_MODULE_PATH 167 /* 168 * If the property says the driver is loaded, check to 169 * make sure that the property setting isn't just left 170 * over from a previous manual shutdown or a runtime 171 * crash. 172 */ 173 if ((proc = fopen(MODULE_FILE, "r")) == NULL) { 174 LOGW("Could not open %s: %s", MODULE_FILE, strerror(errno)); 175 property_set(DRIVER_PROP_NAME, "unloaded"); 176 return 0; 177 } 178 while ((fgets(line, sizeof(line), proc)) != NULL) { 179 if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) { 180 fclose(proc); 181 return 1; 182 } 183 } 184 fclose(proc); 185 property_set(DRIVER_PROP_NAME, "unloaded"); 186 return 0; 187#else 188 return 1; 189#endif 190} 191 192int wifi_load_driver() 193{ 194#ifdef WIFI_DRIVER_MODULE_PATH 195 char driver_status[PROPERTY_VALUE_MAX]; 196 int count = 100; /* wait at most 20 seconds for completion */ 197 198 if (is_wifi_driver_loaded()) { 199 return 0; 200 } 201 202 if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) 203 return -1; 204 205 if (strcmp(FIRMWARE_LOADER,"") == 0) { 206 /* usleep(WIFI_DRIVER_LOADER_DELAY); */ 207 property_set(DRIVER_PROP_NAME, "ok"); 208 } 209 else { 210 property_set("ctl.start", FIRMWARE_LOADER); 211 } 212 sched_yield(); 213 while (count-- > 0) { 214 if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) { 215 if (strcmp(driver_status, "ok") == 0) 216 return 0; 217 else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) { 218 wifi_unload_driver(); 219 return -1; 220 } 221 } 222 usleep(200000); 223 } 224 property_set(DRIVER_PROP_NAME, "timeout"); 225 wifi_unload_driver(); 226 return -1; 227#else 228 property_set(DRIVER_PROP_NAME, "ok"); 229 return 0; 230#endif 231} 232 233int wifi_unload_driver() 234{ 235#ifdef WIFI_DRIVER_MODULE_PATH 236 int count = 20; /* wait at most 10 seconds for completion */ 237 238 usleep(200000); /* allow to finish interface down */ 239 if (rmmod(DRIVER_MODULE_NAME) == 0) { 240 while (count-- > 0) { 241 if (!is_wifi_driver_loaded()) 242 break; 243 usleep(500000); 244 } 245 usleep(300000); /* allow card removal */ 246 if (count) { 247 return 0; 248 } 249 return -1; 250 } else 251 return -1; 252#else 253 property_set(DRIVER_PROP_NAME, "unloaded"); 254 return 0; 255#endif 256} 257 258int ensure_entropy_file_exists() 259{ 260 int ret; 261 int destfd; 262 263 ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK); 264 if ((ret == 0) || (errno == EACCES)) { 265 if ((ret != 0) && 266 (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) { 267 LOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); 268 return -1; 269 } 270 return 0; 271 } 272 destfd = open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660); 273 if (destfd < 0) { 274 LOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); 275 return -1; 276 } 277 278 if (write(destfd, dummy_key, sizeof(dummy_key)) != sizeof(dummy_key)) { 279 LOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); 280 close(destfd); 281 return -1; 282 } 283 close(destfd); 284 285 /* chmod is needed because open() didn't set permisions properly */ 286 if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) { 287 LOGE("Error changing permissions of %s to 0660: %s", 288 SUPP_ENTROPY_FILE, strerror(errno)); 289 unlink(SUPP_ENTROPY_FILE); 290 return -1; 291 } 292 293 if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) { 294 LOGE("Error changing group ownership of %s to %d: %s", 295 SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno)); 296 unlink(SUPP_ENTROPY_FILE); 297 return -1; 298 } 299 return 0; 300} 301 302int ensure_config_file_exists() 303{ 304 char buf[2048]; 305 char ifc[PROPERTY_VALUE_MAX]; 306 char *sptr; 307 char *pbuf; 308 int srcfd, destfd; 309 struct stat sb; 310 int nread; 311 int ret; 312 313 ret = access(SUPP_CONFIG_FILE, R_OK|W_OK); 314 if ((ret == 0) || (errno == EACCES)) { 315 if ((ret != 0) && 316 (chmod(SUPP_CONFIG_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) { 317 LOGE("Cannot set RW to \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 318 return -1; 319 } 320 /* return if filesize is at least 10 bytes */ 321 if (stat(SUPP_CONFIG_FILE, &sb) == 0 && sb.st_size > 10) { 322 pbuf = malloc(sb.st_size + PROPERTY_VALUE_MAX); 323 if (!pbuf) 324 return 0; 325 srcfd = open(SUPP_CONFIG_FILE, O_RDONLY); 326 if (srcfd < 0) { 327 LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 328 free(pbuf); 329 return 0; 330 } 331 nread = read(srcfd, pbuf, sb.st_size); 332 close(srcfd); 333 if (nread < 0) { 334 LOGE("Cannot read \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 335 free(pbuf); 336 return 0; 337 } 338 property_get("wifi.interface", ifc, WIFI_TEST_INTERFACE); 339 if ((sptr = strstr(pbuf, "ctrl_interface="))) { 340 char *iptr = sptr + strlen("ctrl_interface="); 341 int ilen = 0; 342 int mlen = strlen(ifc); 343 if (strncmp(ifc, iptr, mlen) != 0) { 344 LOGE("ctrl_interface != %s", ifc); 345 while (((ilen + (iptr - pbuf)) < nread) && (iptr[ilen] != '\n')) 346 ilen++; 347 mlen = ((ilen >= mlen) ? ilen : mlen) + 1; 348 memmove(iptr + mlen, iptr + ilen + 1, nread - (iptr + ilen + 1 - pbuf)); 349 memset(iptr, '\n', mlen); 350 memcpy(iptr, ifc, strlen(ifc)); 351 destfd = open(SUPP_CONFIG_FILE, O_RDWR, 0660); 352 if (destfd < 0) { 353 LOGE("Cannot update \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 354 free(pbuf); 355 return -1; 356 } 357 write(destfd, pbuf, nread); 358 close(destfd); 359 } 360 } 361 free(pbuf); 362 return 0; 363 } 364 } else if (errno != ENOENT) { 365 LOGE("Cannot access \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 366 return -1; 367 } 368 369 srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY); 370 if (srcfd < 0) { 371 LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); 372 return -1; 373 } 374 375 destfd = open(SUPP_CONFIG_FILE, O_CREAT|O_RDWR, 0660); 376 if (destfd < 0) { 377 close(srcfd); 378 LOGE("Cannot create \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 379 return -1; 380 } 381 382 while ((nread = read(srcfd, buf, sizeof(buf))) != 0) { 383 if (nread < 0) { 384 LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); 385 close(srcfd); 386 close(destfd); 387 unlink(SUPP_CONFIG_FILE); 388 return -1; 389 } 390 write(destfd, buf, nread); 391 } 392 393 close(destfd); 394 close(srcfd); 395 396 /* chmod is needed because open() didn't set permisions properly */ 397 if (chmod(SUPP_CONFIG_FILE, 0660) < 0) { 398 LOGE("Error changing permissions of %s to 0660: %s", 399 SUPP_CONFIG_FILE, strerror(errno)); 400 unlink(SUPP_CONFIG_FILE); 401 return -1; 402 } 403 404 if (chown(SUPP_CONFIG_FILE, AID_SYSTEM, AID_WIFI) < 0) { 405 LOGE("Error changing group ownership of %s to %d: %s", 406 SUPP_CONFIG_FILE, AID_WIFI, strerror(errno)); 407 unlink(SUPP_CONFIG_FILE); 408 return -1; 409 } 410 return 0; 411} 412 413/** 414 * wifi_wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that 415 * may be left over from clients that were previously connected to 416 * wpa_supplicant. This keeps these files from being orphaned in the 417 * event of crashes that prevented them from being removed as part 418 * of the normal orderly shutdown. 419 */ 420void wifi_wpa_ctrl_cleanup(void) 421{ 422 DIR *dir; 423 struct dirent entry; 424 struct dirent *result; 425 size_t dirnamelen; 426 size_t maxcopy; 427 char pathname[PATH_MAX]; 428 char *namep; 429 char *local_socket_dir = CONFIG_CTRL_IFACE_CLIENT_DIR; 430 char *local_socket_prefix = CONFIG_CTRL_IFACE_CLIENT_PREFIX; 431 432 if ((dir = opendir(local_socket_dir)) == NULL) 433 return; 434 435 dirnamelen = (size_t)snprintf(pathname, sizeof(pathname), "%s/", local_socket_dir); 436 if (dirnamelen >= sizeof(pathname)) { 437 closedir(dir); 438 return; 439 } 440 namep = pathname + dirnamelen; 441 maxcopy = PATH_MAX - dirnamelen; 442 while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { 443 if (strncmp(entry.d_name, local_socket_prefix, strlen(local_socket_prefix)) == 0) { 444 if (strlcpy(namep, entry.d_name, maxcopy) < maxcopy) { 445 unlink(pathname); 446 } 447 } 448 } 449 closedir(dir); 450} 451 452int wifi_start_supplicant() 453{ 454 char daemon_cmd[PROPERTY_VALUE_MAX]; 455 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 456 int count = 200; /* wait at most 20 seconds for completion */ 457#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 458 const prop_info *pi; 459 unsigned serial = 0; 460#endif 461 462 /* Check whether already running */ 463 if (property_get(SUPP_PROP_NAME, supp_status, NULL) 464 && strcmp(supp_status, "running") == 0) { 465 return 0; 466 } 467 468 /* Before starting the daemon, make sure its config file exists */ 469 if (ensure_config_file_exists() < 0) { 470 LOGE("Wi-Fi will not be enabled"); 471 return -1; 472 } 473 474 if (ensure_entropy_file_exists() < 0) { 475 LOGE("Wi-Fi entropy file was not created"); 476 } 477 478 /* Clear out any stale socket files that might be left over. */ 479 wifi_wpa_ctrl_cleanup(); 480 481#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 482 /* 483 * Get a reference to the status property, so we can distinguish 484 * the case where it goes stopped => running => stopped (i.e., 485 * it start up, but fails right away) from the case in which 486 * it starts in the stopped state and never manages to start 487 * running at all. 488 */ 489 pi = __system_property_find(SUPP_PROP_NAME); 490 if (pi != NULL) { 491 serial = pi->serial; 492 } 493#endif 494 property_get("wifi.interface", iface, WIFI_TEST_INTERFACE); 495 snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s", SUPPLICANT_NAME, iface); 496 property_set("ctl.start", daemon_cmd); 497 sched_yield(); 498 499 while (count-- > 0) { 500#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 501 if (pi == NULL) { 502 pi = __system_property_find(SUPP_PROP_NAME); 503 } 504 if (pi != NULL) { 505 __system_property_read(pi, NULL, supp_status); 506 if (strcmp(supp_status, "running") == 0) { 507 return 0; 508 } else if (pi->serial != serial && 509 strcmp(supp_status, "stopped") == 0) { 510 return -1; 511 } 512 } 513#else 514 if (property_get(SUPP_PROP_NAME, supp_status, NULL)) { 515 if (strcmp(supp_status, "running") == 0) 516 return 0; 517 } 518#endif 519 usleep(100000); 520 } 521 return -1; 522} 523 524int wifi_stop_supplicant() 525{ 526 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 527 int count = 50; /* wait at most 5 seconds for completion */ 528 529 /* Check whether supplicant already stopped */ 530 if (property_get(SUPP_PROP_NAME, supp_status, NULL) 531 && strcmp(supp_status, "stopped") == 0) { 532 return 0; 533 } 534 535 property_set("ctl.stop", SUPPLICANT_NAME); 536 sched_yield(); 537 538 while (count-- > 0) { 539 if (property_get(SUPP_PROP_NAME, supp_status, NULL)) { 540 if (strcmp(supp_status, "stopped") == 0) 541 return 0; 542 } 543 usleep(100000); 544 } 545 return -1; 546} 547 548int wifi_connect_to_supplicant() 549{ 550 char ifname[256]; 551 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 552 553 /* Make sure supplicant is running */ 554 if (!property_get(SUPP_PROP_NAME, supp_status, NULL) 555 || strcmp(supp_status, "running") != 0) { 556 LOGE("Supplicant not running, cannot connect"); 557 return -1; 558 } 559 560 if (access(IFACE_DIR, F_OK) == 0) { 561 snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface); 562 } else { 563 strlcpy(ifname, iface, sizeof(ifname)); 564 } 565 566 ctrl_conn = wpa_ctrl_open(ifname); 567 if (ctrl_conn == NULL) { 568 LOGE("Unable to open connection to supplicant on \"%s\": %s", 569 ifname, strerror(errno)); 570 return -1; 571 } 572 monitor_conn = wpa_ctrl_open(ifname); 573 if (monitor_conn == NULL) { 574 wpa_ctrl_close(ctrl_conn); 575 ctrl_conn = NULL; 576 return -1; 577 } 578 if (wpa_ctrl_attach(monitor_conn) != 0) { 579 wpa_ctrl_close(monitor_conn); 580 wpa_ctrl_close(ctrl_conn); 581 ctrl_conn = monitor_conn = NULL; 582 return -1; 583 } 584 return 0; 585} 586 587int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len) 588{ 589 int ret; 590 591 if (ctrl_conn == NULL) { 592 LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd); 593 return -1; 594 } 595 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL); 596 if (ret == -2) { 597 LOGD("'%s' command timed out.\n", cmd); 598 return -2; 599 } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) { 600 return -1; 601 } 602 if (strncmp(cmd, "PING", 4) == 0) { 603 reply[*reply_len] = '\0'; 604 } 605 return 0; 606} 607 608int wifi_wait_for_event(char *buf, size_t buflen) 609{ 610 size_t nread = buflen - 1; 611 int fd; 612 fd_set rfds; 613 int result; 614 struct timeval tval; 615 struct timeval *tptr; 616 617 if (monitor_conn == NULL) { 618 LOGD("Connection closed\n"); 619 strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1); 620 buf[buflen-1] = '\0'; 621 return strlen(buf); 622 } 623 624 result = wpa_ctrl_recv(monitor_conn, buf, &nread); 625 if (result < 0) { 626 LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno)); 627 strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1); 628 buf[buflen-1] = '\0'; 629 return strlen(buf); 630 } 631 buf[nread] = '\0'; 632 /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */ 633 /* Check for EOF on the socket */ 634 if (result == 0 && nread == 0) { 635 /* Fabricate an event to pass up */ 636 LOGD("Received EOF on supplicant socket\n"); 637 strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1); 638 buf[buflen-1] = '\0'; 639 return strlen(buf); 640 } 641 /* 642 * Events strings are in the format 643 * 644 * <N>CTRL-EVENT-XXX 645 * 646 * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG, 647 * etc.) and XXX is the event name. The level information is not useful 648 * to us, so strip it off. 649 */ 650 if (buf[0] == '<') { 651 char *match = strchr(buf, '>'); 652 if (match != NULL) { 653 nread -= (match+1-buf); 654 memmove(buf, match+1, nread+1); 655 } 656 } 657 return nread; 658} 659 660void wifi_close_supplicant_connection() 661{ 662 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 663 int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */ 664 665 if (ctrl_conn != NULL) { 666 wpa_ctrl_close(ctrl_conn); 667 ctrl_conn = NULL; 668 } 669 if (monitor_conn != NULL) { 670 wpa_ctrl_close(monitor_conn); 671 monitor_conn = NULL; 672 } 673 674 while (count-- > 0) { 675 if (property_get(SUPP_PROP_NAME, supp_status, NULL)) { 676 if (strcmp(supp_status, "stopped") == 0) 677 return; 678 } 679 usleep(100000); 680 } 681} 682 683int wifi_command(const char *command, char *reply, size_t *reply_len) 684{ 685 return wifi_send_command(ctrl_conn, command, reply, reply_len); 686} 687 688const char *wifi_get_fw_path(int fw_type) 689{ 690 switch (fw_type) { 691 case WIFI_GET_FW_PATH_STA: 692 return WIFI_DRIVER_FW_PATH_STA; 693 case WIFI_GET_FW_PATH_AP: 694 return WIFI_DRIVER_FW_PATH_AP; 695 case WIFI_GET_FW_PATH_P2P: 696 return WIFI_DRIVER_FW_PATH_P2P; 697 } 698 return NULL; 699} 700 701int wifi_change_fw_path(const char *fwpath) 702{ 703 int len; 704 int fd; 705 int ret = 0; 706 707 if (!fwpath) 708 return ret; 709 fd = open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY); 710 if (fd < 0) { 711 LOGE("Failed to open wlan fw path param (%s)", strerror(errno)); 712 return -1; 713 } 714 len = strlen(fwpath) + 1; 715 if (write(fd, fwpath, len) != len) { 716 LOGE("Failed to write wlan fw path param (%s)", strerror(errno)); 717 ret = -1; 718 } 719 close(fd); 720 return ret; 721} 722