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