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