wifi.c revision 0e9f488e672abf0d14580261998cfd9c7211c112
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
22#include "hardware_legacy/wifi.h"
23#include "libwpa_client/wpa_ctrl.h"
24
25#define LOG_TAG "WifiHW"
26#include "cutils/log.h"
27#include "cutils/memory.h"
28#include "cutils/misc.h"
29#include "cutils/properties.h"
30#include "private/android_filesystem_config.h"
31#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
32#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
33#include <sys/_system_properties.h>
34#endif
35
36static struct wpa_ctrl *ctrl_conn;
37static struct wpa_ctrl *monitor_conn;
38
39extern int do_dhcp();
40extern int ifc_init();
41extern void ifc_close();
42extern char *dhcp_lasterror();
43extern void get_dhcp_info();
44extern int init_module(void *, unsigned long, const char *);
45extern int delete_module(const char *, unsigned int);
46
47static char iface[PROPERTY_VALUE_MAX];
48// TODO: use new ANDROID_SOCKET mechanism, once support for multiple
49// sockets is in
50
51#ifndef WIFI_DRIVER_MODULE_PATH
52#define WIFI_DRIVER_MODULE_PATH         "/system/lib/modules/wlan.ko"
53#endif
54#ifndef WIFI_DRIVER_MODULE_NAME
55#define WIFI_DRIVER_MODULE_NAME         "wlan"
56#endif
57#ifndef WIFI_DRIVER_MODULE_ARG
58#define WIFI_DRIVER_MODULE_ARG          ""
59#endif
60#ifndef WIFI_FIRMWARE_LOADER
61#define WIFI_FIRMWARE_LOADER		""
62#endif
63#define WIFI_TEST_INTERFACE		"sta"
64
65#define WIFI_DRIVER_LOADER_DELAY	1000000
66
67static const char IFACE_DIR[]           = "/data/system/wpa_supplicant";
68static const char DRIVER_MODULE_NAME[]  = WIFI_DRIVER_MODULE_NAME;
69static const char DRIVER_MODULE_TAG[]   = WIFI_DRIVER_MODULE_NAME " ";
70static const char DRIVER_MODULE_PATH[]  = WIFI_DRIVER_MODULE_PATH;
71static const char DRIVER_MODULE_ARG[]   = WIFI_DRIVER_MODULE_ARG;
72static const char FIRMWARE_LOADER[]     = WIFI_FIRMWARE_LOADER;
73static const char DRIVER_PROP_NAME[]    = "wlan.driver.status";
74static const char SUPPLICANT_NAME[]     = "wpa_supplicant";
75static const char SUPP_PROP_NAME[]      = "init.svc.wpa_supplicant";
76static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf";
77static const char SUPP_CONFIG_FILE[]    = "/data/misc/wifi/wpa_supplicant.conf";
78static const char MODULE_FILE[]         = "/proc/modules";
79
80static int insmod(const char *filename, const char *args)
81{
82    void *module;
83    unsigned int size;
84    int ret;
85
86    module = load_file(filename, &size);
87    if (!module)
88        return -1;
89
90    ret = init_module(module, size, args);
91
92    free(module);
93
94    return ret;
95}
96
97static int rmmod(const char *modname)
98{
99    int ret = -1;
100    int maxtry = 10;
101
102    while (maxtry-- > 0) {
103        ret = delete_module(modname, O_NONBLOCK | O_EXCL);
104        if (ret < 0 && errno == EAGAIN)
105            usleep(500000);
106        else
107            break;
108    }
109
110    if (ret != 0)
111        LOGD("Unable to unload driver module \"%s\": %s\n",
112             modname, strerror(errno));
113    return ret;
114}
115
116int do_dhcp_request(int *ipaddr, int *gateway, int *mask,
117                    int *dns1, int *dns2, int *server, int *lease) {
118    /* For test driver, always report success */
119    if (strcmp(iface, WIFI_TEST_INTERFACE) == 0)
120        return 0;
121
122    if (ifc_init() < 0)
123        return -1;
124
125    if (do_dhcp(iface) < 0) {
126        ifc_close();
127        return -1;
128    }
129    ifc_close();
130    get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease);
131    return 0;
132}
133
134const char *get_dhcp_error_string() {
135    return dhcp_lasterror();
136}
137
138int is_wifi_driver_loaded() {
139    char driver_status[PROPERTY_VALUE_MAX];
140    FILE *proc;
141    char line[sizeof(DRIVER_MODULE_TAG)+10];
142
143    if (!property_get(DRIVER_PROP_NAME, driver_status, NULL)
144            || strcmp(driver_status, "ok") != 0) {
145        return 0;  /* driver not loaded */
146    }
147    /*
148     * If the property says the driver is loaded, check to
149     * make sure that the property setting isn't just left
150     * over from a previous manual shutdown or a runtime
151     * crash.
152     */
153    if ((proc = fopen(MODULE_FILE, "r")) == NULL) {
154        LOGW("Could not open %s: %s", MODULE_FILE, strerror(errno));
155        property_set(DRIVER_PROP_NAME, "unloaded");
156        return 0;
157    }
158    while ((fgets(line, sizeof(line), proc)) != NULL) {
159        if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) {
160            fclose(proc);
161            return 1;
162        }
163    }
164    fclose(proc);
165    property_set(DRIVER_PROP_NAME, "unloaded");
166    return 0;
167}
168
169int wifi_load_driver()
170{
171    char driver_status[PROPERTY_VALUE_MAX];
172    int count = 100; /* wait at most 20 seconds for completion */
173
174    if (is_wifi_driver_loaded()) {
175        return 0;
176    }
177
178    if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0)
179        return -1;
180
181    if (strcmp(FIRMWARE_LOADER,"") == 0) {
182        /* usleep(WIFI_DRIVER_LOADER_DELAY); */
183        property_set(DRIVER_PROP_NAME, "ok");
184    }
185    else {
186        property_set("ctl.start", FIRMWARE_LOADER);
187    }
188    sched_yield();
189    while (count-- > 0) {
190        if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) {
191            if (strcmp(driver_status, "ok") == 0)
192                return 0;
193            else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) {
194                wifi_unload_driver();
195                return -1;
196            }
197        }
198        usleep(200000);
199    }
200    property_set(DRIVER_PROP_NAME, "timeout");
201    wifi_unload_driver();
202    return -1;
203}
204
205int wifi_unload_driver()
206{
207    int count = 20; /* wait at most 10 seconds for completion */
208
209    if (rmmod(DRIVER_MODULE_NAME) == 0) {
210        while (count-- > 0) {
211            if (!is_wifi_driver_loaded())
212                break;
213            usleep(500000);
214        }
215        if (count) {
216            return 0;
217        }
218        return -1;
219    } else
220        return -1;
221}
222
223int ensure_config_file_exists()
224{
225    char buf[2048];
226    char ifc[PROPERTY_VALUE_MAX];
227    char *sptr;
228    char *pbuf;
229    int srcfd, destfd;
230    struct stat sb;
231    int nread;
232
233    if (access(SUPP_CONFIG_FILE, R_OK|W_OK) == 0) {
234        /* return if filesize is at least 10 bytes */
235        if (stat(SUPP_CONFIG_FILE, &sb) == 0 && sb.st_size > 10) {
236            pbuf = malloc(sb.st_size + PROPERTY_VALUE_MAX);
237            if (!pbuf)
238                return 0;
239            srcfd = open(SUPP_CONFIG_FILE, O_RDONLY);
240            if (srcfd < 0) {
241                LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
242                free(pbuf);
243                return 0;
244            }
245            nread = read(srcfd, pbuf, sb.st_size);
246            close(srcfd);
247            if (nread < 0) {
248                LOGE("Cannot read \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
249                free(pbuf);
250                return 0;
251            }
252            property_get("wifi.interface", ifc, WIFI_TEST_INTERFACE);
253            if ((sptr = strstr(pbuf, "ctrl_interface="))) {
254                char *iptr = sptr + strlen("ctrl_interface=");
255                int ilen = 0;
256                int mlen = strlen(ifc);
257                if (strncmp(ifc, iptr, mlen) != 0) {
258                    LOGE("ctrl_interface != %s", ifc);
259                    while (((ilen + (iptr - pbuf)) < nread) && (iptr[ilen] != '\n'))
260                        ilen++;
261                    mlen = ((ilen >= mlen) ? ilen : mlen) + 1;
262                    memmove(iptr + mlen, iptr + ilen + 1, nread - (iptr + ilen + 1 - pbuf));
263                    memset(iptr, '\n', mlen);
264                    memcpy(iptr, ifc, strlen(ifc));
265                    destfd = open(SUPP_CONFIG_FILE, O_RDWR, 0660);
266                    if (destfd < 0) {
267                        LOGE("Cannot update \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
268                        free(pbuf);
269                        return -1;
270                    }
271                    write(destfd, pbuf, nread);
272                    close(destfd);
273                }
274            }
275            free(pbuf);
276            return 0;
277        }
278    } else if (errno != ENOENT) {
279        LOGE("Cannot access \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
280        return -1;
281    }
282
283    srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY);
284    if (srcfd < 0) {
285        LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
286        return -1;
287    }
288
289    destfd = open(SUPP_CONFIG_FILE, O_CREAT|O_RDWR, 0660);
290    if (destfd < 0) {
291        close(srcfd);
292        LOGE("Cannot create \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno));
293        return -1;
294    }
295
296    while ((nread = read(srcfd, buf, sizeof(buf))) != 0) {
297        if (nread < 0) {
298            LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno));
299            close(srcfd);
300            close(destfd);
301            unlink(SUPP_CONFIG_FILE);
302            return -1;
303        }
304        write(destfd, buf, nread);
305    }
306
307    close(destfd);
308    close(srcfd);
309
310    /* chmod is needed because open() didn't set permisions properly */
311    if (chmod(SUPP_CONFIG_FILE, 0660) < 0) {
312        LOGE("Error changing permissions of %s to 0660: %s",
313             SUPP_CONFIG_FILE, strerror(errno));
314        unlink(SUPP_CONFIG_FILE);
315        return -1;
316    }
317
318    if (chown(SUPP_CONFIG_FILE, AID_SYSTEM, AID_WIFI) < 0) {
319        LOGE("Error changing group ownership of %s to %d: %s",
320             SUPP_CONFIG_FILE, AID_WIFI, strerror(errno));
321        unlink(SUPP_CONFIG_FILE);
322        return -1;
323    }
324    return 0;
325}
326
327int wifi_start_supplicant()
328{
329    char daemon_cmd[PROPERTY_VALUE_MAX];
330    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
331    int count = 200; /* wait at most 20 seconds for completion */
332#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
333    const prop_info *pi;
334    unsigned serial = 0;
335#endif
336
337    /* Check whether already running */
338    if (property_get(SUPP_PROP_NAME, supp_status, NULL)
339            && strcmp(supp_status, "running") == 0) {
340        return 0;
341    }
342
343    /* Before starting the daemon, make sure its config file exists */
344    if (ensure_config_file_exists() < 0) {
345        LOGE("Wi-Fi will not be enabled");
346        return -1;
347    }
348
349    /* Clear out any stale socket files that might be left over. */
350    wpa_ctrl_cleanup();
351
352#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
353    /*
354     * Get a reference to the status property, so we can distinguish
355     * the case where it goes stopped => running => stopped (i.e.,
356     * it start up, but fails right away) from the case in which
357     * it starts in the stopped state and never manages to start
358     * running at all.
359     */
360    pi = __system_property_find(SUPP_PROP_NAME);
361    if (pi != NULL) {
362        serial = pi->serial;
363    }
364#endif
365    property_get("wifi.interface", iface, WIFI_TEST_INTERFACE);
366    snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s", SUPPLICANT_NAME, iface);
367    property_set("ctl.start", daemon_cmd);
368    sched_yield();
369
370    while (count-- > 0) {
371#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
372        if (pi == NULL) {
373            pi = __system_property_find(SUPP_PROP_NAME);
374        }
375        if (pi != NULL) {
376            __system_property_read(pi, NULL, supp_status);
377            if (strcmp(supp_status, "running") == 0) {
378                return 0;
379            } else if (pi->serial != serial &&
380                    strcmp(supp_status, "stopped") == 0) {
381                return -1;
382            }
383        }
384#else
385        if (property_get(SUPP_PROP_NAME, supp_status, NULL)) {
386            if (strcmp(supp_status, "running") == 0)
387                return 0;
388        }
389#endif
390        usleep(100000);
391    }
392    return -1;
393}
394
395int wifi_stop_supplicant()
396{
397    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
398    int count = 50; /* wait at most 5 seconds for completion */
399
400    /* Check whether supplicant already stopped */
401    if (property_get(SUPP_PROP_NAME, supp_status, NULL)
402        && strcmp(supp_status, "stopped") == 0) {
403        return 0;
404    }
405
406    property_set("ctl.stop", SUPPLICANT_NAME);
407    sched_yield();
408
409    while (count-- > 0) {
410        if (property_get(SUPP_PROP_NAME, supp_status, NULL)) {
411            if (strcmp(supp_status, "stopped") == 0)
412                return 0;
413        }
414        usleep(100000);
415    }
416    return -1;
417}
418
419int wifi_connect_to_supplicant()
420{
421    char ifname[256];
422    char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
423
424    /* Make sure supplicant is running */
425    if (!property_get(SUPP_PROP_NAME, supp_status, NULL)
426            || strcmp(supp_status, "running") != 0) {
427        LOGE("Supplicant not running, cannot connect");
428        return -1;
429    }
430
431    if (access(IFACE_DIR, F_OK) == 0) {
432        snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface);
433    } else {
434        strlcpy(ifname, iface, sizeof(ifname));
435    }
436
437    ctrl_conn = wpa_ctrl_open(ifname);
438    if (ctrl_conn == NULL) {
439        LOGE("Unable to open connection to supplicant on \"%s\": %s",
440             ifname, strerror(errno));
441        return -1;
442    }
443    monitor_conn = wpa_ctrl_open(ifname);
444    if (monitor_conn == NULL) {
445        wpa_ctrl_close(ctrl_conn);
446        ctrl_conn = NULL;
447        return -1;
448    }
449    if (wpa_ctrl_attach(monitor_conn) != 0) {
450        wpa_ctrl_close(monitor_conn);
451        wpa_ctrl_close(ctrl_conn);
452        ctrl_conn = monitor_conn = NULL;
453        return -1;
454    }
455    return 0;
456}
457
458int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
459{
460    int ret;
461
462    if (ctrl_conn == NULL) {
463        LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
464        return -1;
465    }
466    ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
467    if (ret == -2) {
468        LOGD("'%s' command timed out.\n", cmd);
469        return -2;
470    } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
471        return -1;
472    }
473    if (strncmp(cmd, "PING", 4) == 0) {
474        reply[*reply_len] = '\0';
475    }
476    return 0;
477}
478
479int wifi_wait_for_event(char *buf, size_t buflen)
480{
481    size_t nread = buflen - 1;
482    int fd;
483    fd_set rfds;
484    int result;
485    struct timeval tval;
486    struct timeval *tptr;
487
488    if (monitor_conn == NULL) {
489        LOGD("Connection closed\n");
490        strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1);
491        buf[buflen-1] = '\0';
492        return strlen(buf);
493    }
494
495    result = wpa_ctrl_recv(monitor_conn, buf, &nread);
496    if (result < 0) {
497        LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno));
498        strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1);
499        buf[buflen-1] = '\0';
500        return strlen(buf);
501    }
502    buf[nread] = '\0';
503    /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */
504    /* Check for EOF on the socket */
505    if (result == 0 && nread == 0) {
506        /* Fabricate an event to pass up */
507        LOGD("Received EOF on supplicant socket\n");
508        strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1);
509        buf[buflen-1] = '\0';
510        return strlen(buf);
511    }
512    /*
513     * Events strings are in the format
514     *
515     *     <N>CTRL-EVENT-XXX
516     *
517     * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG,
518     * etc.) and XXX is the event name. The level information is not useful
519     * to us, so strip it off.
520     */
521    if (buf[0] == '<') {
522        char *match = strchr(buf, '>');
523        if (match != NULL) {
524            nread -= (match+1-buf);
525            memmove(buf, match+1, nread+1);
526        }
527    }
528    return nread;
529}
530
531void wifi_close_supplicant_connection()
532{
533    if (ctrl_conn != NULL) {
534        wpa_ctrl_close(ctrl_conn);
535        ctrl_conn = NULL;
536    }
537    if (monitor_conn != NULL) {
538        wpa_ctrl_close(monitor_conn);
539        monitor_conn = NULL;
540    }
541}
542
543int wifi_command(const char *command, char *reply, size_t *reply_len)
544{
545    return wifi_send_command(ctrl_conn, command, reply, reply_len);
546}
547