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#include <sys/socket.h> 23#include <unistd.h> 24#include <poll.h> 25 26#include "hardware_legacy/wifi.h" 27#include "libwpa_client/wpa_ctrl.h" 28 29#define LOG_TAG "WifiHW" 30#include "cutils/log.h" 31#include "cutils/memory.h" 32#include "cutils/misc.h" 33#include "cutils/properties.h" 34#include "private/android_filesystem_config.h" 35#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 36#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 37#include <sys/_system_properties.h> 38#endif 39 40static struct wpa_ctrl *ctrl_conn; 41static struct wpa_ctrl *monitor_conn; 42 43/* socket pair used to exit from a blocking read */ 44static int exit_sockets[2]; 45 46extern int do_dhcp(); 47extern int ifc_init(); 48extern void ifc_close(); 49extern char *dhcp_lasterror(); 50extern void get_dhcp_info(); 51extern int init_module(void *, unsigned long, const char *); 52extern int delete_module(const char *, unsigned int); 53void wifi_close_sockets(); 54 55static char primary_iface[PROPERTY_VALUE_MAX]; 56// TODO: use new ANDROID_SOCKET mechanism, once support for multiple 57// sockets is in 58 59#ifndef WIFI_DRIVER_MODULE_ARG 60#define WIFI_DRIVER_MODULE_ARG "" 61#endif 62#ifndef WIFI_FIRMWARE_LOADER 63#define WIFI_FIRMWARE_LOADER "" 64#endif 65#define WIFI_TEST_INTERFACE "sta" 66 67#ifndef WIFI_DRIVER_FW_PATH_STA 68#define WIFI_DRIVER_FW_PATH_STA NULL 69#endif 70#ifndef WIFI_DRIVER_FW_PATH_AP 71#define WIFI_DRIVER_FW_PATH_AP NULL 72#endif 73#ifndef WIFI_DRIVER_FW_PATH_P2P 74#define WIFI_DRIVER_FW_PATH_P2P NULL 75#endif 76 77#ifndef WIFI_DRIVER_FW_PATH_PARAM 78#define WIFI_DRIVER_FW_PATH_PARAM "/sys/module/wlan/parameters/fwpath" 79#endif 80 81#define WIFI_DRIVER_LOADER_DELAY 1000000 82 83static const char IFACE_DIR[] = "/data/system/wpa_supplicant"; 84#ifdef WIFI_DRIVER_MODULE_PATH 85static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME; 86static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " "; 87static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH; 88static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG; 89#endif 90static const char FIRMWARE_LOADER[] = WIFI_FIRMWARE_LOADER; 91static const char DRIVER_PROP_NAME[] = "wlan.driver.status"; 92static const char SUPPLICANT_NAME[] = "wpa_supplicant"; 93static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant"; 94static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant"; 95static const char P2P_PROP_NAME[] = "init.svc.p2p_supplicant"; 96static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf"; 97static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf"; 98static const char P2P_CONFIG_FILE[] = "/data/misc/wifi/p2p_supplicant.conf"; 99static const char CONTROL_IFACE_PATH[] = "/data/misc/wifi/sockets"; 100static const char MODULE_FILE[] = "/proc/modules"; 101 102static const char IFNAME[] = "IFNAME="; 103#define IFNAMELEN (sizeof(IFNAME) - 1) 104static const char WPA_EVENT_IGNORE[] = "CTRL-EVENT-IGNORE "; 105 106static const char SUPP_ENTROPY_FILE[] = WIFI_ENTROPY_FILE; 107static unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35, 108 0x68, 0x47, 0x84, 0x99, 0xa9, 0x2b, 109 0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2, 110 0xf3, 0xf4, 0xf5 }; 111 112/* Is either SUPPLICANT_NAME or P2P_SUPPLICANT_NAME */ 113static char supplicant_name[PROPERTY_VALUE_MAX]; 114/* Is either SUPP_PROP_NAME or P2P_PROP_NAME */ 115static char supplicant_prop_name[PROPERTY_KEY_MAX]; 116 117static int insmod(const char *filename, const char *args) 118{ 119 void *module; 120 unsigned int size; 121 int ret; 122 123 module = load_file(filename, &size); 124 if (!module) 125 return -1; 126 127 ret = init_module(module, size, args); 128 129 free(module); 130 131 return ret; 132} 133 134static int rmmod(const char *modname) 135{ 136 int ret = -1; 137 int maxtry = 10; 138 139 while (maxtry-- > 0) { 140 ret = delete_module(modname, O_NONBLOCK | O_EXCL); 141 if (ret < 0 && errno == EAGAIN) 142 usleep(500000); 143 else 144 break; 145 } 146 147 if (ret != 0) 148 ALOGD("Unable to unload driver module \"%s\": %s\n", 149 modname, strerror(errno)); 150 return ret; 151} 152 153int do_dhcp_request(int *ipaddr, int *gateway, int *mask, 154 int *dns1, int *dns2, int *server, int *lease) { 155 /* For test driver, always report success */ 156 if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0) 157 return 0; 158 159 if (ifc_init() < 0) 160 return -1; 161 162 if (do_dhcp(primary_iface) < 0) { 163 ifc_close(); 164 return -1; 165 } 166 ifc_close(); 167 get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease); 168 return 0; 169} 170 171const char *get_dhcp_error_string() { 172 return dhcp_lasterror(); 173} 174 175int is_wifi_driver_loaded() { 176 char driver_status[PROPERTY_VALUE_MAX]; 177#ifdef WIFI_DRIVER_MODULE_PATH 178 FILE *proc; 179 char line[sizeof(DRIVER_MODULE_TAG)+10]; 180#endif 181 182 if (!property_get(DRIVER_PROP_NAME, driver_status, NULL) 183 || strcmp(driver_status, "ok") != 0) { 184 return 0; /* driver not loaded */ 185 } 186#ifdef WIFI_DRIVER_MODULE_PATH 187 /* 188 * If the property says the driver is loaded, check to 189 * make sure that the property setting isn't just left 190 * over from a previous manual shutdown or a runtime 191 * crash. 192 */ 193 if ((proc = fopen(MODULE_FILE, "r")) == NULL) { 194 ALOGW("Could not open %s: %s", MODULE_FILE, strerror(errno)); 195 property_set(DRIVER_PROP_NAME, "unloaded"); 196 return 0; 197 } 198 while ((fgets(line, sizeof(line), proc)) != NULL) { 199 if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) { 200 fclose(proc); 201 return 1; 202 } 203 } 204 fclose(proc); 205 property_set(DRIVER_PROP_NAME, "unloaded"); 206 return 0; 207#else 208 return 1; 209#endif 210} 211 212int wifi_load_driver() 213{ 214#ifdef WIFI_DRIVER_MODULE_PATH 215 char driver_status[PROPERTY_VALUE_MAX]; 216 int count = 100; /* wait at most 20 seconds for completion */ 217 218 if (is_wifi_driver_loaded()) { 219 return 0; 220 } 221 222 if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) 223 return -1; 224 225 if (strcmp(FIRMWARE_LOADER,"") == 0) { 226 /* usleep(WIFI_DRIVER_LOADER_DELAY); */ 227 property_set(DRIVER_PROP_NAME, "ok"); 228 } 229 else { 230 property_set("ctl.start", FIRMWARE_LOADER); 231 } 232 sched_yield(); 233 while (count-- > 0) { 234 if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) { 235 if (strcmp(driver_status, "ok") == 0) 236 return 0; 237 else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) { 238 wifi_unload_driver(); 239 return -1; 240 } 241 } 242 usleep(200000); 243 } 244 property_set(DRIVER_PROP_NAME, "timeout"); 245 wifi_unload_driver(); 246 return -1; 247#else 248 property_set(DRIVER_PROP_NAME, "ok"); 249 return 0; 250#endif 251} 252 253int wifi_unload_driver() 254{ 255 usleep(200000); /* allow to finish interface down */ 256#ifdef WIFI_DRIVER_MODULE_PATH 257 if (rmmod(DRIVER_MODULE_NAME) == 0) { 258 int count = 20; /* wait at most 10 seconds for completion */ 259 while (count-- > 0) { 260 if (!is_wifi_driver_loaded()) 261 break; 262 usleep(500000); 263 } 264 usleep(500000); /* allow card removal */ 265 if (count) { 266 return 0; 267 } 268 return -1; 269 } else 270 return -1; 271#else 272 property_set(DRIVER_PROP_NAME, "unloaded"); 273 return 0; 274#endif 275} 276 277int ensure_entropy_file_exists() 278{ 279 int ret; 280 int destfd; 281 282 ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK); 283 if ((ret == 0) || (errno == EACCES)) { 284 if ((ret != 0) && 285 (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) { 286 ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); 287 return -1; 288 } 289 return 0; 290 } 291 destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660)); 292 if (destfd < 0) { 293 ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); 294 return -1; 295 } 296 297 if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) { 298 ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno)); 299 close(destfd); 300 return -1; 301 } 302 close(destfd); 303 304 /* chmod is needed because open() didn't set permisions properly */ 305 if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) { 306 ALOGE("Error changing permissions of %s to 0660: %s", 307 SUPP_ENTROPY_FILE, strerror(errno)); 308 unlink(SUPP_ENTROPY_FILE); 309 return -1; 310 } 311 312 if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) { 313 ALOGE("Error changing group ownership of %s to %d: %s", 314 SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno)); 315 unlink(SUPP_ENTROPY_FILE); 316 return -1; 317 } 318 return 0; 319} 320 321int update_ctrl_interface(const char *config_file) { 322 323 int srcfd, destfd; 324 int nread; 325 char ifc[PROPERTY_VALUE_MAX]; 326 char *pbuf; 327 char *sptr; 328 struct stat sb; 329 int ret; 330 331 if (stat(config_file, &sb) != 0) 332 return -1; 333 334 pbuf = malloc(sb.st_size + PROPERTY_VALUE_MAX); 335 if (!pbuf) 336 return 0; 337 srcfd = TEMP_FAILURE_RETRY(open(config_file, O_RDONLY)); 338 if (srcfd < 0) { 339 ALOGE("Cannot open \"%s\": %s", config_file, strerror(errno)); 340 free(pbuf); 341 return 0; 342 } 343 nread = TEMP_FAILURE_RETRY(read(srcfd, pbuf, sb.st_size)); 344 close(srcfd); 345 if (nread < 0) { 346 ALOGE("Cannot read \"%s\": %s", config_file, strerror(errno)); 347 free(pbuf); 348 return 0; 349 } 350 351 if (!strcmp(config_file, SUPP_CONFIG_FILE)) { 352 property_get("wifi.interface", ifc, WIFI_TEST_INTERFACE); 353 } else { 354 strcpy(ifc, CONTROL_IFACE_PATH); 355 } 356 /* Assume file is invalid to begin with */ 357 ret = -1; 358 /* 359 * if there is a "ctrl_interface=<value>" entry, re-write it ONLY if it is 360 * NOT a directory. The non-directory value option is an Android add-on 361 * that allows the control interface to be exchanged through an environment 362 * variable (initialized by the "init" program when it starts a service 363 * with a "socket" option). 364 * 365 * The <value> is deemed to be a directory if the "DIR=" form is used or 366 * the value begins with "/". 367 */ 368 if ((sptr = strstr(pbuf, "ctrl_interface="))) { 369 ret = 0; 370 if ((!strstr(pbuf, "ctrl_interface=DIR=")) && 371 (!strstr(pbuf, "ctrl_interface=/"))) { 372 char *iptr = sptr + strlen("ctrl_interface="); 373 int ilen = 0; 374 int mlen = strlen(ifc); 375 int nwrite; 376 if (strncmp(ifc, iptr, mlen) != 0) { 377 ALOGE("ctrl_interface != %s", ifc); 378 while (((ilen + (iptr - pbuf)) < nread) && (iptr[ilen] != '\n')) 379 ilen++; 380 mlen = ((ilen >= mlen) ? ilen : mlen) + 1; 381 memmove(iptr + mlen, iptr + ilen + 1, nread - (iptr + ilen + 1 - pbuf)); 382 memset(iptr, '\n', mlen); 383 memcpy(iptr, ifc, strlen(ifc)); 384 destfd = TEMP_FAILURE_RETRY(open(config_file, O_RDWR, 0660)); 385 if (destfd < 0) { 386 ALOGE("Cannot update \"%s\": %s", config_file, strerror(errno)); 387 free(pbuf); 388 return -1; 389 } 390 TEMP_FAILURE_RETRY(write(destfd, pbuf, nread + mlen - ilen -1)); 391 close(destfd); 392 } 393 } 394 } 395 free(pbuf); 396 return ret; 397} 398 399int ensure_config_file_exists(const char *config_file) 400{ 401 char buf[2048]; 402 int srcfd, destfd; 403 struct stat sb; 404 int nread; 405 int ret; 406 407 ret = access(config_file, R_OK|W_OK); 408 if ((ret == 0) || (errno == EACCES)) { 409 if ((ret != 0) && 410 (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) { 411 ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno)); 412 return -1; 413 } 414 /* return if we were able to update control interface properly */ 415 if (update_ctrl_interface(config_file) >=0) { 416 return 0; 417 } else { 418 /* This handles the scenario where the file had bad data 419 * for some reason. We continue and recreate the file. 420 */ 421 } 422 } else if (errno != ENOENT) { 423 ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno)); 424 return -1; 425 } 426 427 srcfd = TEMP_FAILURE_RETRY(open(SUPP_CONFIG_TEMPLATE, O_RDONLY)); 428 if (srcfd < 0) { 429 ALOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); 430 return -1; 431 } 432 433 destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660)); 434 if (destfd < 0) { 435 close(srcfd); 436 ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno)); 437 return -1; 438 } 439 440 while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) { 441 if (nread < 0) { 442 ALOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); 443 close(srcfd); 444 close(destfd); 445 unlink(config_file); 446 return -1; 447 } 448 TEMP_FAILURE_RETRY(write(destfd, buf, nread)); 449 } 450 451 close(destfd); 452 close(srcfd); 453 454 /* chmod is needed because open() didn't set permisions properly */ 455 if (chmod(config_file, 0660) < 0) { 456 ALOGE("Error changing permissions of %s to 0660: %s", 457 config_file, strerror(errno)); 458 unlink(config_file); 459 return -1; 460 } 461 462 if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) { 463 ALOGE("Error changing group ownership of %s to %d: %s", 464 config_file, AID_WIFI, strerror(errno)); 465 unlink(config_file); 466 return -1; 467 } 468 return update_ctrl_interface(config_file); 469} 470 471int wifi_start_supplicant(int p2p_supported) 472{ 473 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 474 int count = 200; /* wait at most 20 seconds for completion */ 475#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 476 const prop_info *pi; 477 unsigned serial = 0, i; 478#endif 479 480 if (p2p_supported) { 481 strcpy(supplicant_name, P2P_SUPPLICANT_NAME); 482 strcpy(supplicant_prop_name, P2P_PROP_NAME); 483 484 /* Ensure p2p config file is created */ 485 if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) { 486 ALOGE("Failed to create a p2p config file"); 487 return -1; 488 } 489 490 } else { 491 strcpy(supplicant_name, SUPPLICANT_NAME); 492 strcpy(supplicant_prop_name, SUPP_PROP_NAME); 493 } 494 495 /* Check whether already running */ 496 if (property_get(supplicant_name, supp_status, NULL) 497 && strcmp(supp_status, "running") == 0) { 498 return 0; 499 } 500 501 /* Before starting the daemon, make sure its config file exists */ 502 if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) { 503 ALOGE("Wi-Fi will not be enabled"); 504 return -1; 505 } 506 507 if (ensure_entropy_file_exists() < 0) { 508 ALOGE("Wi-Fi entropy file was not created"); 509 } 510 511 /* Clear out any stale socket files that might be left over. */ 512 wpa_ctrl_cleanup(); 513 514 /* Reset sockets used for exiting from hung state */ 515 exit_sockets[0] = exit_sockets[1] = -1; 516 517#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 518 /* 519 * Get a reference to the status property, so we can distinguish 520 * the case where it goes stopped => running => stopped (i.e., 521 * it start up, but fails right away) from the case in which 522 * it starts in the stopped state and never manages to start 523 * running at all. 524 */ 525 pi = __system_property_find(supplicant_prop_name); 526 if (pi != NULL) { 527 serial = __system_property_serial(pi); 528 } 529#endif 530 property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE); 531 532 property_set("ctl.start", supplicant_name); 533 sched_yield(); 534 535 while (count-- > 0) { 536#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 537 if (pi == NULL) { 538 pi = __system_property_find(supplicant_prop_name); 539 } 540 if (pi != NULL) { 541 __system_property_read(pi, NULL, supp_status); 542 if (strcmp(supp_status, "running") == 0) { 543 return 0; 544 } else if (__system_property_serial(pi) != serial && 545 strcmp(supp_status, "stopped") == 0) { 546 return -1; 547 } 548 } 549#else 550 if (property_get(supplicant_prop_name, supp_status, NULL)) { 551 if (strcmp(supp_status, "running") == 0) 552 return 0; 553 } 554#endif 555 usleep(100000); 556 } 557 return -1; 558} 559 560int wifi_stop_supplicant(int p2p_supported) 561{ 562 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 563 int count = 50; /* wait at most 5 seconds for completion */ 564 565 if (p2p_supported) { 566 strcpy(supplicant_name, P2P_SUPPLICANT_NAME); 567 strcpy(supplicant_prop_name, P2P_PROP_NAME); 568 } else { 569 strcpy(supplicant_name, SUPPLICANT_NAME); 570 strcpy(supplicant_prop_name, SUPP_PROP_NAME); 571 } 572 573 /* Check whether supplicant already stopped */ 574 if (property_get(supplicant_prop_name, supp_status, NULL) 575 && strcmp(supp_status, "stopped") == 0) { 576 return 0; 577 } 578 579 property_set("ctl.stop", supplicant_name); 580 sched_yield(); 581 582 while (count-- > 0) { 583 if (property_get(supplicant_prop_name, supp_status, NULL)) { 584 if (strcmp(supp_status, "stopped") == 0) 585 return 0; 586 } 587 usleep(100000); 588 } 589 ALOGE("Failed to stop supplicant"); 590 return -1; 591} 592 593int wifi_connect_on_socket_path(const char *path) 594{ 595 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 596 597 /* Make sure supplicant is running */ 598 if (!property_get(supplicant_prop_name, supp_status, NULL) 599 || strcmp(supp_status, "running") != 0) { 600 ALOGE("Supplicant not running, cannot connect"); 601 return -1; 602 } 603 604 ctrl_conn = wpa_ctrl_open(path); 605 if (ctrl_conn == NULL) { 606 ALOGE("Unable to open connection to supplicant on \"%s\": %s", 607 path, strerror(errno)); 608 return -1; 609 } 610 monitor_conn = wpa_ctrl_open(path); 611 if (monitor_conn == NULL) { 612 wpa_ctrl_close(ctrl_conn); 613 ctrl_conn = NULL; 614 return -1; 615 } 616 if (wpa_ctrl_attach(monitor_conn) != 0) { 617 wpa_ctrl_close(monitor_conn); 618 wpa_ctrl_close(ctrl_conn); 619 ctrl_conn = monitor_conn = NULL; 620 return -1; 621 } 622 623 if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) { 624 wpa_ctrl_close(monitor_conn); 625 wpa_ctrl_close(ctrl_conn); 626 ctrl_conn = monitor_conn = NULL; 627 return -1; 628 } 629 630 return 0; 631} 632 633/* Establishes the control and monitor socket connections on the interface */ 634int wifi_connect_to_supplicant() 635{ 636 static char path[PATH_MAX]; 637 638 if (access(IFACE_DIR, F_OK) == 0) { 639 snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface); 640 } else { 641 snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface); 642 } 643 return wifi_connect_on_socket_path(path); 644} 645 646int wifi_send_command(const char *cmd, char *reply, size_t *reply_len) 647{ 648 int ret; 649 if (ctrl_conn == NULL) { 650 ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd); 651 return -1; 652 } 653 ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL); 654 if (ret == -2) { 655 ALOGD("'%s' command timed out.\n", cmd); 656 /* unblocks the monitor receive socket for termination */ 657 TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1)); 658 return -2; 659 } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) { 660 return -1; 661 } 662 if (strncmp(cmd, "PING", 4) == 0) { 663 reply[*reply_len] = '\0'; 664 } 665 return 0; 666} 667 668int wifi_ctrl_recv(char *reply, size_t *reply_len) 669{ 670 int res; 671 int ctrlfd = wpa_ctrl_get_fd(monitor_conn); 672 struct pollfd rfds[2]; 673 674 memset(rfds, 0, 2 * sizeof(struct pollfd)); 675 rfds[0].fd = ctrlfd; 676 rfds[0].events |= POLLIN; 677 rfds[1].fd = exit_sockets[1]; 678 rfds[1].events |= POLLIN; 679 res = TEMP_FAILURE_RETRY(poll(rfds, 2, -1)); 680 if (res < 0) { 681 ALOGE("Error poll = %d", res); 682 return res; 683 } 684 if (rfds[0].revents & POLLIN) { 685 return wpa_ctrl_recv(monitor_conn, reply, reply_len); 686 } 687 688 /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket) 689 * or we timed out. In either case, this call has failed .. 690 */ 691 return -2; 692} 693 694int wifi_wait_on_socket(char *buf, size_t buflen) 695{ 696 size_t nread = buflen - 1; 697 int result; 698 char *match, *match2; 699 700 if (monitor_conn == NULL) { 701 return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - connection closed"); 702 } 703 704 result = wifi_ctrl_recv(buf, &nread); 705 706 /* Terminate reception on exit socket */ 707 if (result == -2) { 708 return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - connection closed"); 709 } 710 711 if (result < 0) { 712 ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno)); 713 return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - recv error"); 714 } 715 buf[nread] = '\0'; 716 /* Check for EOF on the socket */ 717 if (result == 0 && nread == 0) { 718 /* Fabricate an event to pass up */ 719 ALOGD("Received EOF on supplicant socket\n"); 720 return snprintf(buf, buflen, WPA_EVENT_TERMINATING " - signal 0 received"); 721 } 722 /* 723 * Events strings are in the format 724 * 725 * IFNAME=iface <N>CTRL-EVENT-XXX 726 * or 727 * <N>CTRL-EVENT-XXX 728 * 729 * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG, 730 * etc.) and XXX is the event name. The level information is not useful 731 * to us, so strip it off. 732 */ 733 734 if (strncmp(buf, IFNAME, IFNAMELEN) == 0) { 735 match = strchr(buf, ' '); 736 if (match != NULL) { 737 if (match[1] == '<') { 738 match2 = strchr(match + 2, '>'); 739 if (match2 != NULL) { 740 nread -= (match2 - match); 741 memmove(match + 1, match2 + 1, nread - (match - buf) + 1); 742 } 743 } 744 } else { 745 return snprintf(buf, buflen, "%s", WPA_EVENT_IGNORE); 746 } 747 } else if (buf[0] == '<') { 748 match = strchr(buf, '>'); 749 if (match != NULL) { 750 nread -= (match + 1 - buf); 751 memmove(buf, match + 1, nread + 1); 752 ALOGV("supplicant generated event without interface - %s\n", buf); 753 } 754 } else { 755 /* let the event go as is! */ 756 ALOGW("supplicant generated event without interface and without message level - %s\n", buf); 757 } 758 759 return nread; 760} 761 762int wifi_wait_for_event(char *buf, size_t buflen) 763{ 764 return wifi_wait_on_socket(buf, buflen); 765} 766 767void wifi_close_sockets() 768{ 769 if (ctrl_conn != NULL) { 770 wpa_ctrl_close(ctrl_conn); 771 ctrl_conn = NULL; 772 } 773 774 if (monitor_conn != NULL) { 775 wpa_ctrl_close(monitor_conn); 776 monitor_conn = NULL; 777 } 778 779 if (exit_sockets[0] >= 0) { 780 close(exit_sockets[0]); 781 exit_sockets[0] = -1; 782 } 783 784 if (exit_sockets[1] >= 0) { 785 close(exit_sockets[1]); 786 exit_sockets[1] = -1; 787 } 788} 789 790void wifi_close_supplicant_connection() 791{ 792 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 793 int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */ 794 795 wifi_close_sockets(); 796 797 while (count-- > 0) { 798 if (property_get(supplicant_prop_name, supp_status, NULL)) { 799 if (strcmp(supp_status, "stopped") == 0) 800 return; 801 } 802 usleep(100000); 803 } 804} 805 806int wifi_command(const char *command, char *reply, size_t *reply_len) 807{ 808 return wifi_send_command(command, reply, reply_len); 809} 810 811const char *wifi_get_fw_path(int fw_type) 812{ 813 switch (fw_type) { 814 case WIFI_GET_FW_PATH_STA: 815 return WIFI_DRIVER_FW_PATH_STA; 816 case WIFI_GET_FW_PATH_AP: 817 return WIFI_DRIVER_FW_PATH_AP; 818 case WIFI_GET_FW_PATH_P2P: 819 return WIFI_DRIVER_FW_PATH_P2P; 820 } 821 return NULL; 822} 823 824int wifi_change_fw_path(const char *fwpath) 825{ 826 int len; 827 int fd; 828 int ret = 0; 829 830 if (!fwpath) 831 return ret; 832 fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY)); 833 if (fd < 0) { 834 ALOGE("Failed to open wlan fw path param (%s)", strerror(errno)); 835 return -1; 836 } 837 len = strlen(fwpath) + 1; 838 if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) { 839 ALOGE("Failed to write wlan fw path param (%s)", strerror(errno)); 840 ret = -1; 841 } 842 close(fd); 843 return ret; 844} 845