3#include "libxr_def.hpp"
4#if defined(HAVE_WPA_CLIENT)
6#include <NetworkManager.h>
16#include "net/wifi_client.hpp"
22class LinuxWifiClient :
public WifiClient
25 LinuxWifiClient(
const char* ifname =
nullptr)
29 strncpy(ifname_cstr_, ifname,
sizeof(ifname_cstr_) - 1);
33 std::string iface = DetectWifiInterface();
36 XR_LOG_ERROR(
"Wi-Fi interface not found");
41 strncpy(ifname_cstr_, iface.c_str(),
sizeof(ifname_cstr_) - 1);
45 socket_path_ =
"/var/run/wpa_supplicant/" + std::string(ifname_cstr_);
48 ~LinuxWifiClient()
override
53 wpa_ctrl_close(ctrl_);
57 bool Enable()
override
63 ctrl_ = wpa_ctrl_open(socket_path_.c_str());
66 XR_LOG_PASS(
"Wi-Fi enabled: %s", socket_path_.c_str());
69 XR_LOG_ERROR(
"Wi-Fi enable failed: %s", socket_path_.c_str());
73 void Disable()
override
78 wpa_ctrl_close(ctrl_);
83 bool IsConnected()
const override
86 if (!SendCommand(
"STATUS", out))
90 return out.find(
"wpa_state=COMPLETED") != std::string::npos;
93 IPAddressRaw GetIPAddress()
const override
96 auto ans = snprintf(cmd,
sizeof(cmd),
"ip -4 addr show %s | grep inet", ifname_cstr_);
98 FILE* fp = popen(cmd,
"r");
105 IPAddressRaw ip = {};
106 if (fgets(buf,
sizeof(buf), fp))
108 char ip_str[32] = {};
109 auto ret = sscanf(buf,
" inet %[^/]", ip_str);
111 ip = IPAddressRaw::FromString(ip_str);
117 MACAddressRaw GetMACAddress()
const override
120 auto ans = snprintf(path,
sizeof(path),
"/sys/class/net/%s/address", ifname_cstr_);
122 FILE* fp = fopen(path,
"r");
128 char mac_str[32] = {};
129 if (!fgets(mac_str,
sizeof(mac_str), fp))
131 auto ans = fclose(fp);
135 auto ret = fclose(fp);
137 mac_str[strcspn(mac_str,
"\n")] = 0;
138 return MACAddressRaw::FromString(mac_str);
141 WifiError Connect(
const Config& config)
override
144 SendCommand(
"REMOVE_NETWORK all", out);
145 SendCommand(
"ADD_NETWORK", out);
146 int netid = atoi(out.c_str());
149 XR_LOG_ERROR(
"ADD_NETWORK failed: %s", out.c_str());
150 return WifiError::HARDWARE_FAILURE;
153 std::stringstream cmd;
154 cmd <<
"SET_NETWORK " << netid <<
" ssid \"" << config.ssid <<
"\"";
155 if (!SendCommand(cmd.str().c_str(), out) || out.find(
"OK") == std::string::npos)
157 XR_LOG_ERROR(
"SET_NETWORK ssid failed: %s", out.c_str());
158 return WifiError::AUTHENTICATION_FAILED;
162 cmd <<
"SET_NETWORK " << netid <<
" psk \"" << config.password <<
"\"";
163 if (!SendCommand(cmd.str().c_str(), out) || out.find(
"OK") == std::string::npos)
165 XR_LOG_ERROR(
"SET_NETWORK psk failed: %s", out.c_str());
166 return WifiError::AUTHENTICATION_FAILED;
169 std::vector<std::string> cleanup_cmds = {
170 "key_mgmt WPA-PSK",
"eap NONE",
"phase1 \"\"",
"identity \"\"",
"password \"\"",
172 for (
const auto& line : cleanup_cmds)
175 cmd <<
"SET_NETWORK " << netid <<
" " << line;
176 SendCommand(cmd.str().c_str(), out);
180 cmd <<
"ENABLE_NETWORK " << netid;
181 if (!SendCommand(cmd.str().c_str(), out) || out.find(
"OK") == std::string::npos)
183 XR_LOG_ERROR(
"ENABLE_NETWORK failed: %s", out.c_str());
184 return WifiError::HARDWARE_FAILURE;
188 cmd <<
"SELECT_NETWORK " << netid;
189 SendCommand(cmd.str().c_str(), out);
191 const int TIMEOUT_MS = 30000;
192 const int INTERVAL_MS = 300;
195 while (elapsed < TIMEOUT_MS)
198 SendCommand(
"STATUS", status);
200 if (status.find(
"wpa_state=COMPLETED") != std::string::npos)
202 XR_LOG_PASS(
"Wi-Fi Connected to SSID: %s", config.ssid);
203 return WifiError::NONE;
206 if (status.find(
"wpa_state=INACTIVE") != std::string::npos)
208 XR_LOG_ERROR(
"Wi-Fi Connection failed: %s", status.c_str());
209 return WifiError::AUTHENTICATION_FAILED;
213 elapsed += INTERVAL_MS;
216 XR_LOG_ERROR(
"Wi-Fi Connection timeout");
217 return WifiError::CONNECTION_TIMEOUT;
220 WifiError Disconnect()
override
223 SendCommand(
"DISCONNECT", out);
224 SendCommand(
"REMOVE_NETWORK all", out);
227 return WifiError::UNKNOWN;
229 return WifiError::NONE;
232 WifiError Scan(ScanResult* out_list,
size_t max_count,
size_t& out_found)
override
235 SendCommand(
"SCAN", out);
237 SendCommand(
"SCAN_RESULTS", out);
239 std::istringstream ss(out);
242 std::getline(ss, line);
243 while (std::getline(ss, line) && out_found < max_count)
245 std::istringstream ls(line);
246 std::string bssid, freq, signal, flags, ssid;
247 ls >> bssid >> freq >> signal >> flags;
248 std::getline(ls, ssid);
249 if (!ssid.empty() && ssid[0] ==
'\t')
254 auto& r = out_list[out_found++];
255 strncpy(r.ssid, ssid.c_str(),
sizeof(r.ssid) - 1);
256 r.rssi = atoi(signal.c_str());
258 (flags.find(
"WPA2") != std::string::npos) ? Security::WPA2_PSK : Security::OPEN;
261 return WifiError::NONE;
264 int GetRSSI()
const override
267 SendCommand(
"SIGNAL_POLL", out);
268 auto pos = out.find(
"RSSI=");
269 return pos != std::string::npos ? atoi(out.c_str() + pos + 5) : 0;
273 bool SendCommand(
const char* cmd, std::string& result)
const
280 size_t len =
sizeof(buf);
281 int ret = wpa_ctrl_request(ctrl_, cmd, strlen(cmd), buf, &len,
nullptr);
284 result.assign(buf, len);
287 XR_LOG_ERROR(
"wpa_ctrl_request failed: %s\n", strerror(errno));
291 std::string DetectWifiInterface()
293 GError* error =
nullptr;
294 NMClient* client = nm_client_new(
nullptr, &error);
297 auto ans = fprintf(stderr,
"Failed to create NMClient: %s\n",
298 error ? error->message :
"unknown error");
308 const GPtrArray* devices = nm_client_get_devices(client);
309 for (guint i = 0; i < devices->len; ++i)
311 NMDevice* dev = (NMDevice*)g_ptr_array_index(devices, i);
312 if (NM_IS_DEVICE_WIFI(dev))
314 const char* ifname = nm_device_get_iface(dev);
317 std::string iface_str(ifname);
318 g_object_unref(client);
324 g_object_unref(client);
328 char ifname_cstr_[32] = {};
329 std::string socket_path_;
330 wpa_ctrl* ctrl_ =
nullptr;
static void Sleep(uint32_t milliseconds)
让线程进入休眠状态 Puts the thread to sleep