OSDN Git Service

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