diff options
| author | 2017-09-05 15:03:56 +0300 | |
|---|---|---|
| committer | 2017-09-05 15:03:56 +0300 | |
| commit | 617b6974b992b010d2d9ca12e160433815464366 (patch) | |
| tree | 71da284291575d0d116e055d44b9251648c2602b | |
| parent | Merge pull request #2876 from mailwl/mii-stru (diff) | |
| parent | Services/UDS: Remove an old duplicated declaration of WifiPacket. (diff) | |
| download | yuzu-617b6974b992b010d2d9ca12e160433815464366.tar.gz yuzu-617b6974b992b010d2d9ca12e160433815464366.tar.xz yuzu-617b6974b992b010d2d9ca12e160433815464366.zip | |
Merge pull request #2831 from Subv/uds_auth
Services/UDS: Handle beacon frames and the basic AP connection sequence frames.
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/nwm_uds.cpp | 165 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/nwm_uds.h | 12 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_beacon.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_beacon.h | 30 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_connection.cpp | 79 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/uds_connection.h | 51 |
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 | ||
| 21 | namespace Service { | 24 | namespace Service { |
| 22 | namespace NWM { | 25 | namespace 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. |
| 52 | static int beacon_broadcast_event; | 55 | static 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. | ||
| 59 | static 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. | ||
| 63 | constexpr size_t MaxBeaconFrames = 15; | ||
| 64 | |||
| 65 | // List of the last <MaxBeaconFrames> beacons received from the network. | ||
| 66 | static 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 | */ | ||
| 71 | std::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. | ||
| 78 | void 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. | ||
| 84 | void 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 | */ | ||
| 98 | static 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 | */ | ||
| 115 | void 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 | ||
| 132 | void 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 | */ | ||
| 155 | void 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. | ||
| 175 | void 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 | */ | ||
| 625 | static 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>; | |||
| 42 | enum class NetworkStatus { | 42 | enum 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 | |||
| 85 | static_assert(offsetof(NetworkInfo, wlan_comm_id) == 0x10, "wlancommid is at the wrong offset."); | 86 | static_assert(offsetof(NetworkInfo, wlan_comm_id) == 0x10, "wlancommid is at the wrong offset."); |
| 86 | static_assert(sizeof(NetworkInfo) == 0x108, "NetworkInfo has incorrect size."); | 87 | static_assert(sizeof(NetworkInfo) == 0x108, "NetworkInfo has incorrect size."); |
| 87 | 88 | ||
| 89 | /// Additional block tag ids in the Beacon and Association Response frames | ||
| 90 | enum 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 | |||
| 88 | class NWM_UDS final : public Interface { | 100 | class NWM_UDS final : public Interface { |
| 89 | public: | 101 | public: |
| 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 | ||
| 328 | std::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 { | |||
| 17 | using MacAddress = std::array<u8, 6>; | 17 | using MacAddress = std::array<u8, 6>; |
| 18 | constexpr std::array<u8, 3> NintendoOUI = {0x00, 0x1F, 0x32}; | 18 | constexpr std::array<u8, 3> NintendoOUI = {0x00, 0x1F, 0x32}; |
| 19 | 19 | ||
| 20 | /// Additional block tag ids in the Beacon frames | ||
| 21 | enum 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 | ||
| 136 | static_assert(sizeof(BeaconData) == 0x12, "BeaconData has incorrect size."); | 125 | static_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. | ||
| 140 | struct 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 | */ |
| 162 | std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes); | 137 | std::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 | */ | ||
| 168 | std::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 | |||
| 9 | namespace Service { | ||
| 10 | namespace NWM { | ||
| 11 | |||
| 12 | // Note: These values were taken from a packet capture of an o3DS XL | ||
| 13 | // broadcasting a Super Smash Bros. 4 lobby. | ||
| 14 | constexpr u16 DefaultExtraCapabilities = 0x0431; | ||
| 15 | |||
| 16 | std::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 | |||
| 26 | AuthenticationSeq 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 | */ | ||
| 39 | static 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 | |||
| 58 | std::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 | |||
| 12 | namespace Service { | ||
| 13 | namespace NWM { | ||
| 14 | |||
| 15 | /// Sequence number of the 802.11 authentication frames. | ||
| 16 | enum class AuthenticationSeq : u16 { SEQ1 = 1, SEQ2 = 2 }; | ||
| 17 | |||
| 18 | enum class AuthAlgorithm : u16 { OpenSystem = 0 }; | ||
| 19 | |||
| 20 | enum class AuthStatus : u16 { Successful = 0 }; | ||
| 21 | |||
| 22 | enum class AssocStatus : u16 { Successful = 0 }; | ||
| 23 | |||
| 24 | struct 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 | |||
| 30 | static_assert(sizeof(AuthenticationFrame) == 6, "AuthenticationFrame has wrong size"); | ||
| 31 | |||
| 32 | struct AssociationResponseFrame { | ||
| 33 | u16_le capabilities; | ||
| 34 | u16_le status_code; | ||
| 35 | u16_le assoc_id; | ||
| 36 | }; | ||
| 37 | |||
| 38 | static_assert(sizeof(AssociationResponseFrame) == 6, "AssociationResponseFrame has wrong size"); | ||
| 39 | |||
| 40 | /// Generates an 802.11 authentication frame, starting at the frame body. | ||
| 41 | std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq); | ||
| 42 | |||
| 43 | /// Returns the sequence number from the body of an Authentication frame. | ||
| 44 | AuthenticationSeq 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. | ||
| 48 | std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_id, u32 network_id); | ||
| 49 | |||
| 50 | } // namespace NWM | ||
| 51 | } // namespace Service | ||