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