?? wifi.c
字號:
/* * Copyright 2008, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <stdlib.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include "hardware/wifi.h"#include "libwpa_client/wpa_ctrl.h"#define LOG_TAG "WifiHW"#include "cutils/log.h"#include "cutils/memory.h"#include "cutils/misc.h"#include "cutils/properties.h"#include "private/android_filesystem_config.h"static struct wpa_ctrl *ctrl_conn;static struct wpa_ctrl *monitor_conn;extern int do_dhcp();extern int ifc_init();extern void ifc_close();extern char *dhcp_lasterror();extern void get_dhcp_info();extern int init_module(void *, unsigned long, const char *);extern int delete_module(const char *, unsigned int);static char iface[PROPERTY_VALUE_MAX];// TODO: use new ANDROID_SOCKET mechanism, once support for multiple// sockets is instatic const char IFACE_DIR[] = "/data/system/wpa_supplicant";static const char DRIVER_MODULE_NAME[] = "wlan";static const char DRIVER_MODULE_TAG[] = "wlan ";static const char DRIVER_MODULE_PATH[] = "/system/lib/modules/wlan.ko";static const char FIRMWARE_LOADER[] = "wlan_loader";static const char DRIVER_PROP_NAME[] = "wlan.driver.status";static const char SUPPLICANT_NAME[] = "wpa_supplicant";static const char SUPP_PROP_NAME[] = "init.svc.wpa_supplicant";static const char SUPP_CONFIG_TEMPLATE[]= "/system/etc/wifi/wpa_supplicant.conf";static const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf";static const char MODULE_FILE[] = "/proc/modules";static int insmod(const char *filename){ void *module; unsigned int size; int ret; module = load_file(filename, &size); if (!module) return -1; ret = init_module(module, size, ""); free(module); return ret;}static int rmmod(const char *modname){ int ret = -1; int maxtry = 10; while (maxtry-- > 0) { ret = delete_module(modname, O_NONBLOCK | O_EXCL); if (ret < 0 && errno == EAGAIN) usleep(500000); else break; } if (ret != 0) LOGD("Unable to unload driver module \"%s\": %s\n", modname, strerror(errno)); return ret;}int do_dhcp_request(int *ipaddr, int *gateway, int *mask, int *dns1, int *dns2, int *server, int *lease) { /* For test driver, always report success */ if (strcmp(iface, "sta") == 0) return 0; if (ifc_init() < 0) return -1; if (do_dhcp(iface) < 0) { ifc_close(); return -1; } ifc_close(); get_dhcp_info(ipaddr, gateway, mask, dns1, dns2, server, lease); return 0;}const char *get_dhcp_error_string() { return dhcp_lasterror();}static int check_driver_loaded() { char driver_status[PROPERTY_VALUE_MAX]; FILE *proc; char line[sizeof(DRIVER_MODULE_TAG)+10]; if (!property_get(DRIVER_PROP_NAME, driver_status, NULL) || strcmp(driver_status, "ok") != 0) { return 0; /* driver not loaded */ } /* * If the property says the driver is loaded, check to * make sure that the property setting isn't just left * over from a previous manual shutdown or a runtime * crash. */ if ((proc = fopen(MODULE_FILE, "r")) == NULL) { LOGW("Could not open %s: %s", MODULE_FILE, strerror(errno)); return 0; } while ((fgets(line, sizeof(line), proc)) != NULL) { if (strncmp(line, DRIVER_MODULE_TAG, strlen(DRIVER_MODULE_TAG)) == 0) { fclose(proc); return 1; } } fclose(proc); property_set(DRIVER_PROP_NAME, "unloaded"); return 0;}int wifi_load_driver(){ char driver_status[PROPERTY_VALUE_MAX]; int count = 40; /* wait at most 20 seconds for completion */ if (check_driver_loaded()) { return 0; } insmod(DRIVER_MODULE_PATH); property_set("ctl.start", FIRMWARE_LOADER); while (count-- > 0) { usleep(500000); if (property_get(DRIVER_PROP_NAME, driver_status, NULL)) { if (strcmp(driver_status, "ok") == 0) return 0; else if (strcmp(DRIVER_PROP_NAME, "failed") == 0) return -1; } } property_set(DRIVER_PROP_NAME, "timeout"); return -1;}int wifi_unload_driver(){ if (rmmod(DRIVER_MODULE_NAME) == 0) { usleep(1000000); property_set(DRIVER_PROP_NAME, "unloaded"); return 0; } else return -1;}static int control_supplicant(int startIt){ char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; const char *ctrl_prop = (startIt ? "ctl.start" : "ctl.stop"); const char *desired_status = (startIt ? "running" : "stopped"); int count = 20; /* wait at most 20 seconds for completion */ if (property_get(SUPP_PROP_NAME, supp_status, NULL) && strcmp(supp_status, desired_status) == 0) { return 0; /* supplicant already running */ } property_set(ctrl_prop, SUPPLICANT_NAME); while (count-- > 0) { usleep(1000000); if (property_get(SUPP_PROP_NAME, supp_status, NULL)) { if (strcmp(supp_status, desired_status) == 0) return 0; } } return -1;}int ensure_config_file_exists(){ char buf[2048]; int srcfd, destfd; int nread; if (access(SUPP_CONFIG_FILE, R_OK|W_OK) == 0) { return 0; } else if (errno != ENOENT) { LOGE("Cannot access \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); return -1; } srcfd = open(SUPP_CONFIG_TEMPLATE, O_RDONLY); if (srcfd < 0) { LOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); return -1; } destfd = open(SUPP_CONFIG_FILE, O_CREAT|O_WRONLY, 0660); if (destfd < 0) { close(srcfd); LOGE("Cannot create \"%s\": %s", SUPP_CONFIG_FILE, strerror(errno)); return -1; } while ((nread = read(srcfd, buf, sizeof(buf))) != 0) { if (nread < 0) { LOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); close(srcfd); close(destfd); unlink(SUPP_CONFIG_FILE); return -1; } write(destfd, buf, nread); } close(destfd); close(srcfd); if (chown(SUPP_CONFIG_FILE, AID_SYSTEM, AID_WIFI) < 0) { LOGE("Error changing group ownership of %s to %d: %s", SUPP_CONFIG_FILE, AID_WIFI, strerror(errno)); unlink(SUPP_CONFIG_FILE); return -1; } return 0;}int wifi_start_supplicant(){ /* Before starting the daemon, make sure its config file exists */ if (ensure_config_file_exists() < 0) { LOGE("Wi-Fi will not be enabled"); return -1; } return control_supplicant(1);}int wifi_stop_supplicant(){ return control_supplicant(0);}int wifi_connect_to_supplicant(){ char ifname[256]; static int cleaned_up = 0; property_get("wifi.interface", iface, "sta"); if (access(IFACE_DIR, F_OK) == 0) { snprintf(ifname, sizeof(ifname), "%s/%s", IFACE_DIR, iface); } else { strlcpy(ifname, iface, sizeof(ifname)); } ctrl_conn = wpa_ctrl_open(ifname); if (ctrl_conn == NULL) { LOGD("Unable to open connection to supplicant on \"%s\": %s", ifname, strerror(errno)); /* * errno == ENOENT means the supplicant daemon isn't * running. Take this opportunity to clear out any * stale socket files that might be left over. Note * there's a possible race with the command line client * trying to connect to the daemon, but it would require * that the supplicant be started and the command line * client connect to it during the window between the * error check and the removal of the files. And in * any event, the remedy is that the user would simply * have to run the command line program again. */ if (!cleaned_up && (errno == ENOENT || errno == EADDRINUSE)) { cleaned_up = 1; /* do this just once */ wpa_ctrl_cleanup(); } return -1; } monitor_conn = wpa_ctrl_open(ifname); if (monitor_conn == NULL) { wpa_ctrl_close(ctrl_conn); ctrl_conn = NULL; return -1; } if (wpa_ctrl_attach(monitor_conn) != 0) { wpa_ctrl_close(monitor_conn); wpa_ctrl_close(ctrl_conn); ctrl_conn = monitor_conn = NULL; return -1; } return 0;}int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len){ int ret; if (ctrl_conn == NULL) { LOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd); return -1; } ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL); if (ret == -2) { LOGD("'%s' command timed out.\n", cmd); return -2; } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) { return -1; } if (strncmp(cmd, "PING", 4) == 0) { reply[*reply_len] = '\0'; } return 0;}int wifi_wait_for_event(char *buf, size_t buflen){ size_t nread = buflen - 1; int fd; fd_set rfds; int result; struct timeval tval; struct timeval *tptr; if (monitor_conn == NULL) return 0; result = wpa_ctrl_recv(monitor_conn, buf, &nread); if (result < 0) { LOGD("wpa_ctrl_recv failed: %s\n", strerror(errno)); return -1; } buf[nread] = '\0'; /* LOGD("wait_for_event: result=%d nread=%d string=\"%s\"\n", result, nread, buf); */ /* Check for EOF on the socket */ if (result == 0 && nread == 0) { /* Fabricate an event to pass up */ LOGD("Received EOF on supplicant socket\n"); strncpy(buf, WPA_EVENT_TERMINATING " - signal 0 received", buflen-1); buf[buflen-1] = '\0'; return strlen(buf); } /* * Events strings are in the format * * <N>CTRL-EVENT-XXX * * where N is the message level in numerical form (0=VERBOSE, 1=DEBUG, * etc.) and XXX is the event name. The level information is not useful * to us, so strip it off. */ if (buf[0] == '<') { char *match = strchr(buf, '>'); if (match != NULL) { nread -= (match+1-buf); memmove(buf, match+1, nread+1); } } return nread;}void wifi_close_supplicant_connection(){ if (ctrl_conn != NULL) { wpa_ctrl_close(ctrl_conn); ctrl_conn = NULL; } if (monitor_conn != NULL) { wpa_ctrl_close(monitor_conn); monitor_conn = NULL; }}int wifi_command(const char *command, char *reply, size_t *reply_len){ return wifi_send_command(ctrl_conn, command, reply, reply_len);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -