wifi.c revision eea19f1d855b9434313fbb9447a23caf8123aa58
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_PATH 53#define WIFI_DRIVER_MODULE_PATH "/system/lib/modules/wlan.ko" 54#endif 55#ifndef WIFI_DRIVER_MODULE_NAME 56#define WIFI_DRIVER_MODULE_NAME "wlan" 57#endif 58#ifndef WIFI_DRIVER_MODULE_ARG 59#define WIFI_DRIVER_MODULE_ARG "" 60#endif 61#ifndef WIFI_FIRMWARE_LOADER 62#define WIFI_FIRMWARE_LOADER "" 63#endif 64#define WIFI_TEST_INTERFACE "sta" 65 66#define WIFI_DRIVER_LOADER_DELAY 1000000 67 68static const char IFACE_DIR[] = "/data/system/wpa_supplicant"; 69static const char DRIVER_MODULE_NAME[] = WIFI_DRIVER_MODULE_NAME; 70static const char DRIVER_MODULE_TAG[] = WIFI_DRIVER_MODULE_NAME " "; 71static const char DRIVER_MODULE_PATH[] = WIFI_DRIVER_MODULE_PATH; 72static const char DRIVER_MODULE_ARG[] = WIFI_DRIVER_MODULE_ARG; 73static const char FIRMWARE_LOADER[] = WIFI_FIRMWARE_LOADER; 74static const char DRIVER_PROP_NAME[] = "wlan.driver.status"; 75static const char SUPPLICANT_NAME[] = "wpa_supplicant"; 76static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant"; 77static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf"; 78static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf"; 79static const char MODULE_FILE[] = "/proc/modules"; 80 81static int insmod(const char *filename, const char *args) 82{ 83 void *module; 84 unsigned int size; 85 int ret; 86 87 module = load_file(filename, &size); 88 if (!module) 89 return -1; 90 91 ret = init_module(module, size, args); 92 93 free(module); 94 95 return ret; 96} 97 98static int rmmod(const char *modname) 99{ 100 int ret = -1; 101 int maxtry = 10; 102 103 while (maxtry-- > 0) { 104 ret = delete_module(modname, O_NONBLOCK | O_EXCL); 105 if (ret < 0 && errno == EAGAIN) 106 usleep(500000); 107 else 108 break; 109 } 110 111 if (ret != 0) 112 LOGD("Unable to unload driver module \"%s\": %s\n", 113 modname, strerror(errno)); 114 return ret; 115} 116 117int do_dhcp_request(int *ipaddr, int *gateway, int *mask, 118 int *dns1, int *dns2, int *server, int *lease) { 119 /* For test driver, always report success */ 120 if (strcmp(iface, WIFI_TEST_INTERFACE) == 0) 121 return 0; 122 123 if (ifc_init() < 0) 124 return -1; 125 126 if (do_dhcp(iface) < 0) { 127 ifc_close(); 128 return -1; 129 } 130 ifc_close(); 131 get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease); 132 return 0; 133} 134 135const char *get_dhcp_error_string() { 136 return dhcp_lasterror(); 137} 138 139int is_wifi_driver_loaded() { 140 char driver_status[PROPERTY_VALUE_MAX]; 141 FILE *proc; 142 char line[sizeof(DRIVER_MODULE_TAG)+10]; 143 144 if (!property_get(DRIVER_PROP_NAME, driver_status, NULL) 145 || strcmp(driver_status, "ok") != 0) { 146 return 0; /* driver not loaded */ 147 } 148 /* 149 * If the property says the driver is loaded, check to 150 * make sure that the property setting isn't just left 151 * over from a previous manual shutdown or a runtime 152 * crash. 153 */ 154 if ((proc = fopen(MODULE_FILE, "r")) == NULL) { 155 LOGW("Could not open %s: %s", MODULE_FILE, strerror(errno)); 156 property_set(DRIVER_PROP_NAME, "unloaded"); 157 return 0; 158 } 159 while ((fgets(line, sizeof(line), proc)) != NULL) { 160 if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) { 161 fclose(proc); 162 return 1; 163 } 164 } 165 fclose(proc); 166 property_set(DRIVER_PROP_NAME, "unloaded"); 167 return 0; 168} 169 170int wifi_load_driver() 171{ 172 char driver_status[PROPERTY_VALUE_MAX]; 173 int count = 100; /* wait at most 20 seconds for completion */ 174 175 if (is_wifi_driver_loaded()) { 176 return 0; 177 } 178 179 if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) 180 return -1; 181 182 if (strcmp(FIRMWARE_LOADER,"") == 0) { 183 /* usleep(WIFI_DRIVER_LOADER_DELAY); */ 184 property_set(DRIVER_PROP_NAME, "ok"); 185 } 186 else { 187 property_set("ctl.start", FIRMWARE_LOADER); 188 } 189 sched_yield(); 190 while (count-- > 0) { 191 if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) { 192 if (strcmp(driver_status, "ok") == 0) 193 return 0; 194 else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) { 195 wifi_unload_driver(); 196 return -1; 197 } 198 } 199 usleep(200000); 200 } 201 property_set(DRIVER_PROP_NAME, "timeout"); 202 wifi_unload_driver(); 203 return -1; 204} 205 206int wifi_unload_driver() 207{ 208 int count = 20; /* wait at most 10 seconds for completion */ 209 210 if (rmmod(DRIVER_MODULE_NAME) == 0) { 211 while (count-- > 0) { 212 if (!is_wifi_driver_loaded()) 213 break; 214 usleep(500000); 215 } 216 if (count) { 217 return 0; 218 } 219 return -1; 220 } else 221 return -1; 222} 223 224int ensure_config_file_exists() 225{ 226 char buf[2048]; 227 char ifc[PROPERTY_VALUE_MAX]; 228 char *sptr; 229 char *pbuf; 230 int srcfd, destfd; 231 struct stat sb; 232 int nread; 233 int ret; 234 235 ret = access(SUPP_CONFIG_FILE, R_OK|W_OK); 236 if ((ret == 0) || (errno == EACCES)) { 237 if ((ret != 0) && 238 (chmod(SUPP_CONFIG_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) { 239 LOGE("Cannot set RW to \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 240 return -1; 241 } 242 /* return if filesize is at least 10 bytes */ 243 if (stat(SUPP_CONFIG_FILE, &sb) == 0 && sb.st_size > 10) { 244 pbuf = malloc(sb.st_size + PROPERTY_VALUE_MAX); 245 if (!pbuf) 246 return 0; 247 srcfd = open(SUPP_CONFIG_FILE, O_RDONLY); 248 if (srcfd < 0) { 249 LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 250 free(pbuf); 251 return 0; 252 } 253 nread = read(srcfd, pbuf, sb.st_size); 254 close(srcfd); 255 if (nread < 0) { 256 LOGE("Cannot read \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 257 free(pbuf); 258 return 0; 259 } 260 property_get("wifi.interface", ifc, WIFI_TEST_INTERFACE); 261 if ((sptr = strstr(pbuf, "ctrl_interface="))) { 262 char *iptr = sptr + strlen("ctrl_interface="); 263 int ilen = 0; 264 int mlen = strlen(ifc); 265 if (strncmp(ifc, iptr, mlen) != 0) { 266 LOGE("ctrl_interface != %s", ifc); 267 while (((ilen + (iptr - pbuf)) < nread) && (iptr[ilen] != '\n')) 268 ilen++; 269 mlen = ((ilen >= mlen) ? ilen : mlen) + 1; 270 memmove(iptr + mlen, iptr + ilen + 1, nread - (iptr + ilen + 1 - pbuf)); 271 memset(iptr, '\n', mlen); 272 memcpy(iptr, ifc, strlen(ifc)); 273 destfd = open(SUPP_CONFIG_FILE, O_RDWR, 0660); 274 if (destfd < 0) { 275 LOGE("Cannot update \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 276 free(pbuf); 277 return -1; 278 } 279 write(destfd, pbuf, nread); 280 close(destfd); 281 } 282 } 283 free(pbuf); 284 return 0; 285 } 286 } else if (errno != ENOENT) { 287 LOGE("Cannot access \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 288 return -1; 289 } 290 291 srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY); 292 if (srcfd < 0) { 293 LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); 294 return -1; 295 } 296 297 destfd = open(SUPP_CONFIG_FILE, O_CREAT|O_RDWR, 0660); 298 if (destfd < 0) { 299 close(srcfd); 300 LOGE("Cannot create \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); 301 return -1; 302 } 303 304 while ((nread = read(srcfd, buf, sizeof(buf))) != 0) { 305 if (nread < 0) { 306 LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); 307 close(srcfd); 308 close(destfd); 309 unlink(SUPP_CONFIG_FILE); 310 return -1; 311 } 312 write(destfd, buf, nread); 313 } 314 315 close(destfd); 316 close(srcfd); 317 318 /* chmod is needed because open() didn't set permisions properly */ 319 if (chmod(SUPP_CONFIG_FILE, 0660) < 0) { 320 LOGE("Error changing permissions of %s to 0660: %s", 321 SUPP_CONFIG_FILE, strerror(errno)); 322 unlink(SUPP_CONFIG_FILE); 323 return -1; 324 } 325 326 if (chown(SUPP_CONFIG_FILE, AID_SYSTEM, AID_WIFI) < 0) { 327 LOGE("Error changing group ownership of %s to %d: %s", 328 SUPP_CONFIG_FILE, AID_WIFI, strerror(errno)); 329 unlink(SUPP_CONFIG_FILE); 330 return -1; 331 } 332 return 0; 333} 334 335/** 336 * wifi_wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that 337 * may be left over from clients that were previously connected to 338 * wpa_supplicant. This keeps these files from being orphaned in the 339 * event of crashes that prevented them from being removed as part 340 * of the normal orderly shutdown. 341 */ 342void wifi_wpa_ctrl_cleanup(void) 343{ 344 DIR *dir; 345 struct dirent entry; 346 struct dirent *result; 347 size_t dirnamelen; 348 size_t maxcopy; 349 char pathname[PATH_MAX]; 350 char *namep; 351 char *local_socket_dir = CONFIG_CTRL_IFACE_CLIENT_DIR; 352 char *local_socket_prefix = CONFIG_CTRL_IFACE_CLIENT_PREFIX; 353 354 if ((dir = opendir(local_socket_dir)) == NULL) 355 return; 356 357 dirnamelen = (size_t)snprintf(pathname, sizeof(pathname), "%s/", local_socket_dir); 358 if (dirnamelen >= sizeof(pathname)) { 359 closedir(dir); 360 return; 361 } 362 namep = pathname + dirnamelen; 363 maxcopy = PATH_MAX - dirnamelen; 364 while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { 365 if (strncmp(entry.d_name, local_socket_prefix, strlen(local_socket_prefix)) == 0) { 366 if (strlcpy(namep, entry.d_name, maxcopy) < maxcopy) { 367 unlink(pathname); 368 } 369 } 370 } 371 closedir(dir); 372} 373 374int wifi_start_supplicant() 375{ 376 char daemon_cmd[PROPERTY_VALUE_MAX]; 377 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 378 int count = 200; /* wait at most 20 seconds for completion */ 379#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 380 const prop_info *pi; 381 unsigned serial = 0; 382#endif 383 384 /* Check whether already running */ 385 if (property_get(SUPP_PROP_NAME, supp_status, NULL) 386 && strcmp(supp_status, "running") == 0) { 387 return 0; 388 } 389 390 /* Before starting the daemon, make sure its config file exists */ 391 if (ensure_config_file_exists() < 0) { 392 LOGE("Wi-Fi will not be enabled"); 393 return -1; 394 } 395 396 /* Clear out any stale socket files that might be left over. */ 397 wifi_wpa_ctrl_cleanup(); 398 399#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 400 /* 401 * Get a reference to the status property, so we can distinguish 402 * the case where it goes stopped => running => stopped (i.e., 403 * it start up, but fails right away) from the case in which 404 * it starts in the stopped state and never manages to start 405 * running at all. 406 */ 407 pi = __system_property_find(SUPP_PROP_NAME); 408 if (pi != NULL) { 409 serial = pi->serial; 410 } 411#endif 412 property_get("wifi.interface", iface, WIFI_TEST_INTERFACE); 413 snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s", SUPPLICANT_NAME, iface); 414 property_set("ctl.start", daemon_cmd); 415 sched_yield(); 416 417 while (count-- > 0) { 418#ifdef HAVE_LIBC_SYSTEM_PROPERTIES 419 if (pi == NULL) { 420 pi = __system_property_find(SUPP_PROP_NAME); 421 } 422 if (pi != NULL) { 423 __system_property_read(pi, NULL, supp_status); 424 if (strcmp(supp_status, "running") == 0) { 425 return 0; 426 } else if (pi->serial != serial && 427 strcmp(supp_status, "stopped") == 0) { 428 return -1; 429 } 430 } 431#else 432 if (property_get(SUPP_PROP_NAME, supp_status, NULL)) { 433 if (strcmp(supp_status, "running") == 0) 434 return 0; 435 } 436#endif 437 usleep(100000); 438 } 439 return -1; 440} 441 442int wifi_stop_supplicant() 443{ 444 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 445 int count = 50; /* wait at most 5 seconds for completion */ 446 447 /* Check whether supplicant already stopped */ 448 if (property_get(SUPP_PROP_NAME, supp_status, NULL) 449 && strcmp(supp_status, "stopped") == 0) { 450 return 0; 451 } 452 453 property_set("ctl.stop", SUPPLICANT_NAME); 454 sched_yield(); 455 456 while (count-- > 0) { 457 if (property_get(SUPP_PROP_NAME, supp_status, NULL)) { 458 if (strcmp(supp_status, "stopped") == 0) 459 return 0; 460 } 461 usleep(100000); 462 } 463 return -1; 464} 465 466int wifi_connect_to_supplicant() 467{ 468 char ifname[256]; 469 char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; 470 471 /* Make sure supplicant is running */ 472 if (!property_get(SUPP_PROP_NAME, supp_status, NULL) 473 || strcmp(supp_status, "running") != 0) { 474 LOGE("Supplicant not running, cannot connect"); 475 return -1; 476 } 477 478 if (access(IFACE_DIR, F_OK) == 0) { 479 snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface); 480 } else { 481 strlcpy(ifname, iface, sizeof(ifname)); 482 } 483 484 ctrl_conn = wpa_ctrl_open(ifname); 485 if (ctrl_conn == NULL) { 486 LOGE("Unable to open connection to supplicant on \"%s\": %s", 487 ifname, strerror(errno)); 488 return -1; 489 } 490 monitor_conn = wpa_ctrl_open(ifname); 491 if (monitor_conn == NULL) { 492 wpa_ctrl_close(ctrl_conn); 493 ctrl_conn = NULL; 494 return -1; 495 } 496 if (wpa_ctrl_attach(monitor_conn) != 0) { 497 wpa_ctrl_close(monitor_conn); 498 wpa_ctrl_close(ctrl_conn); 499 ctrl_conn = monitor_conn = NULL; 500 return -1; 501 } 502 return 0; 503} 504 505int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len) 506{ 507 int ret; 508 509 if (ctrl_conn == NULL) { 510 LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd); 511 return -1; 512 } 513 ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL); 514 if (ret == -2) { 515 LOGD("'%s' command timed out.\n", cmd); 516 return -2; 517 } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) { 518 return -1; 519 } 520 if (strncmp(cmd, "PING", 4) == 0) { 521 reply[*reply_len] = '\0'; 522 } 523 return 0; 524} 525 526int wifi_wait_for_event(char *buf, size_t buflen) 527{ 528 size_t nread = buflen - 1; 529 int fd; 530 fd_set rfds; 531 int result; 532 struct timeval tval; 533 struct timeval *tptr; 534 535 if (monitor_conn == NULL) { 536 LOGD("Connection closed\n"); 537 strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1); 538 buf[buflen-1] = '\0'; 539 return strlen(buf); 540 } 541 542 result = wpa_ctrl_recv(monitor_conn, buf, &nread); 543 if (result < 0) { 544 LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno)); 545 strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1); 546 buf[buflen-1] = '\0'; 547 return strlen(buf); 548 } 549 buf[nread] = '\0'; 550 /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */ 551 /* Check for EOF on the socket */ 552 if (result == 0 && nread == 0) { 553 /* Fabricate an event to pass up */ 554 LOGD("Received EOF on supplicant socket\n"); 555 strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1); 556 buf[buflen-1] = '\0'; 557 return strlen(buf); 558 } 559 /* 560 * Events strings are in the format 561 * 562 * <N>CTRL-EVENT-XXX 563 * 564 * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG, 565 * etc.) and XXX is the event name. The level information is not useful 566 * to us, so strip it off. 567 */ 568 if (buf[0] == '<') { 569 char *match = strchr(buf, '>'); 570 if (match != NULL) { 571 nread -= (match+1-buf); 572 memmove(buf, match+1, nread+1); 573 } 574 } 575 return nread; 576} 577 578void wifi_close_supplicant_connection() 579{ 580 if (ctrl_conn != NULL) { 581 wpa_ctrl_close(ctrl_conn); 582 ctrl_conn = NULL; 583 } 584 if (monitor_conn != NULL) { 585 wpa_ctrl_close(monitor_conn); 586 monitor_conn = NULL; 587 } 588} 589 590int wifi_command(const char *command, char *reply, size_t *reply_len) 591{ 592 return wifi_send_command(ctrl_conn, command, reply, reply_len); 593} 594