Home | History | Annotate | Download | only in wifi
      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