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 40 static struct wpa_ctrl *ctrl_conn; 41 static struct wpa_ctrl *monitor_conn; 42 43 /* socket pair used to exit from a blocking read */ 44 static int exit_sockets[2]; 45 46 extern int do_dhcp(); 47 extern int ifc_init(); 48 extern void ifc_close(); 49 extern char *dhcp_lasterror(); 50 extern void get_dhcp_info(); 51 extern int init_module(void *, unsigned long, const char *); 52 extern int delete_module(const char *, unsigned int); 53 void wifi_close_sockets(); 54 55 static 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 83 static const char IFACE_DIR[] = "/data/system/wpa_supplicant"; 84 #ifdef WIFI_DRIVER_MODULE_PATH 85 static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME; 86 static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " "; 87 static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH; 88 static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG; 89 #endif 90 static const char FIRMWARE_LOADER[] = WIFI_FIRMWARE_LOADER; 91 static const char DRIVER_PROP_NAME[] = "wlan.driver.status"; 92 static const char SUPPLICANT_NAME[] = "wpa_supplicant"; 93 static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant"; 94 static const char P2P_SUPPLICANT_NAME[] = "p2p_supplicant"; 95 static const char P2P_PROP_NAME[] = "init.svc.p2p_supplicant"; 96 static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf"; 97 static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf"; 98 static const char P2P_CONFIG_FILE[] = "/data/misc/wifi/p2p_supplicant.conf"; 99 static const char CONTROL_IFACE_PATH[] = "/data/misc/wifi/sockets"; 100 static const char MODULE_FILE[] = "/proc/modules"; 101 102 static const char IFNAME[] = "IFNAME="; 103 #define IFNAMELEN (sizeof(IFNAME) - 1) 104 static const char WPA_EVENT_IGNORE[] = "CTRL-EVENT-IGNORE "; 105 106 static const char SUPP_ENTROPY_FILE[] = WIFI_ENTROPY_FILE; 107 static 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 */ 113 static char supplicant_name[PROPERTY_VALUE_MAX]; 114 /* Is either SUPP_PROP_NAME or P2P_PROP_NAME */ 115 static char supplicant_prop_name[PROPERTY_KEY_MAX]; 116 117 static 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 134 static 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 153 int 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 171 const char *get_dhcp_error_string() { 172 return dhcp_lasterror(); 173 } 174 175 int 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 212 int 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 253 int 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 277 int 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 321 int 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 399 int 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 471 int 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 560 int 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 593 int 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 */ 634 int 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 646 int 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 668 int 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 694 int 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 762 int wifi_wait_for_event(char *buf, size_t buflen) 763 { 764 return wifi_wait_on_socket(buf, buflen); 765 } 766 767 void 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 790 void 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 806 int wifi_command(const char *command, char *reply, size_t *reply_len) 807 { 808 return wifi_send_command(command, reply, reply_len); 809 } 810 811 const 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 824 int 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