3#include "libxr_def.hpp"
4#if defined(HAVE_WPA_CLIENT)
6#include <NetworkManager.h>
16#include "net/wifi_client.hpp"
25class LinuxWifiClient :
public WifiClient
32 LinuxWifiClient(
const char* ifname =
nullptr)
36 strncpy(ifname_cstr_, ifname,
sizeof(ifname_cstr_) - 1);
40 std::string iface = DetectWifiInterface();
43 XR_LOG_ERROR(
"Wi-Fi interface not found");
48 strncpy(ifname_cstr_, iface.c_str(),
sizeof(ifname_cstr_) - 1);
52 socket_path_ =
"/var/run/wpa_supplicant/" + std::string(ifname_cstr_);
58 ~LinuxWifiClient()
override
63 wpa_ctrl_close(ctrl_);
67 bool Enable()
override
73 ctrl_ = wpa_ctrl_open(socket_path_.c_str());
76 XR_LOG_PASS(
"Wi-Fi enabled: %s", socket_path_.c_str());
79 XR_LOG_ERROR(
"Wi-Fi enable failed: %s", socket_path_.c_str());
83 void Disable()
override
88 wpa_ctrl_close(ctrl_);
93 bool IsConnected()
const override
96 if (!SendCommand(
"STATUS", out))
100 return out.find(
"wpa_state=COMPLETED") != std::string::npos;
103 IPAddressRaw GetIPAddress()
const override
106 auto ans = snprintf(cmd,
sizeof(cmd),
"ip -4 addr show %s | grep inet", ifname_cstr_);
108 FILE* fp = popen(cmd,
"r");
115 IPAddressRaw ip = {};
116 if (fgets(buf,
sizeof(buf), fp))
118 char ip_str[32] = {};
119 auto ret = sscanf(buf,
" inet %[^/]", ip_str);
121 ip = IPAddressRaw::FromString(ip_str);
127 MACAddressRaw GetMACAddress()
const override
130 auto ans = snprintf(path,
sizeof(path),
"/sys/class/net/%s/address", ifname_cstr_);
132 FILE* fp = fopen(path,
"r");
138 char mac_str[32] = {};
139 if (!fgets(mac_str,
sizeof(mac_str), fp))
141 auto ans = fclose(fp);
145 auto ret = fclose(fp);
147 mac_str[strcspn(mac_str,
"\n")] = 0;
148 return MACAddressRaw::FromString(mac_str);
151 WifiError Connect(
const Config& config)
override
154 SendCommand(
"REMOVE_NETWORK all", out);
155 SendCommand(
"ADD_NETWORK", out);
156 int netid = atoi(out.c_str());
159 XR_LOG_ERROR(
"ADD_NETWORK failed: %s", out.c_str());
160 return WifiError::HARDWARE_FAILURE;
163 std::stringstream cmd;
164 cmd <<
"SET_NETWORK " << netid <<
" ssid \"" << config.ssid <<
"\"";
165 if (!SendCommand(cmd.str().c_str(), out) || out.find(
"OK") == std::string::npos)
167 XR_LOG_ERROR(
"SET_NETWORK ssid failed: %s", out.c_str());
168 return WifiError::AUTHENTICATION_FAILED;
172 cmd <<
"SET_NETWORK " << netid <<
" psk \"" << config.password <<
"\"";
173 if (!SendCommand(cmd.str().c_str(), out) || out.find(
"OK") == std::string::npos)
175 XR_LOG_ERROR(
"SET_NETWORK psk failed: %s", out.c_str());
176 return WifiError::AUTHENTICATION_FAILED;
179 std::vector<std::string> cleanup_cmds = {
180 "key_mgmt WPA-PSK",
"eap NONE",
"phase1 \"\"",
"identity \"\"",
"password \"\"",
182 for (
const auto& line : cleanup_cmds)
185 cmd <<
"SET_NETWORK " << netid <<
" " << line;
186 SendCommand(cmd.str().c_str(), out);
190 cmd <<
"ENABLE_NETWORK " << netid;
191 if (!SendCommand(cmd.str().c_str(), out) || out.find(
"OK") == std::string::npos)
193 XR_LOG_ERROR(
"ENABLE_NETWORK failed: %s", out.c_str());
194 return WifiError::HARDWARE_FAILURE;
198 cmd <<
"SELECT_NETWORK " << netid;
199 SendCommand(cmd.str().c_str(), out);
201 const int TIMEOUT_MS = 30000;
202 const int INTERVAL_MS = 300;
205 while (elapsed < TIMEOUT_MS)
208 SendCommand(
"STATUS", status);
210 if (status.find(
"wpa_state=COMPLETED") != std::string::npos)
212 XR_LOG_PASS(
"Wi-Fi Connected to SSID: %s", config.ssid);
213 return WifiError::NONE;
216 if (status.find(
"wpa_state=INACTIVE") != std::string::npos)
218 XR_LOG_ERROR(
"Wi-Fi Connection failed: %s", status.c_str());
219 return WifiError::AUTHENTICATION_FAILED;
223 elapsed += INTERVAL_MS;
226 XR_LOG_ERROR(
"Wi-Fi Connection timeout");
227 return WifiError::CONNECTION_TIMEOUT;
230 WifiError Disconnect()
override
233 SendCommand(
"DISCONNECT", out);
234 SendCommand(
"REMOVE_NETWORK all", out);
237 return WifiError::UNKNOWN;
239 return WifiError::NONE;
242 WifiError Scan(ScanResult* out_list,
size_t max_count,
size_t& out_found)
override
245 SendCommand(
"SCAN", out);
247 SendCommand(
"SCAN_RESULTS", out);
249 std::istringstream ss(out);
252 std::getline(ss, line);
253 while (std::getline(ss, line) && out_found < max_count)
255 std::istringstream ls(line);
256 std::string bssid, freq, signal, flags, ssid;
257 ls >> bssid >> freq >> signal >> flags;
258 std::getline(ls, ssid);
259 if (!ssid.empty() && ssid[0] ==
'\t')
264 auto& r = out_list[out_found++];
265 strncpy(r.ssid, ssid.c_str(),
sizeof(r.ssid) - 1);
266 r.rssi = atoi(signal.c_str());
268 (flags.find(
"WPA2") != std::string::npos) ? Security::WPA2_PSK : Security::OPEN;
271 return WifiError::NONE;
274 int GetRSSI()
const override
277 SendCommand(
"SIGNAL_POLL", out);
278 auto pos = out.find(
"RSSI=");
279 return pos != std::string::npos ? atoi(out.c_str() + pos + 5) : 0;
283 bool SendCommand(
const char* cmd, std::string& result)
const
290 size_t len =
sizeof(buf);
291 int ret = wpa_ctrl_request(ctrl_, cmd, strlen(cmd), buf, &len,
nullptr);
294 result.assign(buf, len);
297 XR_LOG_ERROR(
"wpa_ctrl_request failed: %s\n", strerror(errno));
301 std::string DetectWifiInterface()
303 GError* error =
nullptr;
304 NMClient* client = nm_client_new(
nullptr, &error);
307 auto ans = fprintf(stderr,
"Failed to create NMClient: %s\n",
308 error ? error->message :
"unknown error");
318 const GPtrArray* devices = nm_client_get_devices(client);
319 for (guint i = 0; i < devices->len; ++i)
321 NMDevice* dev = (NMDevice*)g_ptr_array_index(devices, i);
322 if (NM_IS_DEVICE_WIFI(dev))
324 const char* ifname = nm_device_get_iface(dev);
327 std::string iface_str(ifname);
328 g_object_unref(client);
334 g_object_unref(client);
338 char ifname_cstr_[32] = {};
339 std::string socket_path_;
340 wpa_ctrl* ctrl_ =
nullptr;
static void Sleep(uint32_t milliseconds)
让线程进入休眠状态 Puts the thread to sleep