OSDN Git Service

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