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