summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/nwm/nwm_uds.cpp165
-rw-r--r--src/core/hle/service/nwm/nwm_uds.h12
-rw-r--r--src/core/hle/service/nwm/uds_beacon.cpp3
-rw-r--r--src/core/hle/service/nwm/uds_beacon.h30
-rw-r--r--src/core/hle/service/nwm/uds_connection.cpp79
-rw-r--r--src/core/hle/service/nwm/uds_connection.h51
7 files changed, 289 insertions, 53 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 662030782..78dec8600 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -145,6 +145,7 @@ set(SRCS
145 hle/service/nwm/nwm_tst.cpp 145 hle/service/nwm/nwm_tst.cpp
146 hle/service/nwm/nwm_uds.cpp 146 hle/service/nwm/nwm_uds.cpp
147 hle/service/nwm/uds_beacon.cpp 147 hle/service/nwm/uds_beacon.cpp
148 hle/service/nwm/uds_connection.cpp
148 hle/service/nwm/uds_data.cpp 149 hle/service/nwm/uds_data.cpp
149 hle/service/pm_app.cpp 150 hle/service/pm_app.cpp
150 hle/service/ptm/ptm.cpp 151 hle/service/ptm/ptm.cpp
@@ -344,6 +345,7 @@ set(HEADERS
344 hle/service/nwm/nwm_tst.h 345 hle/service/nwm/nwm_tst.h
345 hle/service/nwm/nwm_uds.h 346 hle/service/nwm/nwm_uds.h
346 hle/service/nwm/uds_beacon.h 347 hle/service/nwm/uds_beacon.h
348 hle/service/nwm/uds_connection.h
347 hle/service/nwm/uds_data.h 349 hle/service/nwm/uds_data.h
348 hle/service/pm_app.h 350 hle/service/pm_app.h
349 hle/service/ptm/ptm.h 351 hle/service/ptm/ptm.h
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index 6dbdff044..893bbb1e7 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -4,6 +4,7 @@
4 4
5#include <array> 5#include <array>
6#include <cstring> 6#include <cstring>
7#include <mutex>
7#include <unordered_map> 8#include <unordered_map>
8#include <vector> 9#include <vector>
9#include "common/common_types.h" 10#include "common/common_types.h"
@@ -15,8 +16,10 @@
15#include "core/hle/result.h" 16#include "core/hle/result.h"
16#include "core/hle/service/nwm/nwm_uds.h" 17#include "core/hle/service/nwm/nwm_uds.h"
17#include "core/hle/service/nwm/uds_beacon.h" 18#include "core/hle/service/nwm/uds_beacon.h"
19#include "core/hle/service/nwm/uds_connection.h"
18#include "core/hle/service/nwm/uds_data.h" 20#include "core/hle/service/nwm/uds_data.h"
19#include "core/memory.h" 21#include "core/memory.h"
22#include "network/network.h"
20 23
21namespace Service { 24namespace Service {
22namespace NWM { 25namespace NWM {
@@ -51,6 +54,135 @@ static NetworkInfo network_info;
51// Event that will generate and send the 802.11 beacon frames. 54// Event that will generate and send the 802.11 beacon frames.
52static int beacon_broadcast_event; 55static int beacon_broadcast_event;
53 56
57// Mutex to synchronize access to the list of received beacons between the emulation thread and the
58// network thread.
59static std::mutex beacon_mutex;
60
61// Number of beacons to store before we start dropping the old ones.
62// TODO(Subv): Find a more accurate value for this limit.
63constexpr size_t MaxBeaconFrames = 15;
64
65// List of the last <MaxBeaconFrames> beacons received from the network.
66static std::deque<Network::WifiPacket> received_beacons;
67
68/**
69 * Returns a list of received 802.11 beacon frames from the specified sender since the last call.
70 */
71std::deque<Network::WifiPacket> GetReceivedBeacons(const MacAddress& sender) {
72 std::lock_guard<std::mutex> lock(beacon_mutex);
73 // TODO(Subv): Filter by sender.
74 return std::move(received_beacons);
75}
76
77/// Sends a WifiPacket to the room we're currently connected to.
78void SendPacket(Network::WifiPacket& packet) {
79 // TODO(Subv): Implement.
80}
81
82// Inserts the received beacon frame in the beacon queue and removes any older beacons if the size
83// limit is exceeded.
84void HandleBeaconFrame(const Network::WifiPacket& packet) {
85 std::lock_guard<std::mutex> lock(beacon_mutex);
86
87 received_beacons.emplace_back(packet);
88
89 // Discard old beacons if the buffer is full.
90 if (received_beacons.size() > MaxBeaconFrames)
91 received_beacons.pop_front();
92}
93
94/*
95 * Returns an available index in the nodes array for the
96 * currently-hosted UDS network.
97 */
98static u16 GetNextAvailableNodeId() {
99 ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost),
100 "Can not accept clients if we're not hosting a network");
101
102 for (u16 index = 0; index < connection_status.max_nodes; ++index) {
103 if ((connection_status.node_bitmask & (1 << index)) == 0)
104 return index;
105 }
106
107 // Any connection attempts to an already full network should have been refused.
108 ASSERT_MSG(false, "No available connection slots in the network");
109}
110
111/*
112 * Start a connection sequence with an UDS server. The sequence starts by sending an 802.11
113 * authentication frame with SEQ1.
114 */
115void StartConnectionSequence(const MacAddress& server) {
116 ASSERT(connection_status.status == static_cast<u32>(NetworkStatus::NotConnected));
117
118 // TODO(Subv): Handle timeout.
119
120 // Send an authentication frame with SEQ1
121 using Network::WifiPacket;
122 WifiPacket auth_request;
123 auth_request.channel = network_channel;
124 auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ1);
125 auth_request.destination_address = server;
126 auth_request.type = WifiPacket::PacketType::Authentication;
127
128 SendPacket(auth_request);
129}
130
131/// Sends an Association Response frame to the specified mac address
132void SendAssociationResponseFrame(const MacAddress& address) {
133 ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost));
134
135 using Network::WifiPacket;
136 WifiPacket assoc_response;
137 assoc_response.channel = network_channel;
138 // TODO(Subv): This will cause multiple clients to end up with the same association id, but
139 // we're not using that for anything.
140 u16 association_id = 1;
141 assoc_response.data = GenerateAssocResponseFrame(AssocStatus::Successful, association_id,
142 network_info.network_id);
143 assoc_response.destination_address = address;
144 assoc_response.type = WifiPacket::PacketType::AssociationResponse;
145
146 SendPacket(assoc_response);
147}
148
149/*
150 * Handles the authentication request frame and sends the authentication response and association
151 * response frames. Once an Authentication frame with SEQ1 is received by the server, it responds
152 * with an Authentication frame containing SEQ2, and immediately sends an Association response frame
153 * containing the details of the access point and the assigned association id for the new client.
154 */
155void HandleAuthenticationFrame(const Network::WifiPacket& packet) {
156 // Only the SEQ1 auth frame is handled here, the SEQ2 frame doesn't need any special behavior
157 if (GetAuthenticationSeqNumber(packet.data) == AuthenticationSeq::SEQ1) {
158 ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost));
159
160 // Respond with an authentication response frame with SEQ2
161 using Network::WifiPacket;
162 WifiPacket auth_request;
163 auth_request.channel = network_channel;
164 auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ2);
165 auth_request.destination_address = packet.transmitter_address;
166 auth_request.type = WifiPacket::PacketType::Authentication;
167
168 SendPacket(auth_request);
169
170 SendAssociationResponseFrame(packet.transmitter_address);
171 }
172}
173
174/// Callback to parse and handle a received wifi packet.
175void OnWifiPacketReceived(const Network::WifiPacket& packet) {
176 switch (packet.type) {
177 case Network::WifiPacket::PacketType::Beacon:
178 HandleBeaconFrame(packet);
179 break;
180 case Network::WifiPacket::PacketType::Authentication:
181 HandleAuthenticationFrame(packet);
182 break;
183 }
184}
185
54/** 186/**
55 * NWM_UDS::Shutdown service function 187 * NWM_UDS::Shutdown service function
56 * Inputs: 188 * Inputs:
@@ -111,8 +243,7 @@ static void RecvBeaconBroadcastData(Interface* self) {
111 u32 total_size = sizeof(BeaconDataReplyHeader); 243 u32 total_size = sizeof(BeaconDataReplyHeader);
112 244
113 // Retrieve all beacon frames that were received from the desired mac address. 245 // Retrieve all beacon frames that were received from the desired mac address.
114 std::deque<WifiPacket> beacons = 246 auto beacons = GetReceivedBeacons(mac_address);
115 GetReceivedPackets(WifiPacket::PacketType::Beacon, mac_address);
116 247
117 BeaconDataReplyHeader data_reply_header{}; 248 BeaconDataReplyHeader data_reply_header{};
118 data_reply_header.total_entries = beacons.size(); 249 data_reply_header.total_entries = beacons.size();
@@ -193,6 +324,9 @@ static void InitializeWithVersion(Interface* self) {
193 rb.Push(RESULT_SUCCESS); 324 rb.Push(RESULT_SUCCESS);
194 rb.PushCopyHandles(Kernel::g_handle_table.Create(connection_status_event).Unwrap()); 325 rb.PushCopyHandles(Kernel::g_handle_table.Create(connection_status_event).Unwrap());
195 326
327 // TODO(Subv): Connect the OnWifiPacketReceived function to the wifi packet received callback of
328 // the room we're currently in.
329
196 LOG_DEBUG(Service_NWM, "called sharedmem_size=0x%08X, version=0x%08X, sharedmem_handle=0x%08X", 330 LOG_DEBUG(Service_NWM, "called sharedmem_size=0x%08X, version=0x%08X, sharedmem_handle=0x%08X",
197 sharedmem_size, version, sharedmem_handle); 331 sharedmem_size, version, sharedmem_handle);
198} 332}
@@ -610,32 +744,23 @@ static void BeaconBroadcastCallback(u64 userdata, int cycles_late) {
610 if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) 744 if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost))
611 return; 745 return;
612 746
613 // TODO(Subv): Actually send the beacon.
614 std::vector<u8> frame = GenerateBeaconFrame(network_info, node_info); 747 std::vector<u8> frame = GenerateBeaconFrame(network_info, node_info);
615 748
749 using Network::WifiPacket;
750 WifiPacket packet;
751 packet.type = WifiPacket::PacketType::Beacon;
752 packet.data = std::move(frame);
753 packet.destination_address = Network::BroadcastMac;
754 packet.channel = network_channel;
755
756 SendPacket(packet);
757
616 // Start broadcasting the network, send a beacon frame every 102.4ms. 758 // Start broadcasting the network, send a beacon frame every 102.4ms.
617 CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late, 759 CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late,
618 beacon_broadcast_event, 0); 760 beacon_broadcast_event, 0);
619} 761}
620 762
621/* 763/*
622 * Returns an available index in the nodes array for the
623 * currently-hosted UDS network.
624 */
625static u32 GetNextAvailableNodeId() {
626 ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost),
627 "Can not accept clients if we're not hosting a network");
628
629 for (unsigned index = 0; index < connection_status.max_nodes; ++index) {
630 if ((connection_status.node_bitmask & (1 << index)) == 0)
631 return index;
632 }
633
634 // Any connection attempts to an already full network should have been refused.
635 ASSERT_MSG(false, "No available connection slots in the network");
636}
637
638/*
639 * Called when a client connects to an UDS network we're hosting, 764 * Called when a client connects to an UDS network we're hosting,
640 * updates the connection status and signals the update event. 765 * updates the connection status and signals the update event.
641 * @param network_node_id Network Node Id of the connecting client. 766 * @param network_node_id Network Node Id of the connecting client.
diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h
index 141f49f9c..f1caaf974 100644
--- a/src/core/hle/service/nwm/nwm_uds.h
+++ b/src/core/hle/service/nwm/nwm_uds.h
@@ -42,6 +42,7 @@ using NodeList = std::vector<NodeInfo>;
42enum class NetworkStatus { 42enum class NetworkStatus {
43 NotConnected = 3, 43 NotConnected = 3,
44 ConnectedAsHost = 6, 44 ConnectedAsHost = 6,
45 Connecting = 7,
45 ConnectedAsClient = 9, 46 ConnectedAsClient = 9,
46 ConnectedAsSpectator = 10, 47 ConnectedAsSpectator = 10,
47}; 48};
@@ -85,6 +86,17 @@ static_assert(offsetof(NetworkInfo, oui_value) == 0xC, "oui_value is at the wron
85static_assert(offsetof(NetworkInfo, wlan_comm_id) == 0x10, "wlancommid is at the wrong offset."); 86static_assert(offsetof(NetworkInfo, wlan_comm_id) == 0x10, "wlancommid is at the wrong offset.");
86static_assert(sizeof(NetworkInfo) == 0x108, "NetworkInfo has incorrect size."); 87static_assert(sizeof(NetworkInfo) == 0x108, "NetworkInfo has incorrect size.");
87 88
89/// Additional block tag ids in the Beacon and Association Response frames
90enum class TagId : u8 {
91 SSID = 0,
92 SupportedRates = 1,
93 DSParameterSet = 2,
94 TrafficIndicationMap = 5,
95 CountryInformation = 7,
96 ERPInformation = 42,
97 VendorSpecific = 221
98};
99
88class NWM_UDS final : public Interface { 100class NWM_UDS final : public Interface {
89public: 101public:
90 NWM_UDS(); 102 NWM_UDS();
diff --git a/src/core/hle/service/nwm/uds_beacon.cpp b/src/core/hle/service/nwm/uds_beacon.cpp
index 6332b404c..552eaf65e 100644
--- a/src/core/hle/service/nwm/uds_beacon.cpp
+++ b/src/core/hle/service/nwm/uds_beacon.cpp
@@ -325,8 +325,5 @@ std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeL
325 return buffer; 325 return buffer;
326} 326}
327 327
328std::deque<WifiPacket> GetReceivedPackets(WifiPacket::PacketType type, const MacAddress& sender) {
329 return {};
330}
331} // namespace NWM 328} // namespace NWM
332} // namespace Service 329} // namespace Service
diff --git a/src/core/hle/service/nwm/uds_beacon.h b/src/core/hle/service/nwm/uds_beacon.h
index caacf4c6f..50cc76da2 100644
--- a/src/core/hle/service/nwm/uds_beacon.h
+++ b/src/core/hle/service/nwm/uds_beacon.h
@@ -17,17 +17,6 @@ namespace NWM {
17using MacAddress = std::array<u8, 6>; 17using MacAddress = std::array<u8, 6>;
18constexpr std::array<u8, 3> NintendoOUI = {0x00, 0x1F, 0x32}; 18constexpr std::array<u8, 3> NintendoOUI = {0x00, 0x1F, 0x32};
19 19
20/// Additional block tag ids in the Beacon frames
21enum class TagId : u8 {
22 SSID = 0,
23 SupportedRates = 1,
24 DSParameterSet = 2,
25 TrafficIndicationMap = 5,
26 CountryInformation = 7,
27 ERPInformation = 42,
28 VendorSpecific = 221
29};
30
31/** 20/**
32 * Internal vendor-specific tag ids as stored inside 21 * Internal vendor-specific tag ids as stored inside
33 * VendorSpecific blocks in the Beacon frames. 22 * VendorSpecific blocks in the Beacon frames.
@@ -135,20 +124,6 @@ struct BeaconData {
135 124
136static_assert(sizeof(BeaconData) == 0x12, "BeaconData has incorrect size."); 125static_assert(sizeof(BeaconData) == 0x12, "BeaconData has incorrect size.");
137 126
138/// Information about a received WiFi packet.
139/// Acts as our own 802.11 header.
140struct WifiPacket {
141 enum class PacketType { Beacon, Data };
142
143 PacketType type; ///< The type of 802.11 frame, Beacon / Data.
144
145 /// Raw 802.11 frame data, starting at the management frame header for management frames.
146 std::vector<u8> data;
147 MacAddress transmitter_address; ///< Mac address of the transmitter.
148 MacAddress destination_address; ///< Mac address of the receiver.
149 u8 channel; ///< WiFi channel where this frame was transmitted.
150};
151
152/** 127/**
153 * Decrypts the beacon data buffer for the network described by `network_info`. 128 * Decrypts the beacon data buffer for the network described by `network_info`.
154 */ 129 */
@@ -161,10 +136,5 @@ void DecryptBeaconData(const NetworkInfo& network_info, std::vector<u8>& buffer)
161 */ 136 */
162std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes); 137std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes);
163 138
164/**
165 * Returns a list of received 802.11 frames from the specified sender
166 * matching the type since the last call.
167 */
168std::deque<WifiPacket> GetReceivedPackets(WifiPacket::PacketType type, const MacAddress& sender);
169} // namespace NWM 139} // namespace NWM
170} // namespace Service 140} // namespace Service
diff --git a/src/core/hle/service/nwm/uds_connection.cpp b/src/core/hle/service/nwm/uds_connection.cpp
new file mode 100644
index 000000000..c8a76ec2a
--- /dev/null
+++ b/src/core/hle/service/nwm/uds_connection.cpp
@@ -0,0 +1,79 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/nwm/nwm_uds.h"
6#include "core/hle/service/nwm/uds_connection.h"
7#include "fmt/format.h"
8
9namespace Service {
10namespace NWM {
11
12// Note: These values were taken from a packet capture of an o3DS XL
13// broadcasting a Super Smash Bros. 4 lobby.
14constexpr u16 DefaultExtraCapabilities = 0x0431;
15
16std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq) {
17 AuthenticationFrame frame{};
18 frame.auth_seq = static_cast<u16>(seq);
19
20 std::vector<u8> data(sizeof(frame));
21 std::memcpy(data.data(), &frame, sizeof(frame));
22
23 return data;
24}
25
26AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body) {
27 AuthenticationFrame frame;
28 std::memcpy(&frame, body.data(), sizeof(frame));
29
30 return static_cast<AuthenticationSeq>(frame.auth_seq);
31}
32
33/**
34 * Generates an SSID tag of an 802.11 Beacon frame with an 8-byte character representation of the
35 * specified network id as the SSID value.
36 * @param network_id The network id to use.
37 * @returns A buffer with the SSID tag.
38 */
39static std::vector<u8> GenerateSSIDTag(u32 network_id) {
40 constexpr u8 SSIDSize = 8;
41
42 struct {
43 u8 id = static_cast<u8>(TagId::SSID);
44 u8 size = SSIDSize;
45 } tag_header;
46
47 std::vector<u8> buffer(sizeof(tag_header) + SSIDSize);
48
49 std::memcpy(buffer.data(), &tag_header, sizeof(tag_header));
50
51 std::string network_name = fmt::format("{0:08X}", network_id);
52
53 std::memcpy(buffer.data() + sizeof(tag_header), network_name.c_str(), SSIDSize);
54
55 return buffer;
56}
57
58std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_id, u32 network_id) {
59 AssociationResponseFrame frame{};
60 frame.capabilities = DefaultExtraCapabilities;
61 frame.status_code = static_cast<u16>(status);
62 // The association id is ORed with this magic value (0xC000)
63 constexpr u16 AssociationIdMagic = 0xC000;
64 frame.assoc_id = association_id | AssociationIdMagic;
65
66 std::vector<u8> data(sizeof(frame));
67 std::memcpy(data.data(), &frame, sizeof(frame));
68
69 auto ssid_tag = GenerateSSIDTag(network_id);
70 data.insert(data.end(), ssid_tag.begin(), ssid_tag.end());
71
72 // TODO(Subv): Add the SupportedRates tag.
73 // TODO(Subv): Add the DSParameterSet tag.
74 // TODO(Subv): Add the ERPInformation tag.
75 return data;
76}
77
78} // namespace NWM
79} // namespace Service
diff --git a/src/core/hle/service/nwm/uds_connection.h b/src/core/hle/service/nwm/uds_connection.h
new file mode 100644
index 000000000..73f55a4fd
--- /dev/null
+++ b/src/core/hle/service/nwm/uds_connection.h
@@ -0,0 +1,51 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include "common/common_types.h"
9#include "common/swap.h"
10#include "core/hle/service/service.h"
11
12namespace Service {
13namespace NWM {
14
15/// Sequence number of the 802.11 authentication frames.
16enum class AuthenticationSeq : u16 { SEQ1 = 1, SEQ2 = 2 };
17
18enum class AuthAlgorithm : u16 { OpenSystem = 0 };
19
20enum class AuthStatus : u16 { Successful = 0 };
21
22enum class AssocStatus : u16 { Successful = 0 };
23
24struct AuthenticationFrame {
25 u16_le auth_algorithm = static_cast<u16>(AuthAlgorithm::OpenSystem);
26 u16_le auth_seq;
27 u16_le status_code = static_cast<u16>(AuthStatus::Successful);
28};
29
30static_assert(sizeof(AuthenticationFrame) == 6, "AuthenticationFrame has wrong size");
31
32struct AssociationResponseFrame {
33 u16_le capabilities;
34 u16_le status_code;
35 u16_le assoc_id;
36};
37
38static_assert(sizeof(AssociationResponseFrame) == 6, "AssociationResponseFrame has wrong size");
39
40/// Generates an 802.11 authentication frame, starting at the frame body.
41std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq);
42
43/// Returns the sequence number from the body of an Authentication frame.
44AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body);
45
46/// Generates an 802.11 association response frame with the specified status, association id and
47/// network id, starting at the frame body.
48std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_id, u32 network_id);
49
50} // namespace NWM
51} // namespace Service