tenfourfox/dom/wifi/WifiHotspotUtils.cpp

189 lines
4.7 KiB
C++

/* -*- 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/Snprintf.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++;
snprintf_literal(cmd, "STA-NEXT %s", addr);
while (sendCommand(ctrl_conn, cmd, addr, &addrLen) == 0) {
stations++;
snprintf_literal(cmd, "STA-NEXT %s", addr);
}
return stations;
}