OSDN Git Service

merge in ics-release history after reset to master
[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
23 #include "hardware_legacy/wifi.h"
24 #include "libwpa_client/wpa_ctrl.h"
25
26 #define LOG_TAG "WifiHW"
27 #include "cutils/log.h"
28 #include "cutils/memory.h"
29 #include "cutils/misc.h"
30 #include "cutils/properties.h"
31 #include "private/android_filesystem_config.h"
32 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
33 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
34 #include <sys/_system_properties.h>
35 #endif
36
37 static struct wpa_ctrl *ctrl_conn;
38 static struct wpa_ctrl *monitor_conn;
39
40 extern int do_dhcp();
41 extern int ifc_init();
42 extern void ifc_close();
43 extern char *dhcp_lasterror();
44 extern void get_dhcp_info();
45 extern int init_module(void *, unsigned long, const char *);
46 extern int delete_module(const char *, unsigned int);
47
48 static char iface[PROPERTY_VALUE_MAX];
49 // TODO: use new ANDROID_SOCKET mechanism, once support for multiple
50 // sockets is in
51
52 #ifndef WIFI_DRIVER_MODULE_ARG
53 #define WIFI_DRIVER_MODULE_ARG          ""
54 #endif
55 #ifndef WIFI_FIRMWARE_LOADER
56 #define WIFI_FIRMWARE_LOADER            ""
57 #endif
58 #define WIFI_TEST_INTERFACE             "sta"
59
60 #ifndef WIFI_DRIVER_FW_PATH_STA
61 #define WIFI_DRIVER_FW_PATH_STA         NULL
62 #endif
63 #ifndef WIFI_DRIVER_FW_PATH_AP
64 #define WIFI_DRIVER_FW_PATH_AP          NULL
65 #endif
66 #ifndef WIFI_DRIVER_FW_PATH_P2P
67 #define WIFI_DRIVER_FW_PATH_P2P         NULL
68 #endif
69
70 #ifndef WIFI_DRIVER_FW_PATH_PARAM
71 #define WIFI_DRIVER_FW_PATH_PARAM       "/sys/module/wlan/parameters/fwpath"
72 #endif
73
74 #define WIFI_DRIVER_LOADER_DELAY        1000000
75
76 static const char IFACE_DIR[]           = "/data/system/wpa_supplicant";
77 #ifdef WIFI_DRIVER_MODULE_PATH
78 static const char DRIVER_MODULE_NAME[]  = WIFI_DRIVER_MODULE_NAME;
79 static const char DRIVER_MODULE_TAG[]   = WIFI_DRIVER_MODULE_NAME " ";
80 static const char DRIVER_MODULE_PATH[]  = WIFI_DRIVER_MODULE_PATH;
81 static const char DRIVER_MODULE_ARG[]   = WIFI_DRIVER_MODULE_ARG;
82 #endif
83 static const char FIRMWARE_LOADER[]     = WIFI_FIRMWARE_LOADER;
84 static const char DRIVER_PROP_NAME[]    = "wlan.driver.status";
85 static const char SUPPLICANT_NAME[]     = "wpa_supplicant";
86 static const char SUPP_PROP_NAME[]      = "init.svc.wpa_supplicant";
87 static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf";
88 static const char SUPP_CONFIG_FILE[]    = "/data/misc/wifi/wpa_supplicant.conf";
89 static const char P2P_CONFIG_FILE[]     = "/data/misc/wifi/p2p_supplicant.conf";
90 static const char CONTROL_IFACE_PATH[]  = "/data/misc/wifi";
91 static const char MODULE_FILE[]         = "/proc/modules";
92
93 static const char SUPP_ENTROPY_FILE[]   = WIFI_ENTROPY_FILE;
94 static unsigned char dummy_key[20] = { 0x11, 0xbe, 0x33, 0x43, 0x35,
95                                        0x68, 0x47, 0x84, 0x99, 0xa9,
96                                        0x2b, 0x1c, 0xd3, 0xee, 0xff,
97                                        0xf1, 0xe2, 0xf3, 0xf4, 0xf5 };
98
99 static int insmod(const char *filename, const char *args)
100 {
101     void *module;
102     unsigned int size;
103     int ret;
104
105     module = load_file(filename, &size);
106     if (!module)
107         return -1;
108
109     ret = init_module(module, size, args);
110
111     free(module);
112
113     return ret;
114 }
115
116 static int rmmod(const char *modname)
117 {
118     int ret = -1;
119     int maxtry = 10;
120
121     while (maxtry-- > 0) {
122         ret = delete_module(modname, O_NONBLOCK | O_EXCL);
123         if (ret < 0 && errno == EAGAIN)
124             usleep(500000);
125         else
126             break;
127     }
128
129     if (ret != 0)
130         LOGD("Unable to unload driver module \"%s\": %s\n",
131              modname, strerror(errno));
132     return ret;
133 }
134
135 int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
136                     int *dns1, int *dns2, int *server, int *lease) {
137     /* For test driver, always report success */
138     if (strcmp(iface, WIFI_TEST_INTERFACE) == 0)
139         return 0;
140
141     if (ifc_init() < 0)
142         return -1;
143
144     if (do_dhcp(iface) < 0) {
145         ifc_close();
146         return -1;
147     }
148     ifc_close();
149     get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
150     return 0;
151 }
152
153 const char *get_dhcp_error_string() {
154     return dhcp_lasterror();
155 }
156
157 int is_wifi_driver_loaded() {
158     char driver_status[PROPERTY_VALUE_MAX];
159 #ifdef WIFI_DRIVER_MODULE_PATH
160     FILE *proc;
161     char line[sizeof(DRIVER_MODULE_TAG)+10];
162 #endif
163
164     if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
165             || strcmp(driver_status, "ok") != 0) {
166         return 0;  /* driver not loaded */
167     }
168 #ifdef WIFI_DRIVER_MODULE_PATH
169     /*
170      * If the property says the driver is loaded, check to
171      * make sure that the property setting isn't just left
172      * over from a previous manual shutdown or a runtime
173      * crash.
174      */
175     if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
176         LOGW("Could not open %s: %s", MODULE_FILE, strerror(errno));
177         property_set(DRIVER_PROP_NAME, "unloaded");
178         return 0;
179     }
180     while ((fgets(line, sizeof(line), proc)) != NULL) {
181         if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
182             fclose(proc);
183             return 1;
184         }
185     }
186     fclose(proc);
187     property_set(DRIVER_PROP_NAME, "unloaded");
188     return 0;
189 #else
190     return 1;
191 #endif
192 }
193
194 int wifi_load_driver()
195 {
196 #ifdef WIFI_DRIVER_MODULE_PATH
197     char driver_status[PROPERTY_VALUE_MAX];
198     int count = 100; /* wait at most 20 seconds for completion */
199
200     if (is_wifi_driver_loaded()) {
201         return 0;
202     }
203
204     if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
205         return -1;
206
207     if (strcmp(FIRMWARE_LOADER,"") == 0) {
208         /* usleep(WIFI_DRIVER_LOADER_DELAY); */
209         property_set(DRIVER_PROP_NAME, "ok");
210     }
211     else {
212         property_set("ctl.start", FIRMWARE_LOADER);
213     }
214     sched_yield();
215     while (count-- > 0) {
216         if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
217             if (strcmp(driver_status, "ok") == 0)
218                 return 0;
219             else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) {
220                 wifi_unload_driver();
221                 return -1;
222             }
223         }
224         usleep(200000);
225     }
226     property_set(DRIVER_PROP_NAME, "timeout");
227     wifi_unload_driver();
228     return -1;
229 #else
230     property_set(DRIVER_PROP_NAME, "ok");
231     return 0;
232 #endif
233 }
234
235 int wifi_unload_driver()
236 {
237     usleep(200000); /* allow to finish interface down */
238 #ifdef WIFI_DRIVER_MODULE_PATH
239     if (rmmod(DRIVER_MODULE_NAME) == 0) {
240         int count = 20; /* wait at most 10 seconds for completion */
241         while (count-- > 0) {
242             if (!is_wifi_driver_loaded())
243                 break;
244             usleep(500000);
245         }
246         usleep(500000); /* allow card removal */
247         if (count) {
248             return 0;
249         }
250         return -1;
251     } else
252         return -1;
253 #else
254     property_set(DRIVER_PROP_NAME, "unloaded");
255     return 0;
256 #endif
257 }
258
259 int ensure_entropy_file_exists()
260 {
261     int ret;
262     int destfd;
263
264     ret = access(SUPP_ENTROPY_FILE, R_OK|W_OK);
265     if ((ret == 0) || (errno == EACCES)) {
266         if ((ret != 0) &&
267             (chmod(SUPP_ENTROPY_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
268             LOGE("Cannot set RW to \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
269             return -1;
270         }
271         return 0;
272     }
273     destfd = open(SUPP_ENTROPY_FILE, O_CREAT|O_RDWR, 0660);
274     if (destfd < 0) {
275         LOGE("Cannot create \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
276         return -1;
277     }
278
279     if (write(destfd, dummy_key, sizeof(dummy_key)) != sizeof(dummy_key)) {
280         LOGE("Error writing \"%s\": %s", SUPP_ENTROPY_FILE, strerror(errno));
281         close(destfd);
282         return -1;
283     }
284     close(destfd);
285
286     /* chmod is needed because open() didn't set permisions properly */
287     if (chmod(SUPP_ENTROPY_FILE, 0660) < 0) {
288         LOGE("Error changing permissions of %s to 0660: %s",
289              SUPP_ENTROPY_FILE, strerror(errno));
290         unlink(SUPP_ENTROPY_FILE);
291         return -1;
292     }
293
294     if (chown(SUPP_ENTROPY_FILE, AID_SYSTEM, AID_WIFI) < 0) {
295         LOGE("Error changing group ownership of %s to %d: %s",
296              SUPP_ENTROPY_FILE, AID_WIFI, strerror(errno));
297         unlink(SUPP_ENTROPY_FILE);
298         return -1;
299     }
300     return 0;
301 }
302
303 int update_ctrl_interface(const char *config_file) {
304
305     int srcfd, destfd;
306     int nread;
307     char ifc[PROPERTY_VALUE_MAX];
308     char *pbuf;
309     char *sptr;
310     struct stat sb;
311
312     if (stat(config_file, &sb) != 0)
313         return -1;
314
315     pbuf = malloc(sb.st_size + PROPERTY_VALUE_MAX);
316     if (!pbuf)
317         return 0;
318     srcfd = open(config_file, O_RDONLY);
319     if (srcfd < 0) {
320         LOGE("Cannot open \"%s\": %s", config_file, strerror(errno));
321         free(pbuf);
322         return 0;
323     }
324     nread = read(srcfd, pbuf, sb.st_size);
325     close(srcfd);
326     if (nread < 0) {
327         LOGE("Cannot read \"%s\": %s", config_file, strerror(errno));
328         free(pbuf);
329         return 0;
330     }
331
332     if (!strcmp(config_file, SUPP_CONFIG_FILE)) {
333         property_get("wifi.interface", ifc, WIFI_TEST_INTERFACE);
334     } else {
335         strcpy(ifc, CONTROL_IFACE_PATH);
336     }
337     if ((sptr = strstr(pbuf, "ctrl_interface="))) {
338         char *iptr = sptr + strlen("ctrl_interface=");
339         int ilen = 0;
340         int mlen = strlen(ifc);
341         int nwrite;
342         if (strncmp(ifc, iptr, mlen) != 0) {
343             LOGE("ctrl_interface != %s", ifc);
344             while (((ilen + (iptr - pbuf)) < nread) && (iptr[ilen] != '\n'))
345                 ilen++;
346             mlen = ((ilen >= mlen) ? ilen : mlen) + 1;
347             memmove(iptr + mlen, iptr + ilen + 1, nread - (iptr + ilen + 1 - pbuf));
348             memset(iptr, '\n', mlen);
349             memcpy(iptr, ifc, strlen(ifc));
350             destfd = open(config_file, O_RDWR, 0660);
351             if (destfd < 0) {
352                 LOGE("Cannot update \"%s\": %s", config_file, strerror(errno));
353                 free(pbuf);
354                 return -1;
355             }
356             write(destfd, pbuf, nread + mlen - ilen -1);
357             close(destfd);
358         }
359     }
360     free(pbuf);
361     return 0;
362 }
363
364 int ensure_config_file_exists(const char *config_file)
365 {
366     char buf[2048];
367     int srcfd, destfd;
368     struct stat sb;
369     int nread;
370     int ret;
371
372     ret = access(config_file, R_OK|W_OK);
373     if ((ret == 0) || (errno == EACCES)) {
374         if ((ret != 0) &&
375             (chmod(config_file, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) != 0)) {
376             LOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno));
377             return -1;
378         }
379         /* return if filesize is at least 10 bytes */
380         if (stat(config_file, &sb) == 0 && sb.st_size > 10) {
381             return update_ctrl_interface(config_file);
382         }
383     } else if (errno != ENOENT) {
384         LOGE("Cannot access \"%s\": %s", config_file, strerror(errno));
385         return -1;
386     }
387
388     srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY);
389     if (srcfd < 0) {
390         LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
391         return -1;
392     }
393
394     destfd = open(config_file, O_CREAT|O_RDWR, 0660);
395     if (destfd < 0) {
396         close(srcfd);
397         LOGE("Cannot create \"%s\": %s", config_file, strerror(errno));
398         return -1;
399     }
400
401     while ((nread = read(srcfd, buf, sizeof(buf))) != 0) {
402         if (nread < 0) {
403             LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
404             close(srcfd);
405             close(destfd);
406             unlink(config_file);
407             return -1;
408         }
409         write(destfd, buf, nread);
410     }
411
412     close(destfd);
413     close(srcfd);
414
415     /* chmod is needed because open() didn't set permisions properly */
416     if (chmod(config_file, 0660) < 0) {
417         LOGE("Error changing permissions of %s to 0660: %s",
418              config_file, strerror(errno));
419         unlink(config_file);
420         return -1;
421     }
422
423     if (chown(config_file, AID_SYSTEM, AID_WIFI) < 0) {
424         LOGE("Error changing group ownership of %s to %d: %s",
425              config_file, AID_WIFI, strerror(errno));
426         unlink(config_file);
427         return -1;
428     }
429     return update_ctrl_interface(config_file);
430 }
431
432 /**
433  * wifi_wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
434  * may be left over from clients that were previously connected to
435  * wpa_supplicant. This keeps these files from being orphaned in the
436  * event of crashes that prevented them from being removed as part
437  * of the normal orderly shutdown.
438  */
439 void wifi_wpa_ctrl_cleanup(void)
440 {
441     DIR *dir;
442     struct dirent entry;
443     struct dirent *result;
444     size_t dirnamelen;
445     size_t maxcopy;
446     char pathname[PATH_MAX];
447     char *namep;
448     char *local_socket_dir = CONFIG_CTRL_IFACE_CLIENT_DIR;
449     char *local_socket_prefix = CONFIG_CTRL_IFACE_CLIENT_PREFIX;
450
451     if ((dir = opendir(local_socket_dir)) == NULL)
452         return;
453
454     dirnamelen = (size_t)snprintf(pathname, sizeof(pathname), "%s/", local_socket_dir);
455     if (dirnamelen >= sizeof(pathname)) {
456         closedir(dir);
457         return;
458     }
459     namep = pathname + dirnamelen;
460     maxcopy = PATH_MAX - dirnamelen;
461     while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
462         if (strncmp(entry.d_name, local_socket_prefix, strlen(local_socket_prefix)) == 0) {
463             if (strlcpy(namep, entry.d_name, maxcopy) < maxcopy) {
464                 unlink(pathname);
465             }
466         }
467     }
468     closedir(dir);
469 }
470
471 int wifi_start_supplicant_common(const char *config_file)
472 {
473     char daemon_cmd[PROPERTY_VALUE_MAX];
474     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
475     int count = 200; /* wait at most 20 seconds for completion */
476 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
477     const prop_info *pi;
478     unsigned serial = 0;
479 #endif
480
481     /* Check whether already running */
482     if (property_get(SUPP_PROP_NAME, supp_status, NULL)
483             && strcmp(supp_status, "running") == 0) {
484         return 0;
485     }
486
487     /* Before starting the daemon, make sure its config file exists */
488     if (ensure_config_file_exists(config_file) < 0) {
489         LOGE("Wi-Fi will not be enabled");
490         return -1;
491     }
492
493     if (ensure_entropy_file_exists() < 0) {
494         LOGE("Wi-Fi entropy file was not created");
495     }
496
497     /* Clear out any stale socket files that might be left over. */
498     wifi_wpa_ctrl_cleanup();
499
500 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
501     /*
502      * Get a reference to the status property, so we can distinguish
503      * the case where it goes stopped => running => stopped (i.e.,
504      * it start up, but fails right away) from the case in which
505      * it starts in the stopped state and never manages to start
506      * running at all.
507      */
508     pi = __system_property_find(SUPP_PROP_NAME);
509     if (pi != NULL) {
510         serial = pi->serial;
511     }
512 #endif
513     property_get("wifi.interface", iface, WIFI_TEST_INTERFACE);
514     snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s -c%s", SUPPLICANT_NAME, iface, config_file);
515     property_set("ctl.start", daemon_cmd);
516     sched_yield();
517
518     while (count-- > 0) {
519 #ifdef HAVE_LIBC_SYSTEM_PROPERTIES
520         if (pi == NULL) {
521             pi = __system_property_find(SUPP_PROP_NAME);
522         }
523         if (pi != NULL) {
524             __system_property_read(pi, NULL, supp_status);
525             if (strcmp(supp_status, "running") == 0) {
526                 return 0;
527             } else if (pi->serial != serial &&
528                     strcmp(supp_status, "stopped") == 0) {
529                 return -1;
530             }
531         }
532 #else
533         if (property_get(SUPP_PROP_NAME, supp_status, NULL)) {
534             if (strcmp(supp_status, "running") == 0)
535                 return 0;
536         }
537 #endif
538         usleep(100000);
539     }
540     return -1;
541 }
542
543 int wifi_start_supplicant()
544 {
545     return wifi_start_supplicant_common(SUPP_CONFIG_FILE);
546 }
547
548 int wifi_start_p2p_supplicant()
549 {
550     return wifi_start_supplicant_common(P2P_CONFIG_FILE);
551 }
552
553 int wifi_stop_supplicant()
554 {
555     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
556     int count = 50; /* wait at most 5 seconds for completion */
557
558     /* Check whether supplicant already stopped */
559     if (property_get(SUPP_PROP_NAME, supp_status, NULL)
560         && strcmp(supp_status, "stopped") == 0) {
561         return 0;
562     }
563
564     property_set("ctl.stop", SUPPLICANT_NAME);
565     sched_yield();
566
567     while (count-- > 0) {
568         if (property_get(SUPP_PROP_NAME, supp_status, NULL)) {
569             if (strcmp(supp_status, "stopped") == 0)
570                 return 0;
571         }
572         usleep(100000);
573     }
574     return -1;
575 }
576
577 int wifi_connect_to_supplicant()
578 {
579     char ifname[256];
580     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
581
582     /* Make sure supplicant is running */
583     if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
584             || strcmp(supp_status, "running") != 0) {
585         LOGE("Supplicant not running, cannot connect");
586         return -1;
587     }
588
589     if (access(IFACE_DIR, F_OK) == 0) {
590         snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface);
591     } else {
592         strlcpy(ifname, iface, sizeof(ifname));
593     }
594
595     ctrl_conn = wpa_ctrl_open(ifname);
596     if (ctrl_conn == NULL) {
597         LOGE("Unable to open connection to supplicant on \"%s\": %s",
598              ifname, strerror(errno));
599         return -1;
600     }
601     monitor_conn = wpa_ctrl_open(ifname);
602     if (monitor_conn == NULL) {
603         wpa_ctrl_close(ctrl_conn);
604         ctrl_conn = NULL;
605         return -1;
606     }
607     if (wpa_ctrl_attach(monitor_conn) != 0) {
608         wpa_ctrl_close(monitor_conn);
609         wpa_ctrl_close(ctrl_conn);
610         ctrl_conn = monitor_conn = NULL;
611         return -1;
612     }
613     return 0;
614 }
615
616 int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
617 {
618     int ret;
619
620     if (ctrl_conn == NULL) {
621         LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
622         return -1;
623     }
624     ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
625     if (ret == -2) {
626         LOGD("'%s' command timed out.\n", cmd);
627         return -2;
628     } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
629         return -1;
630     }
631     if (strncmp(cmd, "PING", 4) == 0) {
632         reply[*reply_len] = '\0';
633     }
634     return 0;
635 }
636
637 int wifi_wait_for_event(char *buf, size_t buflen)
638 {
639     size_t nread = buflen - 1;
640     int fd;
641     fd_set rfds;
642     int result;
643     struct timeval tval;
644     struct timeval *tptr;
645
646     if (monitor_conn == NULL) {
647         LOGD("Connection closed\n");
648         strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1);
649         buf[buflen-1] = '\0';
650         return strlen(buf);
651     }
652
653     result = wpa_ctrl_recv(monitor_conn, buf, &nread);
654     if (result < 0) {
655         LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno));
656         strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1);
657         buf[buflen-1] = '\0';
658         return strlen(buf);
659     }
660     buf[nread] = '\0';
661     /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */
662     /* Check for EOF on the socket */
663     if (result == 0 && nread == 0) {
664         /* Fabricate an event to pass up */
665         LOGD("Received EOF on supplicant socket\n");
666         strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1);
667         buf[buflen-1] = '\0';
668         return strlen(buf);
669     }
670     /*
671      * Events strings are in the format
672      *
673      *     <N>CTRL-EVENT-XXX 
674      *
675      * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
676      * etc.) and XXX is the event name. The level information is not useful
677      * to us, so strip it off.
678      */
679     if (buf[0] == '<') {
680         char *match = strchr(buf, '>');
681         if (match != NULL) {
682             nread -= (match+1-buf);
683             memmove(buf, match+1, nread+1);
684         }
685     }
686     return nread;
687 }
688
689 void wifi_close_supplicant_connection()
690 {
691     char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
692     int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */
693
694     if (ctrl_conn != NULL) {
695         wpa_ctrl_close(ctrl_conn);
696         ctrl_conn = NULL;
697     }
698     if (monitor_conn != NULL) {
699         wpa_ctrl_close(monitor_conn);
700         monitor_conn = NULL;
701     }
702
703     while (count-- > 0) {
704         if (property_get(SUPP_PROP_NAME, supp_status, NULL)) {
705             if (strcmp(supp_status, "stopped") == 0)
706                 return;
707         }
708         usleep(100000);
709     }
710 }
711
712 int wifi_command(const char *command, char *reply, size_t *reply_len)
713 {
714     return wifi_send_command(ctrl_conn, command, reply, reply_len);
715 }
716
717 const char *wifi_get_fw_path(int fw_type)
718 {
719     switch (fw_type) {
720     case WIFI_GET_FW_PATH_STA:
721         return WIFI_DRIVER_FW_PATH_STA;
722     case WIFI_GET_FW_PATH_AP:
723         return WIFI_DRIVER_FW_PATH_AP;
724     case WIFI_GET_FW_PATH_P2P:
725         return WIFI_DRIVER_FW_PATH_P2P;
726     }
727     return NULL;
728 }
729
730 int wifi_change_fw_path(const char *fwpath)
731 {
732     int len;
733     int fd;
734     int ret = 0;
735
736     if (!fwpath)
737         return ret;
738     fd = open(WIFI_DRIVER_FW_PATH_PARAM, O_WRONLY);
739     if (fd < 0) {
740         LOGE("Failed to open wlan fw path param (%s)", strerror(errno));
741         return -1;
742     }
743     len = strlen(fwpath) + 1;
744     if (write(fd, fwpath, len) != len) {
745         LOGE("Failed to write wlan fw path param (%s)", strerror(errno));
746         ret = -1;
747     }
748     close(fd);
749     return ret;
750 }