Merge pull request #2831 from Subv/uds_auth
Services/UDS: Handle beacon frames and the basic AP connection sequence frames.
This commit is contained in:
commit
617b6974b9
|
@ -145,6 +145,7 @@ set(SRCS
|
||||||
hle/service/nwm/nwm_tst.cpp
|
hle/service/nwm/nwm_tst.cpp
|
||||||
hle/service/nwm/nwm_uds.cpp
|
hle/service/nwm/nwm_uds.cpp
|
||||||
hle/service/nwm/uds_beacon.cpp
|
hle/service/nwm/uds_beacon.cpp
|
||||||
|
hle/service/nwm/uds_connection.cpp
|
||||||
hle/service/nwm/uds_data.cpp
|
hle/service/nwm/uds_data.cpp
|
||||||
hle/service/pm_app.cpp
|
hle/service/pm_app.cpp
|
||||||
hle/service/ptm/ptm.cpp
|
hle/service/ptm/ptm.cpp
|
||||||
|
@ -344,6 +345,7 @@ set(HEADERS
|
||||||
hle/service/nwm/nwm_tst.h
|
hle/service/nwm/nwm_tst.h
|
||||||
hle/service/nwm/nwm_uds.h
|
hle/service/nwm/nwm_uds.h
|
||||||
hle/service/nwm/uds_beacon.h
|
hle/service/nwm/uds_beacon.h
|
||||||
|
hle/service/nwm/uds_connection.h
|
||||||
hle/service/nwm/uds_data.h
|
hle/service/nwm/uds_data.h
|
||||||
hle/service/pm_app.h
|
hle/service/pm_app.h
|
||||||
hle/service/ptm/ptm.h
|
hle/service/ptm/ptm.h
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -15,8 +16,10 @@
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
#include "core/hle/service/nwm/nwm_uds.h"
|
#include "core/hle/service/nwm/nwm_uds.h"
|
||||||
#include "core/hle/service/nwm/uds_beacon.h"
|
#include "core/hle/service/nwm/uds_beacon.h"
|
||||||
|
#include "core/hle/service/nwm/uds_connection.h"
|
||||||
#include "core/hle/service/nwm/uds_data.h"
|
#include "core/hle/service/nwm/uds_data.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
#include "network/network.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
namespace NWM {
|
namespace NWM {
|
||||||
|
@ -51,6 +54,135 @@ static NetworkInfo network_info;
|
||||||
// Event that will generate and send the 802.11 beacon frames.
|
// Event that will generate and send the 802.11 beacon frames.
|
||||||
static int beacon_broadcast_event;
|
static int beacon_broadcast_event;
|
||||||
|
|
||||||
|
// Mutex to synchronize access to the list of received beacons between the emulation thread and the
|
||||||
|
// network thread.
|
||||||
|
static std::mutex beacon_mutex;
|
||||||
|
|
||||||
|
// Number of beacons to store before we start dropping the old ones.
|
||||||
|
// TODO(Subv): Find a more accurate value for this limit.
|
||||||
|
constexpr size_t MaxBeaconFrames = 15;
|
||||||
|
|
||||||
|
// List of the last <MaxBeaconFrames> beacons received from the network.
|
||||||
|
static std::deque<Network::WifiPacket> received_beacons;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of received 802.11 beacon frames from the specified sender since the last call.
|
||||||
|
*/
|
||||||
|
std::deque<Network::WifiPacket> GetReceivedBeacons(const MacAddress& sender) {
|
||||||
|
std::lock_guard<std::mutex> lock(beacon_mutex);
|
||||||
|
// TODO(Subv): Filter by sender.
|
||||||
|
return std::move(received_beacons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends a WifiPacket to the room we're currently connected to.
|
||||||
|
void SendPacket(Network::WifiPacket& packet) {
|
||||||
|
// TODO(Subv): Implement.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inserts the received beacon frame in the beacon queue and removes any older beacons if the size
|
||||||
|
// limit is exceeded.
|
||||||
|
void HandleBeaconFrame(const Network::WifiPacket& packet) {
|
||||||
|
std::lock_guard<std::mutex> lock(beacon_mutex);
|
||||||
|
|
||||||
|
received_beacons.emplace_back(packet);
|
||||||
|
|
||||||
|
// Discard old beacons if the buffer is full.
|
||||||
|
if (received_beacons.size() > MaxBeaconFrames)
|
||||||
|
received_beacons.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns an available index in the nodes array for the
|
||||||
|
* currently-hosted UDS network.
|
||||||
|
*/
|
||||||
|
static u16 GetNextAvailableNodeId() {
|
||||||
|
ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost),
|
||||||
|
"Can not accept clients if we're not hosting a network");
|
||||||
|
|
||||||
|
for (u16 index = 0; index < connection_status.max_nodes; ++index) {
|
||||||
|
if ((connection_status.node_bitmask & (1 << index)) == 0)
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any connection attempts to an already full network should have been refused.
|
||||||
|
ASSERT_MSG(false, "No available connection slots in the network");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start a connection sequence with an UDS server. The sequence starts by sending an 802.11
|
||||||
|
* authentication frame with SEQ1.
|
||||||
|
*/
|
||||||
|
void StartConnectionSequence(const MacAddress& server) {
|
||||||
|
ASSERT(connection_status.status == static_cast<u32>(NetworkStatus::NotConnected));
|
||||||
|
|
||||||
|
// TODO(Subv): Handle timeout.
|
||||||
|
|
||||||
|
// Send an authentication frame with SEQ1
|
||||||
|
using Network::WifiPacket;
|
||||||
|
WifiPacket auth_request;
|
||||||
|
auth_request.channel = network_channel;
|
||||||
|
auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ1);
|
||||||
|
auth_request.destination_address = server;
|
||||||
|
auth_request.type = WifiPacket::PacketType::Authentication;
|
||||||
|
|
||||||
|
SendPacket(auth_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sends an Association Response frame to the specified mac address
|
||||||
|
void SendAssociationResponseFrame(const MacAddress& address) {
|
||||||
|
ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost));
|
||||||
|
|
||||||
|
using Network::WifiPacket;
|
||||||
|
WifiPacket assoc_response;
|
||||||
|
assoc_response.channel = network_channel;
|
||||||
|
// TODO(Subv): This will cause multiple clients to end up with the same association id, but
|
||||||
|
// we're not using that for anything.
|
||||||
|
u16 association_id = 1;
|
||||||
|
assoc_response.data = GenerateAssocResponseFrame(AssocStatus::Successful, association_id,
|
||||||
|
network_info.network_id);
|
||||||
|
assoc_response.destination_address = address;
|
||||||
|
assoc_response.type = WifiPacket::PacketType::AssociationResponse;
|
||||||
|
|
||||||
|
SendPacket(assoc_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handles the authentication request frame and sends the authentication response and association
|
||||||
|
* response frames. Once an Authentication frame with SEQ1 is received by the server, it responds
|
||||||
|
* with an Authentication frame containing SEQ2, and immediately sends an Association response frame
|
||||||
|
* containing the details of the access point and the assigned association id for the new client.
|
||||||
|
*/
|
||||||
|
void HandleAuthenticationFrame(const Network::WifiPacket& packet) {
|
||||||
|
// Only the SEQ1 auth frame is handled here, the SEQ2 frame doesn't need any special behavior
|
||||||
|
if (GetAuthenticationSeqNumber(packet.data) == AuthenticationSeq::SEQ1) {
|
||||||
|
ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost));
|
||||||
|
|
||||||
|
// Respond with an authentication response frame with SEQ2
|
||||||
|
using Network::WifiPacket;
|
||||||
|
WifiPacket auth_request;
|
||||||
|
auth_request.channel = network_channel;
|
||||||
|
auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ2);
|
||||||
|
auth_request.destination_address = packet.transmitter_address;
|
||||||
|
auth_request.type = WifiPacket::PacketType::Authentication;
|
||||||
|
|
||||||
|
SendPacket(auth_request);
|
||||||
|
|
||||||
|
SendAssociationResponseFrame(packet.transmitter_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Callback to parse and handle a received wifi packet.
|
||||||
|
void OnWifiPacketReceived(const Network::WifiPacket& packet) {
|
||||||
|
switch (packet.type) {
|
||||||
|
case Network::WifiPacket::PacketType::Beacon:
|
||||||
|
HandleBeaconFrame(packet);
|
||||||
|
break;
|
||||||
|
case Network::WifiPacket::PacketType::Authentication:
|
||||||
|
HandleAuthenticationFrame(packet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NWM_UDS::Shutdown service function
|
* NWM_UDS::Shutdown service function
|
||||||
* Inputs:
|
* Inputs:
|
||||||
|
@ -111,8 +243,7 @@ static void RecvBeaconBroadcastData(Interface* self) {
|
||||||
u32 total_size = sizeof(BeaconDataReplyHeader);
|
u32 total_size = sizeof(BeaconDataReplyHeader);
|
||||||
|
|
||||||
// Retrieve all beacon frames that were received from the desired mac address.
|
// Retrieve all beacon frames that were received from the desired mac address.
|
||||||
std::deque<WifiPacket> beacons =
|
auto beacons = GetReceivedBeacons(mac_address);
|
||||||
GetReceivedPackets(WifiPacket::PacketType::Beacon, mac_address);
|
|
||||||
|
|
||||||
BeaconDataReplyHeader data_reply_header{};
|
BeaconDataReplyHeader data_reply_header{};
|
||||||
data_reply_header.total_entries = beacons.size();
|
data_reply_header.total_entries = beacons.size();
|
||||||
|
@ -193,6 +324,9 @@ static void InitializeWithVersion(Interface* self) {
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushCopyHandles(Kernel::g_handle_table.Create(connection_status_event).Unwrap());
|
rb.PushCopyHandles(Kernel::g_handle_table.Create(connection_status_event).Unwrap());
|
||||||
|
|
||||||
|
// TODO(Subv): Connect the OnWifiPacketReceived function to the wifi packet received callback of
|
||||||
|
// the room we're currently in.
|
||||||
|
|
||||||
LOG_DEBUG(Service_NWM, "called sharedmem_size=0x%08X, version=0x%08X, sharedmem_handle=0x%08X",
|
LOG_DEBUG(Service_NWM, "called sharedmem_size=0x%08X, version=0x%08X, sharedmem_handle=0x%08X",
|
||||||
sharedmem_size, version, sharedmem_handle);
|
sharedmem_size, version, sharedmem_handle);
|
||||||
}
|
}
|
||||||
|
@ -610,31 +744,22 @@ static void BeaconBroadcastCallback(u64 userdata, int cycles_late) {
|
||||||
if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost))
|
if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO(Subv): Actually send the beacon.
|
|
||||||
std::vector<u8> frame = GenerateBeaconFrame(network_info, node_info);
|
std::vector<u8> frame = GenerateBeaconFrame(network_info, node_info);
|
||||||
|
|
||||||
|
using Network::WifiPacket;
|
||||||
|
WifiPacket packet;
|
||||||
|
packet.type = WifiPacket::PacketType::Beacon;
|
||||||
|
packet.data = std::move(frame);
|
||||||
|
packet.destination_address = Network::BroadcastMac;
|
||||||
|
packet.channel = network_channel;
|
||||||
|
|
||||||
|
SendPacket(packet);
|
||||||
|
|
||||||
// Start broadcasting the network, send a beacon frame every 102.4ms.
|
// Start broadcasting the network, send a beacon frame every 102.4ms.
|
||||||
CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late,
|
CoreTiming::ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU) - cycles_late,
|
||||||
beacon_broadcast_event, 0);
|
beacon_broadcast_event, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns an available index in the nodes array for the
|
|
||||||
* currently-hosted UDS network.
|
|
||||||
*/
|
|
||||||
static u32 GetNextAvailableNodeId() {
|
|
||||||
ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost),
|
|
||||||
"Can not accept clients if we're not hosting a network");
|
|
||||||
|
|
||||||
for (unsigned index = 0; index < connection_status.max_nodes; ++index) {
|
|
||||||
if ((connection_status.node_bitmask & (1 << index)) == 0)
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any connection attempts to an already full network should have been refused.
|
|
||||||
ASSERT_MSG(false, "No available connection slots in the network");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when a client connects to an UDS network we're hosting,
|
* Called when a client connects to an UDS network we're hosting,
|
||||||
* updates the connection status and signals the update event.
|
* updates the connection status and signals the update event.
|
||||||
|
|
|
@ -42,6 +42,7 @@ using NodeList = std::vector<NodeInfo>;
|
||||||
enum class NetworkStatus {
|
enum class NetworkStatus {
|
||||||
NotConnected = 3,
|
NotConnected = 3,
|
||||||
ConnectedAsHost = 6,
|
ConnectedAsHost = 6,
|
||||||
|
Connecting = 7,
|
||||||
ConnectedAsClient = 9,
|
ConnectedAsClient = 9,
|
||||||
ConnectedAsSpectator = 10,
|
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(offsetof(NetworkInfo, wlan_comm_id) == 0x10, "wlancommid is at the wrong offset.");
|
||||||
static_assert(sizeof(NetworkInfo) == 0x108, "NetworkInfo has incorrect size.");
|
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 {
|
class NWM_UDS final : public Interface {
|
||||||
public:
|
public:
|
||||||
NWM_UDS();
|
NWM_UDS();
|
||||||
|
|
|
@ -325,8 +325,5 @@ std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeL
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::deque<WifiPacket> GetReceivedPackets(WifiPacket::PacketType type, const MacAddress& sender) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
} // namespace NWM
|
} // namespace NWM
|
||||||
} // namespace Service
|
} // namespace Service
|
||||||
|
|
|
@ -17,17 +17,6 @@ namespace NWM {
|
||||||
using MacAddress = std::array<u8, 6>;
|
using MacAddress = std::array<u8, 6>;
|
||||||
constexpr std::array<u8, 3> NintendoOUI = {0x00, 0x1F, 0x32};
|
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
|
* Internal vendor-specific tag ids as stored inside
|
||||||
* VendorSpecific blocks in the Beacon frames.
|
* VendorSpecific blocks in the Beacon frames.
|
||||||
|
@ -135,20 +124,6 @@ struct BeaconData {
|
||||||
|
|
||||||
static_assert(sizeof(BeaconData) == 0x12, "BeaconData has incorrect size.");
|
static_assert(sizeof(BeaconData) == 0x12, "BeaconData has incorrect size.");
|
||||||
|
|
||||||
/// Information about a received WiFi packet.
|
|
||||||
/// Acts as our own 802.11 header.
|
|
||||||
struct WifiPacket {
|
|
||||||
enum class PacketType { Beacon, Data };
|
|
||||||
|
|
||||||
PacketType type; ///< The type of 802.11 frame, Beacon / Data.
|
|
||||||
|
|
||||||
/// Raw 802.11 frame data, starting at the management frame header for management frames.
|
|
||||||
std::vector<u8> data;
|
|
||||||
MacAddress transmitter_address; ///< Mac address of the transmitter.
|
|
||||||
MacAddress destination_address; ///< Mac address of the receiver.
|
|
||||||
u8 channel; ///< WiFi channel where this frame was transmitted.
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts the beacon data buffer for the network described by `network_info`.
|
* Decrypts the beacon data buffer for the network described by `network_info`.
|
||||||
*/
|
*/
|
||||||
|
@ -161,10 +136,5 @@ void DecryptBeaconData(const NetworkInfo& network_info, std::vector<u8>& buffer)
|
||||||
*/
|
*/
|
||||||
std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes);
|
std::vector<u8> GenerateBeaconFrame(const NetworkInfo& network_info, const NodeList& nodes);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of received 802.11 frames from the specified sender
|
|
||||||
* matching the type since the last call.
|
|
||||||
*/
|
|
||||||
std::deque<WifiPacket> GetReceivedPackets(WifiPacket::PacketType type, const MacAddress& sender);
|
|
||||||
} // namespace NWM
|
} // namespace NWM
|
||||||
} // namespace Service
|
} // namespace Service
|
||||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue