From 54411bef4eb16af0822820205a923690ea7e822a Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Mon, 17 Jul 2017 09:25:58 -0500
Subject: [PATCH] Services/UDS: Add functions to generate 802.11 auth and assoc
 response frames.

---
 src/core/CMakeLists.txt                     |  2 +
 src/core/hle/service/nwm/nwm_uds.h          | 12 ++++
 src/core/hle/service/nwm/uds_beacon.h       | 11 ---
 src/core/hle/service/nwm/uds_connection.cpp | 79 +++++++++++++++++++++
 src/core/hle/service/nwm/uds_connection.h   | 51 +++++++++++++
 5 files changed, 144 insertions(+), 11 deletions(-)
 create mode 100644 src/core/hle/service/nwm/uds_connection.cpp
 create mode 100644 src/core/hle/service/nwm/uds_connection.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index ea09819e5e..0719138afe 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -144,6 +144,7 @@ set(SRCS
             hle/service/nwm/nwm_tst.cpp
             hle/service/nwm/nwm_uds.cpp
             hle/service/nwm/uds_beacon.cpp
+            hle/service/nwm/uds_connection.cpp
             hle/service/nwm/uds_data.cpp
             hle/service/pm_app.cpp
             hle/service/ptm/ptm.cpp
@@ -342,6 +343,7 @@ set(HEADERS
             hle/service/nwm/nwm_tst.h
             hle/service/nwm/nwm_uds.h
             hle/service/nwm/uds_beacon.h
+            hle/service/nwm/uds_connection.h
             hle/service/nwm/uds_data.h
             hle/service/pm_app.h
             hle/service/ptm/ptm.h
diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h
index 141f49f9c0..f1caaf9746 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>;
 enum class NetworkStatus {
     NotConnected = 3,
     ConnectedAsHost = 6,
+    Connecting = 7,
     ConnectedAsClient = 9,
     ConnectedAsSpectator = 10,
 };
@@ -85,6 +86,17 @@ static_assert(offsetof(NetworkInfo, oui_value) == 0xC, "oui_value is at the wron
 static_assert(offsetof(NetworkInfo, wlan_comm_id) == 0x10, "wlancommid is at the wrong offset.");
 static_assert(sizeof(NetworkInfo) == 0x108, "NetworkInfo has incorrect size.");
 
+/// Additional block tag ids in the Beacon and Association Response frames
+enum class TagId : u8 {
+    SSID = 0,
+    SupportedRates = 1,
+    DSParameterSet = 2,
+    TrafficIndicationMap = 5,
+    CountryInformation = 7,
+    ERPInformation = 42,
+    VendorSpecific = 221
+};
+
 class NWM_UDS final : public Interface {
 public:
     NWM_UDS();
diff --git a/src/core/hle/service/nwm/uds_beacon.h b/src/core/hle/service/nwm/uds_beacon.h
index caacf4c6fa..c726b04d96 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 {
 using MacAddress = std::array<u8, 6>;
 constexpr std::array<u8, 3> NintendoOUI = {0x00, 0x1F, 0x32};
 
-/// Additional block tag ids in the Beacon frames
-enum class TagId : u8 {
-    SSID = 0,
-    SupportedRates = 1,
-    DSParameterSet = 2,
-    TrafficIndicationMap = 5,
-    CountryInformation = 7,
-    ERPInformation = 42,
-    VendorSpecific = 221
-};
-
 /**
  * Internal vendor-specific tag ids as stored inside
  * VendorSpecific blocks in the Beacon frames.
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 0000000000..c8a76ec2aa
--- /dev/null
+++ b/src/core/hle/service/nwm/uds_connection.cpp
@@ -0,0 +1,79 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_uds.h"
+#include "core/hle/service/nwm/uds_connection.h"
+#include "fmt/format.h"
+
+namespace Service {
+namespace NWM {
+
+// Note: These values were taken from a packet capture of an o3DS XL
+// broadcasting a Super Smash Bros. 4 lobby.
+constexpr u16 DefaultExtraCapabilities = 0x0431;
+
+std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq) {
+    AuthenticationFrame frame{};
+    frame.auth_seq = static_cast<u16>(seq);
+
+    std::vector<u8> data(sizeof(frame));
+    std::memcpy(data.data(), &frame, sizeof(frame));
+
+    return data;
+}
+
+AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body) {
+    AuthenticationFrame frame;
+    std::memcpy(&frame, body.data(), sizeof(frame));
+
+    return static_cast<AuthenticationSeq>(frame.auth_seq);
+}
+
+/**
+ * Generates an SSID tag of an 802.11 Beacon frame with an 8-byte character representation of the
+ * specified network id as the SSID value.
+ * @param network_id The network id to use.
+ * @returns A buffer with the SSID tag.
+ */
+static std::vector<u8> GenerateSSIDTag(u32 network_id) {
+    constexpr u8 SSIDSize = 8;
+
+    struct {
+        u8 id = static_cast<u8>(TagId::SSID);
+        u8 size = SSIDSize;
+    } tag_header;
+
+    std::vector<u8> buffer(sizeof(tag_header) + SSIDSize);
+
+    std::memcpy(buffer.data(), &tag_header, sizeof(tag_header));
+
+    std::string network_name = fmt::format("{0:08X}", network_id);
+
+    std::memcpy(buffer.data() + sizeof(tag_header), network_name.c_str(), SSIDSize);
+
+    return buffer;
+}
+
+std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_id, u32 network_id) {
+    AssociationResponseFrame frame{};
+    frame.capabilities = DefaultExtraCapabilities;
+    frame.status_code = static_cast<u16>(status);
+    // The association id is ORed with this magic value (0xC000)
+    constexpr u16 AssociationIdMagic = 0xC000;
+    frame.assoc_id = association_id | AssociationIdMagic;
+
+    std::vector<u8> data(sizeof(frame));
+    std::memcpy(data.data(), &frame, sizeof(frame));
+
+    auto ssid_tag = GenerateSSIDTag(network_id);
+    data.insert(data.end(), ssid_tag.begin(), ssid_tag.end());
+
+    // TODO(Subv): Add the SupportedRates tag.
+    // TODO(Subv): Add the DSParameterSet tag.
+    // TODO(Subv): Add the ERPInformation tag.
+    return data;
+}
+
+} // namespace NWM
+} // 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 0000000000..73f55a4fd9
--- /dev/null
+++ b/src/core/hle/service/nwm/uds_connection.h
@@ -0,0 +1,51 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+/// Sequence number of the 802.11 authentication frames.
+enum class AuthenticationSeq : u16 { SEQ1 = 1, SEQ2 = 2 };
+
+enum class AuthAlgorithm : u16 { OpenSystem = 0 };
+
+enum class AuthStatus : u16 { Successful = 0 };
+
+enum class AssocStatus : u16 { Successful = 0 };
+
+struct AuthenticationFrame {
+    u16_le auth_algorithm = static_cast<u16>(AuthAlgorithm::OpenSystem);
+    u16_le auth_seq;
+    u16_le status_code = static_cast<u16>(AuthStatus::Successful);
+};
+
+static_assert(sizeof(AuthenticationFrame) == 6, "AuthenticationFrame has wrong size");
+
+struct AssociationResponseFrame {
+    u16_le capabilities;
+    u16_le status_code;
+    u16_le assoc_id;
+};
+
+static_assert(sizeof(AssociationResponseFrame) == 6, "AssociationResponseFrame has wrong size");
+
+/// Generates an 802.11 authentication frame, starting at the frame body.
+std::vector<u8> GenerateAuthenticationFrame(AuthenticationSeq seq);
+
+/// Returns the sequence number from the body of an Authentication frame.
+AuthenticationSeq GetAuthenticationSeqNumber(const std::vector<u8>& body);
+
+/// Generates an 802.11 association response frame with the specified status, association id and
+/// network id, starting at the frame body.
+std::vector<u8> GenerateAssocResponseFrame(AssocStatus status, u16 association_id, u32 network_id);
+
+} // namespace NWM
+} // namespace Service
-- 
GitLab