lan_discovery.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "core/hle/service/ldn/lan_discovery.h"
  4. #include "core/internal_network/network.h"
  5. #include "core/internal_network/network_interface.h"
  6. namespace Service::LDN {
  7. LanStation::LanStation(s8 node_id_, LANDiscovery* discovery_)
  8. : node_info(nullptr), status(NodeStatus::Disconnected), node_id(node_id_),
  9. discovery(discovery_) {}
  10. LanStation::~LanStation() = default;
  11. NodeStatus LanStation::GetStatus() const {
  12. return status;
  13. }
  14. void LanStation::OnClose() {
  15. LOG_INFO(Service_LDN, "OnClose {}", node_id);
  16. Reset();
  17. discovery->UpdateNodes();
  18. }
  19. void LanStation::Reset() {
  20. status = NodeStatus::Disconnected;
  21. };
  22. void LanStation::OverrideInfo() {
  23. bool connected = GetStatus() == NodeStatus::Connected;
  24. node_info->node_id = node_id;
  25. node_info->is_connected = connected ? 1 : 0;
  26. }
  27. LANDiscovery::LANDiscovery(Network::RoomNetwork& room_network_)
  28. : stations({{{1, this}, {2, this}, {3, this}, {4, this}, {5, this}, {6, this}, {7, this}}}),
  29. room_network{room_network_} {}
  30. LANDiscovery::~LANDiscovery() {
  31. if (inited) {
  32. Result rc = Finalize();
  33. LOG_INFO(Service_LDN, "Finalize: {}", rc.raw);
  34. }
  35. }
  36. void LANDiscovery::InitNetworkInfo() {
  37. network_info.common.bssid = GetFakeMac();
  38. network_info.common.channel = WifiChannel::Wifi24_6;
  39. network_info.common.link_level = LinkLevel::Good;
  40. network_info.common.network_type = PackedNetworkType::Ldn;
  41. network_info.common.ssid = fake_ssid;
  42. auto& nodes = network_info.ldn.nodes;
  43. for (std::size_t i = 0; i < NodeCountMax; i++) {
  44. nodes[i].node_id = static_cast<s8>(i);
  45. nodes[i].is_connected = 0;
  46. }
  47. }
  48. void LANDiscovery::InitNodeStateChange() {
  49. for (auto& node_update : node_changes) {
  50. node_update.state_change = NodeStateChange::None;
  51. }
  52. for (auto& node_state : node_last_states) {
  53. node_state = 0;
  54. }
  55. }
  56. State LANDiscovery::GetState() const {
  57. return state;
  58. }
  59. void LANDiscovery::SetState(State new_state) {
  60. state = new_state;
  61. }
  62. Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network) const {
  63. if (state == State::AccessPointCreated || state == State::StationConnected) {
  64. std::memcpy(&out_network, &network_info, sizeof(network_info));
  65. return ResultSuccess;
  66. }
  67. return ResultBadState;
  68. }
  69. Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network,
  70. std::vector<NodeLatestUpdate>& out_updates,
  71. std::size_t buffer_count) {
  72. if (buffer_count > NodeCountMax) {
  73. return ResultInvalidBufferCount;
  74. }
  75. if (state == State::AccessPointCreated || state == State::StationConnected) {
  76. std::memcpy(&out_network, &network_info, sizeof(network_info));
  77. for (std::size_t i = 0; i < buffer_count; i++) {
  78. out_updates[i].state_change = node_changes[i].state_change;
  79. node_changes[i].state_change = NodeStateChange::None;
  80. }
  81. return ResultSuccess;
  82. }
  83. return ResultBadState;
  84. }
  85. DisconnectReason LANDiscovery::GetDisconnectReason() const {
  86. return disconnect_reason;
  87. }
  88. Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
  89. const ScanFilter& filter) {
  90. if (!IsFlagSet(filter.flag, ScanFilterFlag::NetworkType) ||
  91. filter.network_type <= NetworkType::All) {
  92. if (!IsFlagSet(filter.flag, ScanFilterFlag::Ssid) && filter.ssid.length >= SsidLengthMax) {
  93. return ResultBadInput;
  94. }
  95. }
  96. {
  97. std::scoped_lock lock{packet_mutex};
  98. scan_results.clear();
  99. SendBroadcast(Network::LDNPacketType::Scan);
  100. }
  101. LOG_INFO(Service_LDN, "Waiting for scan replies");
  102. std::this_thread::sleep_for(std::chrono::seconds(1));
  103. std::scoped_lock lock{packet_mutex};
  104. for (const auto& [key, info] : scan_results) {
  105. if (count >= networks.size()) {
  106. break;
  107. }
  108. if (IsFlagSet(filter.flag, ScanFilterFlag::LocalCommunicationId)) {
  109. if (filter.network_id.intent_id.local_communication_id !=
  110. info.network_id.intent_id.local_communication_id) {
  111. continue;
  112. }
  113. }
  114. if (IsFlagSet(filter.flag, ScanFilterFlag::SessionId)) {
  115. if (filter.network_id.session_id != info.network_id.session_id) {
  116. continue;
  117. }
  118. }
  119. if (IsFlagSet(filter.flag, ScanFilterFlag::NetworkType)) {
  120. if (filter.network_type != static_cast<NetworkType>(info.common.network_type)) {
  121. continue;
  122. }
  123. }
  124. if (IsFlagSet(filter.flag, ScanFilterFlag::Ssid)) {
  125. if (filter.ssid != info.common.ssid) {
  126. continue;
  127. }
  128. }
  129. if (IsFlagSet(filter.flag, ScanFilterFlag::SceneId)) {
  130. if (filter.network_id.intent_id.scene_id != info.network_id.intent_id.scene_id) {
  131. continue;
  132. }
  133. }
  134. networks[count++] = info;
  135. }
  136. return ResultSuccess;
  137. }
  138. Result LANDiscovery::SetAdvertiseData(std::span<const u8> data) {
  139. std::scoped_lock lock{packet_mutex};
  140. const std::size_t size = data.size();
  141. if (size > AdvertiseDataSizeMax) {
  142. return ResultAdvertiseDataTooLarge;
  143. }
  144. std::memcpy(network_info.ldn.advertise_data.data(), data.data(), size);
  145. network_info.ldn.advertise_data_size = static_cast<u16>(size);
  146. UpdateNodes();
  147. return ResultSuccess;
  148. }
  149. Result LANDiscovery::OpenAccessPoint() {
  150. std::scoped_lock lock{packet_mutex};
  151. disconnect_reason = DisconnectReason::None;
  152. if (state == State::None) {
  153. return ResultBadState;
  154. }
  155. ResetStations();
  156. SetState(State::AccessPointOpened);
  157. return ResultSuccess;
  158. }
  159. Result LANDiscovery::CloseAccessPoint() {
  160. std::scoped_lock lock{packet_mutex};
  161. if (state == State::None) {
  162. return ResultBadState;
  163. }
  164. if (state == State::AccessPointCreated) {
  165. DestroyNetwork();
  166. }
  167. ResetStations();
  168. SetState(State::Initialized);
  169. return ResultSuccess;
  170. }
  171. Result LANDiscovery::OpenStation() {
  172. std::scoped_lock lock{packet_mutex};
  173. disconnect_reason = DisconnectReason::None;
  174. if (state == State::None) {
  175. return ResultBadState;
  176. }
  177. ResetStations();
  178. SetState(State::StationOpened);
  179. return ResultSuccess;
  180. }
  181. Result LANDiscovery::CloseStation() {
  182. std::scoped_lock lock{packet_mutex};
  183. if (state == State::None) {
  184. return ResultBadState;
  185. }
  186. if (state == State::StationConnected) {
  187. Disconnect();
  188. }
  189. ResetStations();
  190. SetState(State::Initialized);
  191. return ResultSuccess;
  192. }
  193. Result LANDiscovery::CreateNetwork(const SecurityConfig& security_config,
  194. const UserConfig& user_config,
  195. const NetworkConfig& network_config) {
  196. std::scoped_lock lock{packet_mutex};
  197. if (state != State::AccessPointOpened) {
  198. return ResultBadState;
  199. }
  200. InitNetworkInfo();
  201. network_info.ldn.node_count_max = network_config.node_count_max;
  202. network_info.ldn.security_mode = security_config.security_mode;
  203. if (network_config.channel == WifiChannel::Default) {
  204. network_info.common.channel = WifiChannel::Wifi24_6;
  205. } else {
  206. network_info.common.channel = network_config.channel;
  207. }
  208. std::independent_bits_engine<std::mt19937, 64, u64> bits_engine;
  209. network_info.network_id.session_id.high = bits_engine();
  210. network_info.network_id.session_id.low = bits_engine();
  211. network_info.network_id.intent_id = network_config.intent_id;
  212. NodeInfo& node0 = network_info.ldn.nodes[0];
  213. const Result rc2 = GetNodeInfo(node0, user_config, network_config.local_communication_version);
  214. if (rc2.IsError()) {
  215. return ResultAccessPointConnectionFailed;
  216. }
  217. SetState(State::AccessPointCreated);
  218. InitNodeStateChange();
  219. node0.is_connected = 1;
  220. UpdateNodes();
  221. return rc2;
  222. }
  223. Result LANDiscovery::DestroyNetwork() {
  224. for (auto local_ip : connected_clients) {
  225. SendPacket(Network::LDNPacketType::DestroyNetwork, local_ip);
  226. }
  227. ResetStations();
  228. SetState(State::AccessPointOpened);
  229. lan_event();
  230. return ResultSuccess;
  231. }
  232. Result LANDiscovery::Connect(const NetworkInfo& network_info_, const UserConfig& user_config,
  233. u16 local_communication_version) {
  234. std::scoped_lock lock{packet_mutex};
  235. if (network_info_.ldn.node_count == 0) {
  236. return ResultInvalidNodeCount;
  237. }
  238. Result rc = GetNodeInfo(node_info, user_config, local_communication_version);
  239. if (rc.IsError()) {
  240. return ResultConnectionFailed;
  241. }
  242. Ipv4Address node_host = network_info_.ldn.nodes[0].ipv4_address;
  243. std::reverse(std::begin(node_host), std::end(node_host)); // htonl
  244. host_ip = node_host;
  245. SendPacket(Network::LDNPacketType::Connect, node_info, *host_ip);
  246. InitNodeStateChange();
  247. std::this_thread::sleep_for(std::chrono::seconds(1));
  248. return ResultSuccess;
  249. }
  250. Result LANDiscovery::Disconnect() {
  251. if (host_ip) {
  252. SendPacket(Network::LDNPacketType::Disconnect, node_info, *host_ip);
  253. }
  254. SetState(State::StationOpened);
  255. lan_event();
  256. return ResultSuccess;
  257. }
  258. Result LANDiscovery::Initialize(LanEventFunc lan_event_, bool listening) {
  259. std::scoped_lock lock{packet_mutex};
  260. if (inited) {
  261. return ResultSuccess;
  262. }
  263. for (auto& station : stations) {
  264. station.discovery = this;
  265. station.node_info = &network_info.ldn.nodes[station.node_id];
  266. station.Reset();
  267. }
  268. connected_clients.clear();
  269. lan_event = lan_event_;
  270. SetState(State::Initialized);
  271. inited = true;
  272. return ResultSuccess;
  273. }
  274. Result LANDiscovery::Finalize() {
  275. std::scoped_lock lock{packet_mutex};
  276. Result rc = ResultSuccess;
  277. if (inited) {
  278. if (state == State::AccessPointCreated) {
  279. DestroyNetwork();
  280. }
  281. if (state == State::StationConnected) {
  282. Disconnect();
  283. }
  284. ResetStations();
  285. inited = false;
  286. }
  287. SetState(State::None);
  288. return rc;
  289. }
  290. void LANDiscovery::ResetStations() {
  291. for (auto& station : stations) {
  292. station.Reset();
  293. }
  294. connected_clients.clear();
  295. }
  296. void LANDiscovery::UpdateNodes() {
  297. u8 count = 0;
  298. for (auto& station : stations) {
  299. bool connected = station.GetStatus() == NodeStatus::Connected;
  300. if (connected) {
  301. count++;
  302. }
  303. station.OverrideInfo();
  304. }
  305. network_info.ldn.node_count = count + 1;
  306. for (auto local_ip : connected_clients) {
  307. SendPacket(Network::LDNPacketType::SyncNetwork, network_info, local_ip);
  308. }
  309. OnNetworkInfoChanged();
  310. }
  311. void LANDiscovery::OnSyncNetwork(const NetworkInfo& info) {
  312. network_info = info;
  313. if (state == State::StationOpened) {
  314. SetState(State::StationConnected);
  315. }
  316. OnNetworkInfoChanged();
  317. }
  318. void LANDiscovery::OnDisconnectFromHost() {
  319. LOG_INFO(Service_LDN, "OnDisconnectFromHost state: {}", static_cast<int>(state));
  320. host_ip = std::nullopt;
  321. if (state == State::StationConnected) {
  322. SetState(State::StationOpened);
  323. lan_event();
  324. }
  325. }
  326. void LANDiscovery::OnNetworkInfoChanged() {
  327. if (IsNodeStateChanged()) {
  328. lan_event();
  329. }
  330. return;
  331. }
  332. Network::IPv4Address LANDiscovery::GetLocalIp() const {
  333. Network::IPv4Address local_ip{0xFF, 0xFF, 0xFF, 0xFF};
  334. if (auto room_member = room_network.GetRoomMember().lock()) {
  335. if (room_member->IsConnected()) {
  336. local_ip = room_member->GetFakeIpAddress();
  337. }
  338. }
  339. return local_ip;
  340. }
  341. template <typename Data>
  342. void LANDiscovery::SendPacket(Network::LDNPacketType type, const Data& data,
  343. Ipv4Address remote_ip) {
  344. Network::LDNPacket packet;
  345. packet.type = type;
  346. packet.broadcast = false;
  347. packet.local_ip = GetLocalIp();
  348. packet.remote_ip = remote_ip;
  349. packet.data.resize(sizeof(data));
  350. std::memcpy(packet.data.data(), &data, sizeof(data));
  351. SendPacket(packet);
  352. }
  353. void LANDiscovery::SendPacket(Network::LDNPacketType type, Ipv4Address remote_ip) {
  354. Network::LDNPacket packet;
  355. packet.type = type;
  356. packet.broadcast = false;
  357. packet.local_ip = GetLocalIp();
  358. packet.remote_ip = remote_ip;
  359. SendPacket(packet);
  360. }
  361. template <typename Data>
  362. void LANDiscovery::SendBroadcast(Network::LDNPacketType type, const Data& data) {
  363. Network::LDNPacket packet;
  364. packet.type = type;
  365. packet.broadcast = true;
  366. packet.local_ip = GetLocalIp();
  367. packet.data.resize(sizeof(data));
  368. std::memcpy(packet.data.data(), &data, sizeof(data));
  369. SendPacket(packet);
  370. }
  371. void LANDiscovery::SendBroadcast(Network::LDNPacketType type) {
  372. Network::LDNPacket packet;
  373. packet.type = type;
  374. packet.broadcast = true;
  375. packet.local_ip = GetLocalIp();
  376. SendPacket(packet);
  377. }
  378. void LANDiscovery::SendPacket(const Network::LDNPacket& packet) {
  379. if (auto room_member = room_network.GetRoomMember().lock()) {
  380. if (room_member->IsConnected()) {
  381. room_member->SendLdnPacket(packet);
  382. }
  383. }
  384. }
  385. void LANDiscovery::ReceivePacket(const Network::LDNPacket& packet) {
  386. std::scoped_lock lock{packet_mutex};
  387. switch (packet.type) {
  388. case Network::LDNPacketType::Scan: {
  389. LOG_INFO(Frontend, "Scan packet received!");
  390. if (state == State::AccessPointCreated) {
  391. // Reply to the sender
  392. SendPacket(Network::LDNPacketType::ScanResp, network_info, packet.local_ip);
  393. }
  394. break;
  395. }
  396. case Network::LDNPacketType::ScanResp: {
  397. LOG_INFO(Frontend, "ScanResp packet received!");
  398. NetworkInfo info{};
  399. std::memcpy(&info, packet.data.data(), sizeof(NetworkInfo));
  400. scan_results.insert({info.common.bssid, info});
  401. break;
  402. }
  403. case Network::LDNPacketType::Connect: {
  404. LOG_INFO(Frontend, "Connect packet received!");
  405. NodeInfo info{};
  406. std::memcpy(&info, packet.data.data(), sizeof(NodeInfo));
  407. connected_clients.push_back(packet.local_ip);
  408. for (LanStation& station : stations) {
  409. if (station.status != NodeStatus::Connected) {
  410. *station.node_info = info;
  411. station.status = NodeStatus::Connected;
  412. break;
  413. }
  414. }
  415. UpdateNodes();
  416. break;
  417. }
  418. case Network::LDNPacketType::Disconnect: {
  419. LOG_INFO(Frontend, "Disconnect packet received!");
  420. connected_clients.erase(
  421. std::remove(connected_clients.begin(), connected_clients.end(), packet.local_ip),
  422. connected_clients.end());
  423. NodeInfo info{};
  424. std::memcpy(&info, packet.data.data(), sizeof(NodeInfo));
  425. for (LanStation& station : stations) {
  426. if (station.status == NodeStatus::Connected &&
  427. station.node_info->mac_address == info.mac_address) {
  428. station.OnClose();
  429. break;
  430. }
  431. }
  432. break;
  433. }
  434. case Network::LDNPacketType::DestroyNetwork: {
  435. ResetStations();
  436. OnDisconnectFromHost();
  437. break;
  438. }
  439. case Network::LDNPacketType::SyncNetwork: {
  440. if (state == State::StationOpened || state == State::StationConnected) {
  441. LOG_INFO(Frontend, "SyncNetwork packet received!");
  442. NetworkInfo info{};
  443. std::memcpy(&info, packet.data.data(), sizeof(NetworkInfo));
  444. OnSyncNetwork(info);
  445. } else {
  446. LOG_INFO(Frontend, "SyncNetwork packet received but in wrong State!");
  447. }
  448. break;
  449. }
  450. default: {
  451. LOG_INFO(Frontend, "ReceivePacket unhandled type {}", static_cast<int>(packet.type));
  452. break;
  453. }
  454. }
  455. }
  456. bool LANDiscovery::IsNodeStateChanged() {
  457. bool changed = false;
  458. const auto& nodes = network_info.ldn.nodes;
  459. for (int i = 0; i < NodeCountMax; i++) {
  460. if (nodes[i].is_connected != node_last_states[i]) {
  461. if (nodes[i].is_connected) {
  462. node_changes[i].state_change |= NodeStateChange::Connect;
  463. } else {
  464. node_changes[i].state_change |= NodeStateChange::Disconnect;
  465. }
  466. node_last_states[i] = nodes[i].is_connected;
  467. changed = true;
  468. }
  469. }
  470. return changed;
  471. }
  472. bool LANDiscovery::IsFlagSet(ScanFilterFlag flag, ScanFilterFlag search_flag) const {
  473. const auto flag_value = static_cast<u32>(flag);
  474. const auto search_flag_value = static_cast<u32>(search_flag);
  475. return (flag_value & search_flag_value) == search_flag_value;
  476. }
  477. int LANDiscovery::GetStationCount() const {
  478. return static_cast<int>(
  479. std::count_if(stations.begin(), stations.end(), [](const auto& station) {
  480. return station.GetStatus() != NodeStatus::Disconnected;
  481. }));
  482. }
  483. MacAddress LANDiscovery::GetFakeMac() const {
  484. MacAddress mac{};
  485. mac.raw[0] = 0x02;
  486. mac.raw[1] = 0x00;
  487. const auto ip = GetLocalIp();
  488. memcpy(mac.raw.data() + 2, &ip, sizeof(ip));
  489. return mac;
  490. }
  491. Result LANDiscovery::GetNodeInfo(NodeInfo& node, const UserConfig& userConfig,
  492. u16 localCommunicationVersion) {
  493. const auto network_interface = Network::GetSelectedNetworkInterface();
  494. if (!network_interface) {
  495. LOG_ERROR(Service_LDN, "No network interface available");
  496. return ResultNoIpAddress;
  497. }
  498. node.mac_address = GetFakeMac();
  499. node.is_connected = 1;
  500. std::memcpy(node.user_name.data(), userConfig.user_name.data(), UserNameBytesMax + 1);
  501. node.local_communication_version = localCommunicationVersion;
  502. Ipv4Address current_address = GetLocalIp();
  503. std::reverse(std::begin(current_address), std::end(current_address)); // ntohl
  504. node.ipv4_address = current_address;
  505. return ResultSuccess;
  506. }
  507. } // namespace Service::LDN