diff --git a/include/hardware_legacy/wifi.h b/include/hardware_legacy/wifi.h
index 4166a6d..26a3912 100644
--- a/include/hardware_legacy/wifi.h
+++ b/include/hardware_legacy/wifi.h
@@ -65,24 +65,25 @@ int wifi_start_p2p_supplicant();
int wifi_stop_supplicant();
/**
- * Open a connection to supplicant.
+ * Open a connection to supplicant on interface
*
* @return 0 on success, < 0 on failure.
*/
-int wifi_connect_to_supplicant();
+int wifi_connect_to_supplicant(const char *ifname);
/**
- * Close connection supplicant.
+ * Close connection to supplicant on interface
*
* @return 0 on success, < 0 on failure.
*/
-void wifi_close_supplicant_connection();
+void wifi_close_supplicant_connection(const char *ifname);
/**
* wifi_wait_for_event() performs a blocking call to
* get a Wi-Fi event and returns a string representing
* a Wi-Fi event when it occurs.
*
+ * @param iface is the interface on which event is received
* @param buf is the buffer that receives the event
* @param len is the maximum length of the buffer
*
@@ -90,61 +91,19 @@ void wifi_close_supplicant_connection();
* event (for instance, no connection), and less than 0
* if there is an error.
*/
-int wifi_wait_for_event(char *buf, size_t len);
+int wifi_wait_for_event(const char *iface, char *buf, size_t len);
/**
* wifi_command() issues a command to the Wi-Fi driver.
*
- * Android extends the standard commands listed at
- * /link http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html
+ * Android extends the standard commands listed at
+ * /link http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html
* to include support for sending commands to the driver:
*
- *
- *
- * Command / Command summary |
- * Form of Response |
- * Processing |
- *
- *
- * DRIVER START Turn on Wi-Fi Hardware |
- * OK if successful |
- * OK ? true : false |
- *
- *
- * DRIVER STOP Turn off Wi-Fi hardware |
- * OK if successful |
- * OK ? true : false |
- *
- *
- * DRIVER RSSI Return received signal strength indicator in -db for current AP |
- * <ssid> Rssi xx |
- * %*s %*s %d", &rssi |
- *
- *
- * DRIVER LINKSPEED Return link speed in MBPS |
- * LinkSpeed xx |
- * %*s %d", &linkspd |
- *
- *
- * DRIVER MACADDR Return mac address of the station |
- * Macaddr = xx.xx.xx.xx.xx.xx |
- * "%*s = %s", &macadr |
- *
- *
- * DRIVER SCAN-ACTIVE Set scan type to active |
- * "OK" if successful |
- * "OK" ? true : false |
- *
- *
- * DRIVER SCAN-PASSIVE Set scan type to passive |
- * "OK" if successful |
- * "OK" ? true : false |
- *
- *
- *
- * See libs/android_runtime/android_net_wifi_Wifi.cpp for more information
- * describing how these and other commands are invoked.
+ * See wifi/java/android/net/wifi/WifiNative.java for the details of
+ * driver commands that are supported
*
+ * @param iface is the interface on which command is sent
* @param command is the string command
* @param reply is a buffer to receive a reply string
* @param reply_len on entry, this is the maximum length of
@@ -153,7 +112,7 @@ int wifi_wait_for_event(char *buf, size_t len);
*
* @return 0 if successful, < 0 if an error.
*/
-int wifi_command(const char *command, char *reply, size_t *reply_len);
+int wifi_command(const char *iface, const char *command, char *reply, size_t *reply_len);
/**
* do_dhcp_request() issues a dhcp request and returns the acquired
diff --git a/wifi/wifi.c b/wifi/wifi.c
index fc8f54e..dd216f1 100644
--- a/wifi/wifi.c
+++ b/wifi/wifi.c
@@ -36,10 +36,21 @@
#include
#endif
-static struct wpa_ctrl *ctrl_conn;
-static struct wpa_ctrl *monitor_conn;
+/* PRIMARY refers to the connection on the primary interface
+ * SECONDARY refers to an optional connection on a p2p interface
+ *
+ * For concurrency, we only support one active p2p connection and
+ * one active STA connection at a time
+ */
+#define PRIMARY 0
+#define SECONDARY 1
+#define MAX_CONNS 2
+
+static struct wpa_ctrl *ctrl_conn[MAX_CONNS];
+static struct wpa_ctrl *monitor_conn[MAX_CONNS];
+
/* socket pair used to exit from a blocking read */
-static int exit_sockets[2] = { -1, -1 };
+static int exit_sockets[MAX_CONNS][2];
extern int do_dhcp();
extern int ifc_init();
@@ -49,7 +60,7 @@ 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];
+static char primary_iface[PROPERTY_VALUE_MAX];
// TODO: use new ANDROID_SOCKET mechanism, once support for multiple
// sockets is in
@@ -100,6 +111,16 @@ static unsigned char dummy_key[21] = { 0x02, 0x11, 0xbe, 0x33, 0x43, 0x35,
0x1c, 0xd3, 0xee, 0xff, 0xf1, 0xe2,
0xf3, 0xf4, 0xf5 };
+static int is_primary_interface(const char *ifname)
+{
+ //Treat NULL as primary interface to allow control
+ //on STA without an interface
+ if (ifname == NULL || !strncmp(ifname, primary_iface, strlen(primary_iface))) {
+ return 1;
+ }
+ return 0;
+}
+
static int insmod(const char *filename, const char *args)
{
void *module;
@@ -139,13 +160,13 @@ static int rmmod(const char *modname)
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, WIFI_TEST_INTERFACE) == 0)
+ if (strcmp(primary_iface, WIFI_TEST_INTERFACE) == 0)
return 0;
if (ifc_init() < 0)
return -1;
- if (do_dhcp(iface) < 0) {
+ if (do_dhcp(primary_iface) < 0) {
ifc_close();
return -1;
}
@@ -479,7 +500,7 @@ int wifi_start_supplicant_common(const char *config_file)
int count = 200; /* wait at most 20 seconds for completion */
#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
const prop_info *pi;
- unsigned serial = 0;
+ unsigned serial = 0, i;
#endif
/* Check whether already running */
@@ -501,6 +522,11 @@ int wifi_start_supplicant_common(const char *config_file)
/* Clear out any stale socket files that might be left over. */
wifi_wpa_ctrl_cleanup();
+ /* Reset sockets used for exiting from hung state */
+ for (i=0; iserial;
}
#endif
- property_get("wifi.interface", iface, WIFI_TEST_INTERFACE);
- snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s -c%s", SUPPLICANT_NAME, iface, config_file);
+ property_get("wifi.interface", primary_iface, WIFI_TEST_INTERFACE);
+ snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s -c%s", SUPPLICANT_NAME, primary_iface,
+ config_file);
property_set("ctl.start", daemon_cmd);
sched_yield();
@@ -578,9 +605,8 @@ int wifi_stop_supplicant()
return -1;
}
-int wifi_connect_to_supplicant()
+int wifi_connect_on_socket_path(int index, const char *path)
{
- char ifname[256];
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
/* Make sure supplicant is running */
@@ -590,54 +616,66 @@ int wifi_connect_to_supplicant()
return -1;
}
- 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) {
+ ctrl_conn[index] = wpa_ctrl_open(path);
+ if (ctrl_conn[index] == NULL) {
LOGE("Unable to open connection to supplicant on \"%s\": %s",
- ifname, strerror(errno));
+ path, strerror(errno));
return -1;
}
- monitor_conn = wpa_ctrl_open(ifname);
- if (monitor_conn == NULL) {
- wpa_ctrl_close(ctrl_conn);
- ctrl_conn = NULL;
+ monitor_conn[index] = wpa_ctrl_open(path);
+ if (monitor_conn[index] == NULL) {
+ wpa_ctrl_close(ctrl_conn[index]);
+ ctrl_conn[index] = 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;
+ if (wpa_ctrl_attach(monitor_conn[index]) != 0) {
+ wpa_ctrl_close(monitor_conn[index]);
+ wpa_ctrl_close(ctrl_conn[index]);
+ ctrl_conn[index] = monitor_conn[index] = NULL;
return -1;
}
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets) == -1) {
- wpa_ctrl_close(monitor_conn);
- wpa_ctrl_close(ctrl_conn);
- ctrl_conn = monitor_conn = NULL;
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, exit_sockets[index]) == -1) {
+ wpa_ctrl_close(monitor_conn[index]);
+ wpa_ctrl_close(ctrl_conn[index]);
+ ctrl_conn[index] = monitor_conn[index] = NULL;
return -1;
}
return 0;
}
-int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_t *reply_len)
+/* Establishes the control and monitor socket connections on the interface */
+int wifi_connect_to_supplicant(const char *ifname)
+{
+ char path[256];
+
+ if (is_primary_interface(ifname)) {
+ if (access(IFACE_DIR, F_OK) == 0) {
+ snprintf(path, sizeof(path), "%s/%s", IFACE_DIR, primary_iface);
+ } else {
+ strlcpy(path, primary_iface, sizeof(path));
+ }
+ return wifi_connect_on_socket_path(PRIMARY, path);
+ } else {
+ sprintf(path, "%s/%s", CONTROL_IFACE_PATH, ifname);
+ return wifi_connect_on_socket_path(SECONDARY, path);
+ }
+}
+
+int wifi_send_command(int index, const char *cmd, char *reply, size_t *reply_len)
{
int ret;
- if (ctrl_conn == NULL) {
+ if (ctrl_conn[index] == NULL) {
ALOGV("Not connected to wpa_supplicant - \"%s\" command dropped.\n", cmd);
return -1;
}
- ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, NULL);
+ ret = wpa_ctrl_request(ctrl_conn[index], cmd, strlen(cmd), reply, reply_len, NULL);
if (ret == -2) {
LOGD("'%s' command timed out.\n", cmd);
/* unblocks the monitor receive socket for termination */
- write(exit_sockets[0], "T", 1);
+ write(exit_sockets[index][0], "T", 1);
return -2;
} else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
return -1;
@@ -648,16 +686,16 @@ int wifi_send_command(struct wpa_ctrl *ctrl, const char *cmd, char *reply, size_
return 0;
}
-int wifi_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+int wifi_ctrl_recv(int index, char *reply, size_t *reply_len)
{
int res;
- int ctrlfd = wpa_ctrl_get_fd(ctrl);
+ int ctrlfd = wpa_ctrl_get_fd(ctrl_conn[index]);
struct pollfd rfds[2];
memset(rfds, 0, 2 * sizeof(struct pollfd));
rfds[0].fd = ctrlfd;
rfds[0].events |= POLLIN;
- rfds[1].fd = exit_sockets[1];
+ rfds[1].fd = exit_sockets[index][1];
rfds[1].events |= POLLIN;
res = poll(rfds, 2, -1);
if (res < 0) {
@@ -665,7 +703,7 @@ int wifi_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
return res;
}
if (rfds[0].revents & POLLIN) {
- return wpa_ctrl_recv(ctrl, reply, reply_len);
+ return wpa_ctrl_recv(monitor_conn[index], reply, reply_len);
} else {
LOGD("Received on exit socket, terminate");
return -1;
@@ -673,7 +711,7 @@ int wifi_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
return 0;
}
-int wifi_wait_for_event(char *buf, size_t buflen)
+int wifi_wait_on_socket(int index, char *buf, size_t buflen)
{
size_t nread = buflen - 1;
int fd;
@@ -682,14 +720,14 @@ int wifi_wait_for_event(char *buf, size_t buflen)
struct timeval tval;
struct timeval *tptr;
- if (monitor_conn == NULL) {
+ if (monitor_conn[index] == NULL) {
LOGD("Connection closed\n");
strncpy(buf, WPA_EVENT_TERMINATING " - connection closed", buflen-1);
buf[buflen-1] = '\0';
return strlen(buf);
}
- result = wifi_ctrl_recv(monitor_conn, buf, &nread);
+ result = wifi_ctrl_recv(index, buf, &nread);
if (result < 0) {
LOGD("wifi_ctrl_recv failed: %s\n", strerror(errno));
strncpy(buf, WPA_EVENT_TERMINATING " - recv error", buflen-1);
@@ -725,28 +763,51 @@ int wifi_wait_for_event(char *buf, size_t buflen)
return nread;
}
-void wifi_close_supplicant_connection()
+int wifi_wait_for_event(const char *ifname, char *buf, size_t buflen)
+{
+ if (is_primary_interface(ifname)) {
+ return wifi_wait_on_socket(PRIMARY, buf, buflen);
+ } else {
+ return wifi_wait_on_socket(SECONDARY, buf, buflen);
+ }
+}
+
+void wifi_close_sockets(int index)
+{
+ if (ctrl_conn[index] != NULL) {
+ wpa_ctrl_close(ctrl_conn[index]);
+ ctrl_conn[index] = NULL;
+ }
+
+ if (monitor_conn[index] != NULL) {
+ wpa_ctrl_close(monitor_conn[index]);
+ monitor_conn[index] = NULL;
+ }
+
+ if (exit_sockets[index][0] >= 0) {
+ close(exit_sockets[index][0]);
+ exit_sockets[index][0] = -1;
+ }
+
+ if (exit_sockets[index][1] >= 0) {
+ close(exit_sockets[index][1]);
+ exit_sockets[index][1] = -1;
+ }
+}
+
+void wifi_close_supplicant_connection(const char *ifname)
{
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */
- if (ctrl_conn != NULL) {
- wpa_ctrl_close(ctrl_conn);
- ctrl_conn = NULL;
- }
- if (monitor_conn != NULL) {
- wpa_ctrl_close(monitor_conn);
- monitor_conn = NULL;
- }
- if (exit_sockets[0] >= 0) {
- close(exit_sockets[0]);
- exit_sockets[0] = -1;
- }
-
- if (exit_sockets[1] >= 0) {
- close(exit_sockets[1]);
- exit_sockets[1] = -1;
+ if (is_primary_interface(ifname)) {
+ wifi_close_sockets(PRIMARY);
+ } else {
+ wifi_close_sockets(SECONDARY);
+ //closing p2p connection does not need a wait on
+ //supplicant stop
+ return;
}
while (count-- > 0) {
@@ -758,9 +819,13 @@ void wifi_close_supplicant_connection()
}
}
-int wifi_command(const char *command, char *reply, size_t *reply_len)
+int wifi_command(const char *ifname, const char *command, char *reply, size_t *reply_len)
{
- return wifi_send_command(ctrl_conn, command, reply, reply_len);
+ if (is_primary_interface(ifname)) {
+ return wifi_send_command(PRIMARY, command, reply, reply_len);
+ } else {
+ return wifi_send_command(SECONDARY, command, reply, reply_len);
+ }
}
const char *wifi_get_fw_path(int fw_type)