nwm_uds.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. // Copyright 2017 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <array>
  5. #include <cstring>
  6. #include <unordered_map>
  7. #include <vector>
  8. #include "common/common_types.h"
  9. #include "common/logging/log.h"
  10. #include "core/core_timing.h"
  11. #include "core/hle/ipc_helpers.h"
  12. #include "core/hle/kernel/event.h"
  13. #include "core/hle/kernel/shared_memory.h"
  14. #include "core/hle/result.h"
  15. #include "core/hle/service/nwm/nwm_uds.h"
  16. #include "core/hle/service/nwm/uds_beacon.h"
  17. #include "core/hle/service/nwm/uds_data.h"
  18. #include "core/memory.h"
  19. namespace Service {
  20. namespace NWM {
  21. // Event that is signaled every time the connection status changes.
  22. static Kernel::SharedPtr<Kernel::Event> connection_status_event;
  23. // Shared memory provided by the application to store the receive buffer.
  24. // This is not currently used.
  25. static Kernel::SharedPtr<Kernel::SharedMemory> recv_buffer_memory;
  26. // Connection status of this 3DS.
  27. static ConnectionStatus connection_status{};
  28. /* Node information about the current network.
  29. * The amount of elements in this vector is always the maximum number
  30. * of nodes specified in the network configuration.
  31. * The first node is always the host, so this always contains at least 1 entry.
  32. */
  33. static NodeList node_info(1);
  34. // Mapping of bind node ids to their respective events.
  35. static std::unordered_map<u32, Kernel::SharedPtr<Kernel::Event>> bind_node_events;
  36. // The WiFi network channel that the network is currently on.
  37. // Since we're not actually interacting with physical radio waves, this is just a dummy value.
  38. static u8 network_channel = DefaultNetworkChannel;
  39. // Information about the network that we're currently connected to.
  40. static NetworkInfo network_info;
  41. // Event that will generate and send the 802.11 beacon frames.
  42. static int beacon_broadcast_event;
  43. /**
  44. * NWM_UDS::Shutdown service function
  45. * Inputs:
  46. * 1 : None
  47. * Outputs:
  48. * 0 : Return header
  49. * 1 : Result of function, 0 on success, otherwise error code
  50. */
  51. static void Shutdown(Interface* self) {
  52. u32* cmd_buff = Kernel::GetCommandBuffer();
  53. // TODO(purpasmart): Verify return header on HW
  54. cmd_buff[1] = RESULT_SUCCESS.raw;
  55. LOG_WARNING(Service_NWM, "(STUBBED) called");
  56. }
  57. /**
  58. * NWM_UDS::RecvBeaconBroadcastData service function
  59. * Returns the raw beacon data for nearby networks that match the supplied WlanCommId.
  60. * Inputs:
  61. * 1 : Output buffer max size
  62. * 2-3 : Unknown
  63. * 4-5 : Host MAC address.
  64. * 6-14 : Unused
  65. * 15 : WLan Comm Id
  66. * 16 : Id
  67. * 17 : Value 0
  68. * 18 : Input handle
  69. * 19 : (Size<<4) | 12
  70. * 20 : Output buffer ptr
  71. * Outputs:
  72. * 0 : Return header
  73. * 1 : Result of function, 0 on success, otherwise error code
  74. */
  75. static void RecvBeaconBroadcastData(Interface* self) {
  76. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 16, 4);
  77. u32 out_buffer_size = rp.Pop<u32>();
  78. u32 unk1 = rp.Pop<u32>();
  79. u32 unk2 = rp.Pop<u32>();
  80. MacAddress mac_address;
  81. rp.PopRaw(mac_address);
  82. rp.Skip(9, false);
  83. u32 wlan_comm_id = rp.Pop<u32>();
  84. u32 id = rp.Pop<u32>();
  85. Kernel::Handle input_handle = rp.PopHandle();
  86. size_t desc_size;
  87. const VAddr out_buffer_ptr = rp.PopMappedBuffer(&desc_size);
  88. ASSERT(desc_size == out_buffer_size);
  89. VAddr current_buffer_pos = out_buffer_ptr;
  90. u32 total_size = sizeof(BeaconDataReplyHeader);
  91. // Retrieve all beacon frames that were received from the desired mac address.
  92. std::deque<WifiPacket> beacons =
  93. GetReceivedPackets(WifiPacket::PacketType::Beacon, mac_address);
  94. BeaconDataReplyHeader data_reply_header{};
  95. data_reply_header.total_entries = beacons.size();
  96. data_reply_header.max_output_size = out_buffer_size;
  97. Memory::WriteBlock(current_buffer_pos, &data_reply_header, sizeof(BeaconDataReplyHeader));
  98. current_buffer_pos += sizeof(BeaconDataReplyHeader);
  99. // Write each of the received beacons into the buffer
  100. for (const auto& beacon : beacons) {
  101. BeaconEntryHeader entry{};
  102. // TODO(Subv): Figure out what this size is used for.
  103. entry.unk_size = sizeof(BeaconEntryHeader) + beacon.data.size();
  104. entry.total_size = sizeof(BeaconEntryHeader) + beacon.data.size();
  105. entry.wifi_channel = beacon.channel;
  106. entry.header_size = sizeof(BeaconEntryHeader);
  107. entry.mac_address = beacon.transmitter_address;
  108. ASSERT(current_buffer_pos < out_buffer_ptr + out_buffer_size);
  109. Memory::WriteBlock(current_buffer_pos, &entry, sizeof(BeaconEntryHeader));
  110. current_buffer_pos += sizeof(BeaconEntryHeader);
  111. Memory::WriteBlock(current_buffer_pos, beacon.data.data(), beacon.data.size());
  112. current_buffer_pos += beacon.data.size();
  113. total_size += sizeof(BeaconEntryHeader) + beacon.data.size();
  114. }
  115. // Update the total size in the structure and write it to the buffer again.
  116. data_reply_header.total_size = total_size;
  117. Memory::WriteBlock(out_buffer_ptr, &data_reply_header, sizeof(BeaconDataReplyHeader));
  118. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  119. rb.Push(RESULT_SUCCESS);
  120. LOG_DEBUG(Service_NWM, "called out_buffer_size=0x%08X, wlan_comm_id=0x%08X, id=0x%08X,"
  121. "input_handle=0x%08X, out_buffer_ptr=0x%08X, unk1=0x%08X, unk2=0x%08X",
  122. out_buffer_size, wlan_comm_id, id, input_handle, out_buffer_ptr, unk1, unk2);
  123. }
  124. /**
  125. * NWM_UDS::Initialize service function
  126. * Inputs:
  127. * 1 : Shared memory size
  128. * 2-11 : Input NodeInfo Structure
  129. * 12 : 2-byte Version
  130. * 13 : Value 0
  131. * 14 : Shared memory handle
  132. * Outputs:
  133. * 0 : Return header
  134. * 1 : Result of function, 0 on success, otherwise error code
  135. * 2 : Value 0
  136. * 3 : Output event handle
  137. */
  138. static void InitializeWithVersion(Interface* self) {
  139. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1B, 12, 2);
  140. u32 sharedmem_size = rp.Pop<u32>();
  141. // Update the node information with the data the game gave us.
  142. rp.PopRaw(node_info[0]);
  143. u16 version = rp.Pop<u16>();
  144. Kernel::Handle sharedmem_handle = rp.PopHandle();
  145. recv_buffer_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(sharedmem_handle);
  146. ASSERT_MSG(recv_buffer_memory->size == sharedmem_size, "Invalid shared memory size.");
  147. // Reset the connection status, it contains all zeros after initialization,
  148. // except for the actual status value.
  149. connection_status = {};
  150. connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
  151. IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
  152. rb.Push(RESULT_SUCCESS);
  153. rb.PushCopyHandles(Kernel::g_handle_table.Create(connection_status_event).MoveFrom());
  154. LOG_DEBUG(Service_NWM, "called sharedmem_size=0x%08X, version=0x%08X, sharedmem_handle=0x%08X",
  155. sharedmem_size, version, sharedmem_handle);
  156. }
  157. /**
  158. * NWM_UDS::GetConnectionStatus service function.
  159. * Returns the connection status structure for the currently open network connection.
  160. * This structure contains information about the connection,
  161. * like the number of connected nodes, etc.
  162. * Inputs:
  163. * 0 : Command header.
  164. * Outputs:
  165. * 0 : Return header
  166. * 1 : Result of function, 0 on success, otherwise error code
  167. * 2-13 : Channel of the current WiFi network connection.
  168. */
  169. static void GetConnectionStatus(Interface* self) {
  170. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xB, 0, 0);
  171. IPC::RequestBuilder rb = rp.MakeBuilder(13, 0);
  172. rb.Push(RESULT_SUCCESS);
  173. rb.PushRaw(connection_status);
  174. // Reset the bitmask of changed nodes after each call to this
  175. // function to prevent falsely informing games of outstanding
  176. // changes in subsequent calls.
  177. connection_status.changed_nodes = 0;
  178. LOG_DEBUG(Service_NWM, "called");
  179. }
  180. /**
  181. * NWM_UDS::Bind service function.
  182. * Binds a BindNodeId to a data channel and retrieves a data event.
  183. * Inputs:
  184. * 1 : BindNodeId
  185. * 2 : Receive buffer size.
  186. * 3 : u8 Data channel to bind to.
  187. * 4 : Network node id.
  188. * Outputs:
  189. * 0 : Return header
  190. * 1 : Result of function, 0 on success, otherwise error code
  191. * 2 : Copy handle descriptor.
  192. * 3 : Data available event handle.
  193. */
  194. static void Bind(Interface* self) {
  195. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 4, 0);
  196. u32 bind_node_id = rp.Pop<u32>();
  197. u32 recv_buffer_size = rp.Pop<u32>();
  198. u8 data_channel = rp.Pop<u8>();
  199. u16 network_node_id = rp.Pop<u16>();
  200. // TODO(Subv): Store the data channel and verify it when receiving data frames.
  201. LOG_DEBUG(Service_NWM, "called");
  202. if (data_channel == 0) {
  203. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  204. rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS,
  205. ErrorSummary::WrongArgument, ErrorLevel::Usage));
  206. return;
  207. }
  208. // Create a new event for this bind node.
  209. // TODO(Subv): Signal this event when new data is received on this data channel.
  210. auto event = Kernel::Event::Create(Kernel::ResetType::OneShot,
  211. "NWM::BindNodeEvent" + std::to_string(bind_node_id));
  212. bind_node_events[bind_node_id] = event;
  213. IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
  214. rb.Push(RESULT_SUCCESS);
  215. rb.PushCopyHandles(Kernel::g_handle_table.Create(event).MoveFrom());
  216. }
  217. /**
  218. * NWM_UDS::BeginHostingNetwork service function.
  219. * Creates a network and starts broadcasting its presence.
  220. * Inputs:
  221. * 1 : Passphrase buffer size.
  222. * 3 : VAddr of the NetworkInfo structure.
  223. * 5 : VAddr of the passphrase.
  224. * Outputs:
  225. * 0 : Return header
  226. * 1 : Result of function, 0 on success, otherwise error code
  227. */
  228. static void BeginHostingNetwork(Interface* self) {
  229. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 1, 4);
  230. const u32 passphrase_size = rp.Pop<u32>();
  231. size_t desc_size;
  232. const VAddr network_info_address = rp.PopStaticBuffer(&desc_size, false);
  233. ASSERT(desc_size == sizeof(NetworkInfo));
  234. const VAddr passphrase_address = rp.PopStaticBuffer(&desc_size, false);
  235. ASSERT(desc_size == passphrase_size);
  236. // TODO(Subv): Store the passphrase and verify it when attempting a connection.
  237. LOG_DEBUG(Service_NWM, "called");
  238. Memory::ReadBlock(network_info_address, &network_info, sizeof(NetworkInfo));
  239. // The real UDS module throws a fatal error if this assert fails.
  240. ASSERT_MSG(network_info.max_nodes > 1, "Trying to host a network of only one member.");
  241. connection_status.status = static_cast<u32>(NetworkStatus::ConnectedAsHost);
  242. // Ensure the application data size is less than the maximum value.
  243. ASSERT_MSG(network_info.application_data_size <= ApplicationDataSize, "Data size is too big.");
  244. // Set up basic information for this network.
  245. network_info.oui_value = NintendoOUI;
  246. network_info.oui_type = static_cast<u8>(NintendoTagId::NetworkInfo);
  247. connection_status.max_nodes = network_info.max_nodes;
  248. // Resize the nodes list to hold max_nodes.
  249. node_info.resize(network_info.max_nodes);
  250. // There's currently only one node in the network (the host).
  251. connection_status.total_nodes = 1;
  252. network_info.total_nodes = 1;
  253. // The host is always the first node
  254. connection_status.network_node_id = 1;
  255. node_info[0].network_node_id = 1;
  256. connection_status.nodes[0] = connection_status.network_node_id;
  257. // Set the bit 0 in the nodes bitmask to indicate that node 1 is already taken.
  258. connection_status.node_bitmask |= 1;
  259. // Notify the application that the first node was set.
  260. connection_status.changed_nodes |= 1;
  261. // If the game has a preferred channel, use that instead.
  262. if (network_info.channel != 0)
  263. network_channel = network_info.channel;
  264. connection_status_event->Signal();
  265. // Start broadcasting the network, send a beacon frame every 102.4ms.
  266. CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU),
  267. beacon_broadcast_event, 0);
  268. LOG_WARNING(Service_NWM,
  269. "An UDS network has been created, but broadcasting it is unimplemented.");
  270. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  271. rb.Push(RESULT_SUCCESS);
  272. }
  273. /**
  274. * NWM_UDS::DestroyNetwork service function.
  275. * Closes the network that we're currently hosting.
  276. * Inputs:
  277. * 0 : Command header.
  278. * Outputs:
  279. * 0 : Return header
  280. * 1 : Result of function, 0 on success, otherwise error code
  281. */
  282. static void DestroyNetwork(Interface* self) {
  283. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 0, 0);
  284. // TODO(Subv): Find out what happens if this is called while
  285. // no network is being hosted.
  286. // Unschedule the beacon broadcast event.
  287. CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0);
  288. // TODO(Subv): Check if connection_status is indeed reset after this call.
  289. connection_status = {};
  290. connection_status.status = static_cast<u8>(NetworkStatus::NotConnected);
  291. connection_status_event->Signal();
  292. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  293. rb.Push(RESULT_SUCCESS);
  294. LOG_WARNING(Service_NWM, "called");
  295. }
  296. /**
  297. * NWM_UDS::SendTo service function.
  298. * Sends a data frame to the UDS network we're connected to.
  299. * Inputs:
  300. * 0 : Command header.
  301. * 1 : Unknown.
  302. * 2 : u16 Destination network node id.
  303. * 3 : u8 Data channel.
  304. * 4 : Buffer size >> 2
  305. * 5 : Data size
  306. * 6 : Flags
  307. * 7 : Input buffer descriptor
  308. * 8 : Input buffer address
  309. * Outputs:
  310. * 0 : Return header
  311. * 1 : Result of function, 0 on success, otherwise error code
  312. */
  313. static void SendTo(Interface* self) {
  314. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x17, 6, 2);
  315. rp.Skip(1, false);
  316. u16 dest_node_id = rp.Pop<u16>();
  317. u8 data_channel = rp.Pop<u8>();
  318. rp.Skip(1, false);
  319. u32 data_size = rp.Pop<u32>();
  320. u32 flags = rp.Pop<u32>();
  321. size_t desc_size;
  322. const VAddr input_address = rp.PopStaticBuffer(&desc_size, false);
  323. ASSERT(desc_size == data_size);
  324. // TODO(Subv): Figure out the error if this is called while not connected to a network.
  325. if (connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsClient) ||
  326. connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost)) {
  327. ASSERT_MSG(false, "Not connected to a network (unimplemented)");
  328. }
  329. // TODO(Subv): Do something with the flags.
  330. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  331. constexpr size_t MaxSize = 0x5C6;
  332. if (data_size > MaxSize) {
  333. rb.Push(ResultCode(ErrorDescription::TooLarge, ErrorModule::UDS,
  334. ErrorSummary::WrongArgument, ErrorLevel::Usage));
  335. return;
  336. }
  337. std::vector<u8> data(data_size);
  338. Memory::ReadBlock(input_address, data.data(), data.size());
  339. // TODO(Subv): Increment the sequence number after each sent packet.
  340. u16 sequence_number = 0;
  341. std::vector<u8> data_frame = GenerateDataFrame(data, data_channel, dest_node_id,
  342. connection_status.network_node_id,
  343. sequence_number);
  344. // TODO(Subv): Send the frame.
  345. rb.Push(RESULT_SUCCESS);
  346. LOG_WARNING(Service_NWM, "(STUB) called dest_node_id=%u size=%u flags=%u channel=%u",
  347. static_cast<u32>(dest_node_id), data_size, flags, static_cast<u32>(data_channel));
  348. }
  349. /**
  350. * NWM_UDS::GetChannel service function.
  351. * Returns the WiFi channel in which the network we're connected to is transmitting.
  352. * Inputs:
  353. * 0 : Command header.
  354. * Outputs:
  355. * 0 : Return header
  356. * 1 : Result of function, 0 on success, otherwise error code
  357. * 2 : Channel of the current WiFi network connection.
  358. */
  359. static void GetChannel(Interface* self) {
  360. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1A, 0, 0);
  361. IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
  362. bool is_connected = connection_status.status != static_cast<u32>(NetworkStatus::NotConnected);
  363. u8 channel = is_connected ? network_channel : 0;
  364. rb.Push(RESULT_SUCCESS);
  365. rb.Push(channel);
  366. LOG_DEBUG(Service_NWM, "called");
  367. }
  368. /**
  369. * NWM_UDS::SetApplicationData service function.
  370. * Updates the application data that is being broadcast in the beacon frames
  371. * for the network that we're hosting.
  372. * Inputs:
  373. * 1 : Data size.
  374. * 3 : VAddr of the data.
  375. * Outputs:
  376. * 0 : Return header
  377. * 1 : Result of function, 0 on success, otherwise error code
  378. * 2 : Channel of the current WiFi network connection.
  379. */
  380. static void SetApplicationData(Interface* self) {
  381. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1A, 1, 2);
  382. u32 size = rp.Pop<u32>();
  383. size_t desc_size;
  384. const VAddr address = rp.PopStaticBuffer(&desc_size, false);
  385. ASSERT(desc_size == size);
  386. LOG_DEBUG(Service_NWM, "called");
  387. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
  388. if (size > ApplicationDataSize) {
  389. rb.Push(ResultCode(ErrorDescription::TooLarge, ErrorModule::UDS,
  390. ErrorSummary::WrongArgument, ErrorLevel::Usage));
  391. return;
  392. }
  393. network_info.application_data_size = size;
  394. Memory::ReadBlock(address, network_info.application_data.data(), size);
  395. rb.Push(RESULT_SUCCESS);
  396. }
  397. /**
  398. * NWM_UDS::DecryptBeaconData service function.
  399. * Decrypts the encrypted data tags contained in the 802.11 beacons.
  400. * Inputs:
  401. * 1 : Input network struct buffer descriptor.
  402. * 2 : Input network struct buffer ptr.
  403. * 3 : Input tag0 encrypted buffer descriptor.
  404. * 4 : Input tag0 encrypted buffer ptr.
  405. * 5 : Input tag1 encrypted buffer descriptor.
  406. * 6 : Input tag1 encrypted buffer ptr.
  407. * 64 : Output buffer descriptor.
  408. * 65 : Output buffer ptr.
  409. * Outputs:
  410. * 0 : Return header
  411. * 1 : Result of function, 0 on success, otherwise error code
  412. */
  413. static void DecryptBeaconData(Interface* self) {
  414. IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 0, 6);
  415. size_t desc_size;
  416. const VAddr network_struct_addr = rp.PopStaticBuffer(&desc_size);
  417. ASSERT(desc_size == sizeof(NetworkInfo));
  418. size_t data0_size;
  419. const VAddr encrypted_data0_addr = rp.PopStaticBuffer(&data0_size);
  420. size_t data1_size;
  421. const VAddr encrypted_data1_addr = rp.PopStaticBuffer(&data1_size);
  422. size_t output_buffer_size;
  423. const VAddr output_buffer_addr = rp.PeekStaticBuffer(0, &output_buffer_size);
  424. // This size is hardcoded in the 3DS UDS code.
  425. ASSERT(output_buffer_size == sizeof(NodeInfo) * UDSMaxNodes);
  426. LOG_WARNING(Service_NWM, "called in0=%08X in1=%08X out=%08X", encrypted_data0_addr,
  427. encrypted_data1_addr, output_buffer_addr);
  428. NetworkInfo net_info;
  429. Memory::ReadBlock(network_struct_addr, &net_info, sizeof(net_info));
  430. // Read the encrypted data.
  431. // The first 4 bytes should be the OUI and the OUI Type of the tags.
  432. std::array<u8, 3> oui;
  433. Memory::ReadBlock(encrypted_data0_addr, oui.data(), oui.size());
  434. ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI");
  435. Memory::ReadBlock(encrypted_data1_addr, oui.data(), oui.size());
  436. ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI");
  437. ASSERT_MSG(Memory::Read8(encrypted_data0_addr + 3) ==
  438. static_cast<u8>(NintendoTagId::EncryptedData0),
  439. "Unexpected tag id");
  440. ASSERT_MSG(Memory::Read8(encrypted_data1_addr + 3) ==
  441. static_cast<u8>(NintendoTagId::EncryptedData1),
  442. "Unexpected tag id");
  443. std::vector<u8> beacon_data(data0_size + data1_size);
  444. Memory::ReadBlock(encrypted_data0_addr + 4, beacon_data.data(), data0_size);
  445. Memory::ReadBlock(encrypted_data1_addr + 4, beacon_data.data() + data0_size, data1_size);
  446. // Decrypt the data
  447. DecryptBeaconData(net_info, beacon_data);
  448. // The beacon data header contains the MD5 hash of the data.
  449. BeaconData beacon_header;
  450. std::memcpy(&beacon_header, beacon_data.data(), sizeof(beacon_header));
  451. // TODO(Subv): Verify the MD5 hash of the data and return 0xE1211005 if invalid.
  452. u8 num_nodes = net_info.max_nodes;
  453. std::vector<NodeInfo> nodes;
  454. for (int i = 0; i < num_nodes; ++i) {
  455. BeaconNodeInfo info;
  456. std::memcpy(&info, beacon_data.data() + sizeof(beacon_header) + i * sizeof(info),
  457. sizeof(info));
  458. // Deserialize the node information.
  459. NodeInfo node{};
  460. node.friend_code_seed = info.friend_code_seed;
  461. node.network_node_id = info.network_node_id;
  462. for (int i = 0; i < info.username.size(); ++i)
  463. node.username[i] = info.username[i];
  464. nodes.push_back(node);
  465. }
  466. Memory::ZeroBlock(output_buffer_addr, sizeof(NodeInfo) * UDSMaxNodes);
  467. Memory::WriteBlock(output_buffer_addr, nodes.data(), sizeof(NodeInfo) * nodes.size());
  468. IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
  469. rb.PushStaticBuffer(output_buffer_addr, output_buffer_size, 0);
  470. rb.Push(RESULT_SUCCESS);
  471. }
  472. // Sends a 802.11 beacon frame with information about the current network.
  473. static void BeaconBroadcastCallback(u64 userdata, int cycles_late) {
  474. // Don't do anything if we're not actually hosting a network
  475. if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost))
  476. return;
  477. // TODO(Subv): Actually send the beacon.
  478. std::vector<u8> frame = GenerateBeaconFrame(network_info, node_info);
  479. // Start broadcasting the network, send a beacon frame every 102.4ms.
  480. CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late,
  481. beacon_broadcast_event, 0);
  482. }
  483. const Interface::FunctionInfo FunctionTable[] = {
  484. {0x00010442, nullptr, "Initialize (deprecated)"},
  485. {0x00020000, nullptr, "Scrap"},
  486. {0x00030000, Shutdown, "Shutdown"},
  487. {0x00040402, nullptr, "CreateNetwork (deprecated)"},
  488. {0x00050040, nullptr, "EjectClient"},
  489. {0x00060000, nullptr, "EjectSpectator"},
  490. {0x00070080, nullptr, "UpdateNetworkAttribute"},
  491. {0x00080000, DestroyNetwork, "DestroyNetwork"},
  492. {0x00090442, nullptr, "ConnectNetwork (deprecated)"},
  493. {0x000A0000, nullptr, "DisconnectNetwork"},
  494. {0x000B0000, GetConnectionStatus, "GetConnectionStatus"},
  495. {0x000D0040, nullptr, "GetNodeInformation"},
  496. {0x000E0006, nullptr, "DecryptBeaconData (deprecated)"},
  497. {0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"},
  498. {0x00100042, SetApplicationData, "SetApplicationData"},
  499. {0x00110040, nullptr, "GetApplicationData"},
  500. {0x00120100, Bind, "Bind"},
  501. {0x00130040, nullptr, "Unbind"},
  502. {0x001400C0, nullptr, "PullPacket"},
  503. {0x00150080, nullptr, "SetMaxSendDelay"},
  504. {0x00170182, SendTo, "SendTo"},
  505. {0x001A0000, GetChannel, "GetChannel"},
  506. {0x001B0302, InitializeWithVersion, "InitializeWithVersion"},
  507. {0x001D0044, BeginHostingNetwork, "BeginHostingNetwork"},
  508. {0x001E0084, nullptr, "ConnectToNetwork"},
  509. {0x001F0006, DecryptBeaconData, "DecryptBeaconData"},
  510. {0x00200040, nullptr, "Flush"},
  511. {0x00210080, nullptr, "SetProbeResponseParam"},
  512. {0x00220402, nullptr, "ScanOnConnection"},
  513. };
  514. NWM_UDS::NWM_UDS() {
  515. connection_status_event =
  516. Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM::connection_status_event");
  517. Register(FunctionTable);
  518. beacon_broadcast_event =
  519. CoreTiming::RegisterEvent("UDS::BeaconBroadcastCallback", BeaconBroadcastCallback);
  520. }
  521. NWM_UDS::~NWM_UDS() {
  522. network_info = {};
  523. bind_node_events.clear();
  524. connection_status_event = nullptr;
  525. recv_buffer_memory = nullptr;
  526. connection_status = {};
  527. connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
  528. CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0);
  529. }
  530. } // namespace NWM
  531. } // namespace Service