diff options
Diffstat (limited to 'dom/wifi/WifiHotspotUtils.cpp')
-rw-r--r-- | dom/wifi/WifiHotspotUtils.cpp | 188 |
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; +} |