summaryrefslogtreecommitdiffstats
path: root/dom/wifi/WifiHotspotUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/wifi/WifiHotspotUtils.cpp')
-rw-r--r--dom/wifi/WifiHotspotUtils.cpp188
1 files changed, 188 insertions, 0 deletions
diff --git a/dom/wifi/WifiHotspotUtils.cpp b/dom/wifi/WifiHotspotUtils.cpp
new file mode 100644
index 000000000..5fdb9b76e
--- /dev/null
+++ b/dom/wifi/WifiHotspotUtils.cpp
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WifiHotspotUtils.h"
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <cutils/properties.h>
+
+#include "prinit.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/Sprintf.h"
+#include "nsDebug.h"
+#include "nsPrintfCString.h"
+
+static void* sWifiHotspotUtilsLib;
+static PRCallOnceType sInitWifiHotspotUtilsLib;
+// Socket pair used to exit from a blocking read.
+static struct wpa_ctrl* ctrl_conn;
+static const char *ctrl_iface_dir = "/data/misc/wifi/hostapd";
+static char *ctrl_ifname = nullptr;
+
+DEFINE_DLFUNC(wpa_ctrl_open, struct wpa_ctrl*, const char*)
+DEFINE_DLFUNC(wpa_ctrl_close, void, struct wpa_ctrl*)
+DEFINE_DLFUNC(wpa_ctrl_attach, int32_t, struct wpa_ctrl*)
+DEFINE_DLFUNC(wpa_ctrl_detach, int32_t, struct wpa_ctrl*)
+DEFINE_DLFUNC(wpa_ctrl_request, int32_t, struct wpa_ctrl*,
+ const char*, size_t cmd_len, char *reply,
+ size_t *reply_len, void (*msg_cb)(char *msg, size_t len))
+
+
+static PRStatus
+InitWifiHotspotUtilsLib()
+{
+ sWifiHotspotUtilsLib = dlopen("/system/lib/libwpa_client.so", RTLD_LAZY);
+ // We might fail to open the hardware lib. That's OK.
+ return PR_SUCCESS;
+}
+
+static void*
+GetWifiHotspotLibHandle()
+{
+ PR_CallOnce(&sInitWifiHotspotUtilsLib, InitWifiHotspotUtilsLib);
+ return sWifiHotspotUtilsLib;
+}
+
+struct wpa_ctrl *
+WifiHotspotUtils::openConnection(const char *ifname)
+{
+ if (!ifname) {
+ return nullptr;
+ }
+
+ USE_DLFUNC(wpa_ctrl_open)
+ ctrl_conn = wpa_ctrl_open(nsPrintfCString("%s/%s", ctrl_iface_dir, ifname).get());
+ return ctrl_conn;
+}
+
+int32_t
+WifiHotspotUtils::sendCommand(struct wpa_ctrl *ctrl, const char *cmd,
+ char *reply, size_t *reply_len)
+{
+ int32_t ret;
+
+ if (!ctrl_conn) {
+ NS_WARNING(nsPrintfCString("Not connected to hostapd - \"%s\" command dropped.\n", cmd).get());
+ return -1;
+ }
+
+ USE_DLFUNC(wpa_ctrl_request)
+ ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), reply, reply_len, nullptr);
+ if (ret == -2) {
+ NS_WARNING(nsPrintfCString("'%s' command timed out.\n", cmd).get());
+ return -2;
+ } else if (ret < 0 || strncmp(reply, "FAIL", 4) == 0) {
+ return -1;
+ }
+
+ // Make the reply printable.
+ reply[*reply_len] = '\0';
+ if (strncmp(cmd, "STA-FIRST", 9) == 0 ||
+ strncmp(cmd, "STA-NEXT", 8) == 0) {
+ char *pos = reply;
+
+ while (*pos && *pos != '\n')
+ pos++;
+ *pos = '\0';
+ }
+
+ return 0;
+}
+
+
+// static
+void*
+WifiHotspotUtils::GetSharedLibrary()
+{
+ void* wpaClientLib = GetWifiHotspotLibHandle();
+ if (!wpaClientLib) {
+ NS_WARNING("No /system/lib/libwpa_client.so");
+ }
+ return wpaClientLib;
+}
+
+int32_t WifiHotspotUtils::do_wifi_connect_to_hostapd()
+{
+ struct dirent *dent;
+
+ DIR *dir = opendir(ctrl_iface_dir);
+ if (dir) {
+ while ((dent = readdir(dir))) {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0) {
+ continue;
+ }
+ ctrl_ifname = strdup(dent->d_name);
+ break;
+ }
+ closedir(dir);
+ }
+
+ ctrl_conn = openConnection(ctrl_ifname);
+ if (!ctrl_conn) {
+ NS_WARNING(nsPrintfCString("Unable to open connection to hostapd on \"%s\": %s",
+ ctrl_ifname, strerror(errno)).get());
+ return -1;
+ }
+
+ USE_DLFUNC(wpa_ctrl_attach)
+ if (wpa_ctrl_attach(ctrl_conn) != 0) {
+ USE_DLFUNC(wpa_ctrl_close)
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = nullptr;
+ return -1;
+ }
+
+ return 0;
+}
+
+int32_t WifiHotspotUtils::do_wifi_close_hostapd_connection()
+{
+ if (!ctrl_conn) {
+ NS_WARNING("Invalid ctrl_conn.");
+ return -1;
+ }
+
+ USE_DLFUNC(wpa_ctrl_detach)
+ if (wpa_ctrl_detach(ctrl_conn) < 0) {
+ NS_WARNING("Failed to detach wpa_ctrl.");
+ }
+
+ USE_DLFUNC(wpa_ctrl_close)
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = nullptr;
+ return 0;
+}
+
+int32_t WifiHotspotUtils::do_wifi_hostapd_command(const char *command,
+ char *reply,
+ size_t *reply_len)
+{
+ return sendCommand(ctrl_conn, command, reply, reply_len);
+}
+
+int32_t WifiHotspotUtils::do_wifi_hostapd_get_stations()
+{
+ char addr[32], cmd[64];
+ int stations = 0;
+ size_t addrLen = sizeof(addr);
+
+ if (sendCommand(ctrl_conn, "STA-FIRST", addr, &addrLen)) {
+ return 0;
+ }
+ stations++;
+
+ SprintfLiteral(cmd, "STA-NEXT %s", addr);
+ while (sendCommand(ctrl_conn, cmd, addr, &addrLen) == 0) {
+ stations++;
+ SprintfLiteral(cmd, "STA-NEXT %s", addr);
+ }
+
+ return stations;
+}