mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-02-04 02:51:18 +01:00
wifi scanner
This commit is contained in:
@@ -1171,8 +1171,12 @@ add_library(core STATIC
|
||||
|
||||
if (ENABLE_WIFI_SCAN)
|
||||
# find_package(libiw REQUIRED)
|
||||
target_compile_definitions(core PRIVATE ENABLE_WIFI_SCAN)
|
||||
target_link_libraries(core PRIVATE iw)
|
||||
target_sources(core PRIVATE internal_network/wifi_scanner.cpp)
|
||||
if (PLATFORM_LINUX)
|
||||
target_link_libraries(core PRIVATE iw)
|
||||
endif()
|
||||
else()
|
||||
target_sources(core PRIVATE internal_network/wifi_scanner_dummy.cpp)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
|
||||
@@ -9,6 +9,30 @@
|
||||
#include <ranges>
|
||||
#include <bit>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <iphlpapi.h>
|
||||
#elif defined(__linux__) || defined(__ANDROID__)
|
||||
#include <cerrno>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
@@ -16,14 +40,6 @@
|
||||
#include "core/internal_network/emu_net_state.h"
|
||||
#include "core/internal_network/network_interface.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <iphlpapi.h>
|
||||
#else
|
||||
#include <cerrno>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
namespace Network {
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -86,8 +102,8 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
#else
|
||||
|
||||
std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
#if defined(__ANDROID__) || defined(__linux__)
|
||||
struct ifaddrs* ifaddr = nullptr;
|
||||
|
||||
if (getifaddrs(&ifaddr) != 0) {
|
||||
LOG_ERROR(Network, "getifaddrs: {}", std::strerror(errno));
|
||||
return {};
|
||||
@@ -101,7 +117,7 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
u32 flags;
|
||||
};
|
||||
std::vector<RoutingEntry> routes{};
|
||||
#ifdef ANDROID
|
||||
#ifdef __ANDROID__
|
||||
// Even through Linux based, we can't reliably obtain routing information from there :(
|
||||
#else
|
||||
if (std::ifstream file("/proc/net/route"); file.is_open()) {
|
||||
@@ -140,6 +156,62 @@ std::vector<Network::NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||
}
|
||||
freeifaddrs(ifaddr);
|
||||
return ifaces;
|
||||
#elif defined(__FreeBSD__)
|
||||
std::vector<Network::NetworkInterface> ifaces;
|
||||
int fd = ::socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
|
||||
if (fd < 0) {
|
||||
LOG_ERROR(Network, "socket: {}", std::strerror(errno));
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t bufsz = 0;
|
||||
int mib[6] = {
|
||||
CTL_NET, PF_ROUTE, 0,
|
||||
AF_UNSPEC, NET_RT_IFLIST, 0
|
||||
};
|
||||
if (::sysctl(mib, sizeof(mib) / sizeof(mib[0]), nullptr, &bufsz, nullptr, 0) < 0) {
|
||||
LOG_ERROR(Network, "sysctl.1: {}", std::strerror(errno));
|
||||
return {};
|
||||
}
|
||||
std::vector<char> buf(bufsz);
|
||||
if (::sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf.data(), &bufsz, nullptr, 0) < 0) {
|
||||
LOG_ERROR(Network, "sysctl.2: {}", std::strerror(errno));
|
||||
return {};
|
||||
}
|
||||
|
||||
struct rt_msghdr const *rtm = NULL;
|
||||
for (char *next = buf.data(); next < buf.data() + bufsz; next += rtm->rtm_msglen) {
|
||||
rtm = (struct rt_msghdr const *)next;
|
||||
if (rtm->rtm_type == RTM_IFINFO) {
|
||||
struct if_msghdr const* ifm = (struct if_msghdr const *)rtm;
|
||||
size_t msglen = rtm->rtm_msglen - sizeof(*ifm);
|
||||
char const* p = (char const*)(ifm + 1);
|
||||
|
||||
Network::NetworkInterface iface{};
|
||||
for (size_t i = 0; i < RTAX_MAX; i++)
|
||||
if ((ifm->ifm_addrs & (1 << i)) != 0) {
|
||||
struct sockaddr const* sa = reinterpret_cast<struct sockaddr const*>(p);
|
||||
if (msglen == 0 || msglen < SA_SIZE(sa))
|
||||
break;
|
||||
if (i == RTA_NETMASK && sa->sa_family == AF_LINK) {
|
||||
size_t namelen = 0;
|
||||
struct sockaddr_dl const* sdl = reinterpret_cast<struct sockaddr_dl const*>(sa);
|
||||
::link_ntoa_r(sdl, nullptr, &namelen);
|
||||
iface.name = std::string(namelen, ' ');
|
||||
::link_ntoa_r(sdl, iface.name.data(), &namelen);
|
||||
std::memcpy(&iface.ip_address, sa, sizeof(struct sockaddr_in));
|
||||
}
|
||||
msglen -= SA_SIZE(sa);
|
||||
p += SA_SIZE(sa);
|
||||
}
|
||||
ifaces.push_back(iface);
|
||||
}
|
||||
}
|
||||
::close(fd);
|
||||
return ifaces;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/internal_network/wifi_scanner.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
@@ -18,16 +13,28 @@ using namespace std::chrono_literals;
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "wlanapi.lib")
|
||||
#endif
|
||||
#elif defined(__linux__) && !defined(__ANDROID__)
|
||||
#include <iwlib.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/internal_network/wifi_scanner.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace Network {
|
||||
#ifdef ENABLE_WIFI_SCAN
|
||||
#ifdef _WIN32
|
||||
static u8 QualityToPercent(DWORD q) {
|
||||
return static_cast<u8>(q);
|
||||
return u8(q);
|
||||
}
|
||||
|
||||
static std::vector<Network::ScanData> ScanWifiWin(std::chrono::milliseconds deadline) {
|
||||
std::vector<Network::ScanData> ScanWifiNetworks(std::chrono::milliseconds deadline) {
|
||||
std::vector<Network::ScanData> out;
|
||||
|
||||
HANDLE hClient{};
|
||||
@@ -85,38 +92,16 @@ static std::vector<Network::ScanData> ScanWifiWin(std::chrono::milliseconds dead
|
||||
WlanCloseHandle(hClient, nullptr);
|
||||
return out;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#if defined(__linux__) && !defined(_WIN32) && !defined(ANDROID)
|
||||
#include <iwlib.h>
|
||||
|
||||
#elif defined(__linux__) && !defined(__ANDROID__)
|
||||
static u8 QualityToPercent(const iwrange& r, const wireless_scan* ws) {
|
||||
const iw_quality qual = ws->stats.qual;
|
||||
const int lvl = qual.level;
|
||||
const int max = r.max_qual.level ? r.max_qual.level : 100;
|
||||
return static_cast<u8>(std::clamp(100 * lvl / max, 0, 100));
|
||||
}
|
||||
|
||||
static int wifi_callback(int skfd, char* ifname, char* args[], int count)
|
||||
{
|
||||
iwrange range;
|
||||
|
||||
int res = iw_get_range_info(skfd, ifname, &range);
|
||||
|
||||
LOG_INFO(Network, "ifname {} returned {} on iw_get_range_info", ifname, res);
|
||||
|
||||
if (res >= 0) {
|
||||
strncpy(args[0], ifname, IFNAMSIZ - 1);
|
||||
args[0][IFNAMSIZ - 1] = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return u8(std::clamp(100 * lvl / max, 0, 100));
|
||||
}
|
||||
|
||||
// TODO(crueter, Maufeat): Check if driver supports wireless extensions, fallback to nl80211 if not
|
||||
static std::vector<Network::ScanData> ScanWifiLinux(std::chrono::milliseconds deadline) {
|
||||
std::vector<Network::ScanData> ScanWifiNetworks(std::chrono::milliseconds deadline) {
|
||||
std::vector<Network::ScanData> out;
|
||||
int sock = iw_sockets_open();
|
||||
if (sock < 0) {
|
||||
@@ -127,7 +112,17 @@ static std::vector<Network::ScanData> ScanWifiLinux(std::chrono::milliseconds de
|
||||
char ifname[IFNAMSIZ] = {0};
|
||||
char *args[1] = {ifname};
|
||||
|
||||
iw_enum_devices(sock, &wifi_callback, args, 0);
|
||||
iw_enum_devices(sock, [](int skfd, char* ifname, char* args[], int count) -> int {
|
||||
iwrange range;
|
||||
int res = iw_get_range_info(skfd, ifname, &range);
|
||||
LOG_INFO(Network, "ifname {} returned {} on iw_get_range_info", ifname, res);
|
||||
if (res >= 0) {
|
||||
strncpy(args[0], ifname, IFNAMSIZ - 1);
|
||||
args[0][IFNAMSIZ - 1] = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}, args, 0);
|
||||
|
||||
if (strlen(ifname) == 0) {
|
||||
LOG_WARNING(Network, "No wireless interface found");
|
||||
@@ -153,20 +148,19 @@ static std::vector<Network::ScanData> ScanWifiLinux(std::chrono::milliseconds de
|
||||
|
||||
out.clear();
|
||||
for (auto* ws = head.result; ws; ws = ws->next) {
|
||||
if (!ws->b.has_essid)
|
||||
continue;
|
||||
if (ws->b.has_essid) {
|
||||
Network::ScanData sd{};
|
||||
sd.ssid_len = static_cast<u8>(std::min<int>(ws->b.essid_len, 0x20));
|
||||
std::memcpy(sd.ssid, ws->b.essid, sd.ssid_len);
|
||||
sd.quality = QualityToPercent(range, ws);
|
||||
sd.flags |= 1;
|
||||
if (ws->b.has_key)
|
||||
sd.flags |= 2;
|
||||
|
||||
Network::ScanData sd{};
|
||||
sd.ssid_len = static_cast<u8>(std::min<int>(ws->b.essid_len, 0x20));
|
||||
std::memcpy(sd.ssid, ws->b.essid, sd.ssid_len);
|
||||
sd.quality = QualityToPercent(range, ws);
|
||||
sd.flags |= 1;
|
||||
if (ws->b.has_key)
|
||||
sd.flags |= 2;
|
||||
|
||||
out.emplace_back(sd);
|
||||
char tmp[0x22]{};
|
||||
std::memcpy(tmp, sd.ssid, sd.ssid_len);
|
||||
out.emplace_back(sd);
|
||||
char tmp[0x22]{};
|
||||
std::memcpy(tmp, sd.ssid, sd.ssid_len);
|
||||
}
|
||||
}
|
||||
have = !out.empty();
|
||||
}
|
||||
@@ -174,21 +168,10 @@ static std::vector<Network::ScanData> ScanWifiLinux(std::chrono::milliseconds de
|
||||
iw_sockets_close(sock);
|
||||
return out;
|
||||
}
|
||||
#endif /* linux */
|
||||
#endif
|
||||
|
||||
#else
|
||||
std::vector<Network::ScanData> ScanWifiNetworks(std::chrono::milliseconds deadline) {
|
||||
#ifdef ENABLE_WIFI_SCAN
|
||||
#if defined(_WIN32)
|
||||
return ScanWifiWin(deadline);
|
||||
#elif defined(__linux__) && !defined(ANDROID)
|
||||
return ScanWifiLinux(deadline);
|
||||
#else
|
||||
return {}; // unsupported host, pretend no results
|
||||
#endif
|
||||
#else
|
||||
return {}; // disabled, pretend no results
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Network
|
||||
|
||||
8
src/core/internal_network/wifi_scanner_dummy.cpp
Normal file
8
src/core/internal_network/wifi_scanner_dummy.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
namespace Network {
|
||||
std::vector<Network::ScanData> ScanWifiNetworks(std::chrono::milliseconds deadline) {
|
||||
return {}; // disabled, pretend no results
|
||||
}
|
||||
} // namespace Network
|
||||
Reference in New Issue
Block a user