/* -*- 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; }