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 <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(DRIVER_NAME_PROP, modname, NULL))
400         return -1;
401
402     if (rmmod(modname) == 0) {
403         int count = 20; /* wait at most 10 seconds for completion */
404         while (count-- > 0) {
405             if (!is_wifi_driver_loaded())
406                 break;
407             usleep(500000);
408         }
409         usleep(500000); /* allow card removal */
410         if (count) {
411             return 0;
412         }
413     }
414     return -1;
415 #else
416 #ifdef WIFI_DRIVER_STATE_CTRL_PARAM
417     if (is_wifi_driver_loaded()) {
418         if (wifi_change_driver_state(WIFI_DRIVER_STATE_OFF) < 0)
419             return -1;
420     }
421 #endif
422     property_set(DRIVER_PROP_NAME, "unloaded");
423     return 0;
424 #endif
425 }
426
427 int ensure_entropy_file_exists()
428 {
429     int ret;
430     int destfd;
431
432     ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK);
433     if ((ret == 0) || (errno == EACCES)) {
434         if ((ret != 0) &&
435             (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
436             ALOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
437             return -1;
438         }
439         return 0;
440     }
441     destfd = TEMP_FAILURE_RETRY(open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660));
442     if (destfd < 0) {
443         ALOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
444         return -1;
445     }
446
447     if (TEMP_FAILURE_RETRY(write(destfd, dummy_key, sizeof(dummy_key))) != sizeof(dummy_key)) {
448         ALOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
449         close(destfd);
450         return -1;
451     }
452     close(destfd);
453
454     /* chmod is needed because open() didn't set permisions properly */
455     if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) {
456         ALOGE("Error changing permissions of %s to 0660: %s",
457              SUPP_ENTROPY_FILE, strerror(errno));
458         unlink(SUPP_ENTROPY_FILE);
459         return -1;
460     }
461
462     if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) {
463         ALOGE("Error changing group ownership of %s to %d: %s",
464              SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno));
465         unlink(SUPP_ENTROPY_FILE);
466         return -1;
467     }
468     return 0;
469 }
470
471 int ensure_config_file_exists(const char *config_file)
472 {
473     char buf[2048];
474     int srcfd, destfd;
475     struct stat sb;
476     int nread;
477     int ret;
478
479     ret = access(config_file, R_OK|W_OK);
480     if ((ret == 0) || (errno == EACCES)) {
481         if ((ret != 0) &&
482             (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
483             ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno));
484             return -1;
485         }
486         return 0;
487     } else if (errno != ENOENT) {
488         ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno));
489         return -1;
490     }
491
492     srcfd = TEMP_FAILURE_RETRY(open(SUPP_CONFIG_TEMPLATE, O_RDONLY));
493     if (srcfd < 0) {
494         ALOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
495         return -1;
496     }
497
498     destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT|O_RDWR, 0660));
499     if (destfd < 0) {
500         close(srcfd);
501         ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno));
502         return -1;
503     }
504
505     while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) {
506         if (nread < 0) {
507             ALOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
508             close(srcfd);
509             close(destfd);
510             unlink(config_file);
511             return -1;
512         }
513         TEMP_FAILURE_RETRY(write(destfd, buf, nread));
514     }
515
516     close(destfd);
517     close(srcfd);
518
519     /* chmod is needed because open() didn't set permisions properly */
520     if (chmod(config_file, 0660) < 0) {
521         ALOGE("Error changing permissions of %s to 0660: %s",
522              config_file, strerror(errno));
523         unlink(config_file);
524         return -1;
525     }
526
527     if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) {
528         ALOGE("Error changing group ownership of %s to %d: %s",
529              config_file, AID_WIFI, strerror(errno));
530         unlink(config_file);
531         return -1;
532     }
533     return 0;
534 }
535
536 int wifi_start_supplicant(int p2p_supported)
537 {
538     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
539     int count = 200; /* wait at most 20 seconds for completion */
540     const prop_info *pi;
541     unsigned serial = 0, i;
542
543     if (p2p_supported) {
544         strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
545         strcpy(supplicant_prop_name, P2P_PROP_NAME);
546
547         /* Ensure p2p config file is created */
548         if (ensure_config_file_exists(P2P_CONFIG_FILE) < 0) {
549             ALOGE("Failed to create a p2p config file");
550             return -1;
551         }
552
553     } else {
554         strcpy(supplicant_name, SUPPLICANT_NAME);
555         strcpy(supplicant_prop_name, SUPP_PROP_NAME);
556     }
557
558     /* Check whether already running */
559     if (property_get(supplicant_prop_name, supp_status, NULL)
560             && strcmp(supp_status, "running") == 0) {
561         return 0;
562     }
563
564     /* Before starting the daemon, make sure its config file exists */
565     if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) {
566         ALOGE("Wi-Fi will not be enabled");
567         return -1;
568     }
569
570     if (ensure_entropy_file_exists() < 0) {
571         ALOGE("Wi-Fi entropy file was not created");
572     }
573
574     /* Clear out any stale socket files that might be left over. */
575     wpa_ctrl_cleanup();
576
577     /* Reset sockets used for exiting from hung state */
578     exit_sockets[0] = exit_sockets[1] = -1;
579
580     /*
581      * Get a reference to the status property, so we can distinguish
582      * the case where it goes stopped => running => stopped (i.e.,
583      * it start up, but fails right away) from the case in which
584      * it starts in the stopped state and never manages to start
585      * running at all.
586      */
587     pi = __system_property_find(supplicant_prop_name);
588     if (pi != NULL) {
589         serial = __system_property_serial(pi);
590     }
591     property_get("wlan.interface", primary_iface, WIFI_TEST_INTERFACE);
592
593     property_set("ctl.start", supplicant_name);
594     sched_yield();
595
596     while (count-- > 0) {
597         if (pi == NULL) {
598             pi = __system_property_find(supplicant_prop_name);
599         }
600         if (pi != NULL) {
601             /*
602              * property serial updated means that init process is scheduled
603              * after we sched_yield, further property status checking is based on this */
604             if (__system_property_serial(pi) != serial) {
605                 __system_property_read(pi, NULL, supp_status);
606                 if (strcmp(supp_status, "running") == 0) {
607                     return 0;
608                 } else if (strcmp(supp_status, "stopped") == 0) {
609                     return -1;
610                 }
611             }
612         }
613         usleep(100000);
614     }
615     return -1;
616 }
617
618 int wifi_stop_supplicant(int p2p_supported)
619 {
620     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
621     int count = 50; /* wait at most 5 seconds for completion */
622
623     if (p2p_supported) {
624         strcpy(supplicant_name, P2P_SUPPLICANT_NAME);
625         strcpy(supplicant_prop_name, P2P_PROP_NAME);
626     } else {
627         strcpy(supplicant_name, SUPPLICANT_NAME);
628         strcpy(supplicant_prop_name, SUPP_PROP_NAME);
629     }
630
631     /* Check whether supplicant already stopped */
632     if (property_get(supplicant_prop_name, supp_status, NULL)
633         && strcmp(supp_status, "stopped") == 0) {
634         return 0;
635     }
636
637     property_set("ctl.stop", supplicant_name);
638     sched_yield();
639
640     while (count-- > 0) {
641         if (property_get(supplicant_prop_name, supp_status, NULL)) {
642             if (strcmp(supp_status, "stopped") == 0)
643                 return 0;
644         }
645         usleep(100000);
646     }
647     ALOGE("Failed to stop supplicant");
648     return -1;
649 }
650
651 int wifi_connect_on_socket_path(const char *path)
652 {
653     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
654
655     /* Make sure supplicant is running */
656     if (!property_get(supplicant_prop_name, supp_status, NULL)
657             || strcmp(supp_status, "running") != 0) {
658         ALOGE("Supplicant not running, cannot connect");
659         return -1;
660     }
661
662     ctrl_conn = wpa_ctrl_open(path);
663     if (ctrl_conn == NULL) {
664         ALOGE("Unable to open connection to supplicant on \"%s\": %s",
665              path, strerror(errno));
666         return -1;
667     }
668     monitor_conn = wpa_ctrl_open(path);
669     if (monitor_conn == NULL) {
670         wpa_ctrl_close(ctrl_conn);
671         ctrl_conn = NULL;
672         return -1;
673     }
674     if (wpa_ctrl_attach(monitor_conn) != 0) {
675         wpa_ctrl_close(monitor_conn);
676         wpa_ctrl_close(ctrl_conn);
677         ctrl_conn = monitor_conn = NULL;
678         return -1;
679     }
680
681     if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
682         wpa_ctrl_close(monitor_conn);
683         wpa_ctrl_close(ctrl_conn);
684         ctrl_conn = monitor_conn = NULL;
685         return -1;
686     }
687
688     return 0;
689 }
690
691 /* Establishes the control and monitor socket connections on the interface */
692 int wifi_connect_to_supplicant()
693 {
694     static char path[PATH_MAX];
695
696     if (access(IFACE_DIR, F_OK) == 0) {
697         snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
698     } else {
699         snprintf(path, sizeof(path), "@android:wpa_%s", primary_iface);
700     }
701     return wifi_connect_on_socket_path(path);
702 }
703
704 int wifi_send_command(const char *cmd, char *reply, size_t *reply_len)
705 {
706     int ret;
707     if (ctrl_conn == NULL) {
708         ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
709         return -1;
710     }
711     ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), reply, reply_len, NULL);
712     if (ret == -2) {
713         ALOGD("'%s' command timed out.\n", cmd);
714         /* unblocks the monitor receive socket for termination */
715         TEMP_FAILURE_RETRY(write(exit_sockets[0], "T", 1));
716         return -2;
717     } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
718         return -1;
719     }
720     if (strncmp(cmd, "PING", 4) == 0) {
721         reply[*reply_len] = '\0';
722     }
723     return 0;
724 }
725
726 int wifi_supplicant_connection_active()
727 {
728     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
729
730     if (property_get(supplicant_prop_name, supp_status, NULL)) {
731         if (strcmp(supp_status, "stopped") == 0)
732             return -1;
733     }
734
735     return 0;
736 }
737
738 int wifi_ctrl_recv(char *reply, size_t *reply_len)
739 {
740     int res;
741     int ctrlfd = wpa_ctrl_get_fd(monitor_conn);
742     struct pollfd rfds[2];
743
744     memset(rfds, 0, 2 * sizeof(struct pollfd));
745     rfds[0].fd = ctrlfd;
746     rfds[0].events |= POLLIN;
747     rfds[1].fd = exit_sockets[1];
748     rfds[1].events |= POLLIN;
749     do {
750         res = TEMP_FAILURE_RETRY(poll(rfds, 2, 30000));
751         if (res < 0) {
752             ALOGE("Error poll = %d", res);
753             return res;
754         } else if (res == 0) {
755             /* timed out, check if supplicant is active
756              * or not ..
757              */
758             res = wifi_supplicant_connection_active();
759             if (res < 0)
760                 return -2;
761         }
762     } while (res == 0);
763
764     if (rfds[0].revents & POLLIN) {
765         return wpa_ctrl_recv(monitor_conn, reply, reply_len);
766     }
767
768     /* it is not rfds[0], then it must be rfts[1] (i.e. the exit socket)
769      * or we timed out. In either case, this call has failed ..
770      */
771     return -2;
772 }
773
774 int wifi_wait_on_socket(char *buf, size_t buflen)
775 {
776     size_t nread = buflen - 1;
777     int result;
778     char *match, *match2;
779
780     if (monitor_conn == NULL) {
781         return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
782                         primary_iface, WPA_EVENT_TERMINATING);
783     }
784
785     result = wifi_ctrl_recv(buf, &nread);
786
787     /* Terminate reception on exit socket */
788     if (result == -2) {
789         return snprintf(buf, buflen, "IFNAME=%s %s - connection closed",
790                         primary_iface, WPA_EVENT_TERMINATING);
791     }
792
793     if (result < 0) {
794         ALOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
795         return snprintf(buf, buflen, "IFNAME=%s %s - recv error",
796                         primary_iface, WPA_EVENT_TERMINATING);
797     }
798     buf[nread] = '\0';
799     /* Check for EOF on the socket */
800     if (result == 0 && nread == 0) {
801         /* Fabricate an event to pass up */
802         ALOGD("Received EOF on supplicant socket\n");
803         return snprintf(buf, buflen, "IFNAME=%s %s - signal 0 received",
804                         primary_iface, WPA_EVENT_TERMINATING);
805     }
806     /*
807      * Events strings are in the format
808      *
809      *     IFNAME=iface <N>CTRL-EVENT-XXX 
810      *        or
811      *     <N>CTRL-EVENT-XXX 
812      *
813      * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
814      * etc.) and XXX is the event name. The level information is not useful
815      * to us, so strip it off.
816      */
817
818     if (strncmp(buf, IFNAME, IFNAMELEN) == 0) {
819         match = strchr(buf, ' ');
820         if (match != NULL) {
821             if (match[1] == '<') {
822                 match2 = strchr(match + 2, '>');
823                 if (match2 != NULL) {
824                     nread -= (match2 - match);
825                     memmove(match + 1, match2 + 1, nread - (match - buf) + 1);
826                 }
827             }
828         } else {
829             return snprintf(buf, buflen, "%s", WPA_EVENT_IGNORE);
830         }
831     } else if (buf[0] == '<') {
832         match = strchr(buf, '>');
833         if (match != NULL) {
834             nread -= (match + 1 - buf);
835             memmove(buf, match + 1, nread + 1);
836             ALOGV("supplicant generated event without interface - %s\n", buf);
837         }
838     } else {
839         /* let the event go as is! */
840         ALOGW("supplicant generated event without interface and without message level - %s\n", buf);
841     }
842
843     return nread;
844 }
845
846 int wifi_wait_for_event(char *buf, size_t buflen)
847 {
848     return wifi_wait_on_socket(buf, buflen);
849 }
850
851 void wifi_close_sockets()
852 {
853     if (ctrl_conn != NULL) {
854         wpa_ctrl_close(ctrl_conn);
855         ctrl_conn = NULL;
856     }
857
858     if (monitor_conn != NULL) {
859         wpa_ctrl_close(monitor_conn);
860         monitor_conn = NULL;
861     }
862
863     if (exit_sockets[0] >= 0) {
864         close(exit_sockets[0]);
865         exit_sockets[0] = -1;
866     }
867
868     if (exit_sockets[1] >= 0) {
869         close(exit_sockets[1]);
870         exit_sockets[1] = -1;
871     }
872 }
873
874 void wifi_close_supplicant_connection()
875 {
876     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
877     int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */
878
879     wifi_close_sockets();
880
881     while (count-- > 0) {
882         if (property_get(supplicant_prop_name, supp_status, NULL)) {
883             if (strcmp(supp_status, "stopped") == 0)
884                 return;
885         }
886         usleep(100000);
887     }
888 }
889
890 int wifi_command(const char *command, char *reply, size_t *reply_len)
891 {
892     return wifi_send_command(command, reply, reply_len);
893 }
894
895 const char *wifi_get_fw_path(int fw_type)
896 {
897     switch (fw_type) {
898     case WIFI_GET_FW_PATH_STA:
899         return WIFI_DRIVER_FW_PATH_STA;
900     case WIFI_GET_FW_PATH_AP:
901         return WIFI_DRIVER_FW_PATH_AP;
902     case WIFI_GET_FW_PATH_P2P:
903         return WIFI_DRIVER_FW_PATH_P2P;
904     }
905     return NULL;
906 }
907
908 int wifi_change_fw_path(const char *fwpath)
909 {
910     int len;
911     int fd;
912     int ret = 0;
913
914     if (!fwpath)
915         return ret;
916     fd = TEMP_FAILURE_RETRY(open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY));
917     if (fd < 0) {
918         ALOGE("Failed to open wlan fw path param (%s)", strerror(errno));
919         return -1;
920     }
921     len = strlen(fwpath) + 1;
922     if (TEMP_FAILURE_RETRY(write(fd, fwpath, len)) != len) {
923         ALOGE("Failed to write wlan fw path param (%s)", strerror(errno));
924         ret = -1;
925     }
926     close(fd);
927     return ret;
928 }