summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2022-08-01 17:37:49 -0400
committerGitHub <noreply@github.com>2022-08-01 17:37:49 -0400
commitcc1cb4499302b182e7b0da2103f3e32a4f2bc5e2 (patch)
tree0193446511783161d45785d76e3d5bcdd607a582 /Source/Core
parentfb45ed3981d4aaaaa55fcd16686bba68fed2c4f1 (diff)
parentbfc2d11891e12494e7ec0e70bb4594bcfea30798 (diff)
Merge pull request #10928 from sepalani/bba-arp
BBA/BuiltIn: Generate a MAC address for each new IP address
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp209
-rw-r--r--Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h9
2 files changed, 117 insertions, 101 deletions
diff --git a/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp b/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp
index 9e2a4dcca7..c02cb8585f 100644
--- a/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp
+++ b/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp
@@ -56,77 +56,6 @@ void SetIPIdentification(u8* ptr, std::size_t size, u16 value)
checksum_bitcast_ptr = u16(0);
checksum_bitcast_ptr = htons(Common::ComputeNetworkChecksum(ip_ptr, ip_header_size));
}
-
-std::optional<std::vector<u8>> TryGetDataFromSocket(StackRef* ref)
-{
- size_t datasize = 0; // Set by socket.receive using a non-const reference
- unsigned short remote_port;
-
- switch (ref->type)
- {
- case IPPROTO_UDP:
- {
- std::array<u8, MAX_UDP_LENGTH> buffer;
- ref->udp_socket.receive(buffer.data(), MAX_UDP_LENGTH, datasize, ref->target, remote_port);
- if (datasize > 0)
- {
- ref->from.sin_port = htons(remote_port);
- ref->from.sin_addr.s_addr = htonl(ref->target.toInteger());
- const std::vector<u8> udp_data(buffer.begin(), buffer.begin() + datasize);
- const Common::UDPPacket packet(ref->bba_mac, ref->my_mac, ref->from, ref->to, udp_data);
- return packet.Build();
- }
- break;
- }
-
- case IPPROTO_TCP:
- sf::Socket::Status st = sf::Socket::Status::Done;
- TcpBuffer* tcp_buffer = nullptr;
- for (auto& tcp_buf : ref->tcp_buffers)
- {
- if (tcp_buf.used)
- continue;
- tcp_buffer = &tcp_buf;
- break;
- }
-
- // set default size to 0 to avoid issue
- datasize = 0;
- const bool can_go = (GetTickCountStd() - ref->poke_time > 100 || ref->window_size > 2000);
- std::array<u8, MAX_TCP_LENGTH> buffer;
- if (tcp_buffer != nullptr && ref->ready && can_go)
- st = ref->tcp_socket.receive(buffer.data(), MAX_TCP_LENGTH, datasize);
-
- if (datasize > 0)
- {
- Common::TCPPacket packet(ref->bba_mac, ref->my_mac, ref->from, ref->to, ref->seq_num,
- ref->ack_num, TCP_FLAG_ACK);
- packet.data = std::vector<u8>(buffer.begin(), buffer.begin() + datasize);
-
- // build buffer
- tcp_buffer->seq_id = ref->seq_num;
- tcp_buffer->tick = GetTickCountStd();
- tcp_buffer->data = packet.Build();
- tcp_buffer->seq_id = ref->seq_num;
- tcp_buffer->used = true;
- ref->seq_num += static_cast<u32>(datasize);
- ref->poke_time = GetTickCountStd();
- return tcp_buffer->data;
- }
- if (GetTickCountStd() - ref->delay > 3000)
- {
- if (st == sf::Socket::Disconnected || st == sf::Socket::Error)
- {
- ref->ip = 0;
- ref->tcp_socket.disconnect();
- return BuildFINFrame(ref);
- }
- }
- break;
- }
-
- return std::nullopt;
-}
} // namespace
bool CEXIETHERNET::BuiltInBBAInterface::Activate()
@@ -137,13 +66,16 @@ bool CEXIETHERNET::BuiltInBBAInterface::Activate()
m_active = true;
for (auto& buf : m_queue_data)
buf.reserve(2048);
- m_fake_mac = Common::GenerateMacAddress(Common::MACConsumer::BBA);
// Workaround to get the host IP (might not be accurate)
const u32 ip = m_local_ip.empty() ? sf::IpAddress::getLocalAddress().toInteger() :
sf::IpAddress(m_local_ip).toInteger();
m_current_ip = htonl(ip);
+ m_current_mac = Common::BitCastPtr<Common::MACAddress>(&m_eth_ref->mBbaMem[BBA_NAFR_PAR0]);
+ m_arp_table[m_current_ip] = m_current_mac;
m_router_ip = (m_current_ip & 0xFFFFFF) | 0x01000000;
+ m_router_mac = Common::GenerateMacAddress(Common::MACConsumer::BBA);
+ m_arp_table[m_router_ip] = m_router_mac;
// clear all ref
for (auto& ref : network_ref)
@@ -174,6 +106,8 @@ void CEXIETHERNET::BuiltInBBAInterface::Deactivate()
ref.ip = 0;
}
+ m_arp_table.clear();
+
// Wait for read thread to exit.
if (m_read_thread.joinable())
m_read_thread.join();
@@ -195,20 +129,9 @@ void CEXIETHERNET::BuiltInBBAInterface::WriteToQueue(const std::vector<u8>& data
void CEXIETHERNET::BuiltInBBAInterface::HandleARP(const Common::ARPPacket& packet)
{
const auto& [hwdata, arpdata] = packet;
- const Common::MACAddress bba_mac =
- Common::BitCastPtr<Common::MACAddress>(&m_eth_ref->mBbaMem[BBA_NAFR_PAR0]);
- Common::ARPPacket response(bba_mac, m_fake_mac);
-
- if (arpdata.target_ip == m_current_ip)
- {
- // game asked for himself, reply with his mac address
- response.arp_header = Common::ARPHeader(arpdata.target_ip, bba_mac, m_current_ip, bba_mac);
- }
- else
- {
- response.arp_header = Common::ARPHeader(arpdata.target_ip, m_fake_mac, m_current_ip, bba_mac);
- }
-
+ Common::ARPPacket response(m_current_mac, m_router_mac);
+ response.arp_header = Common::ARPHeader(arpdata.target_ip, ResolveAddress(arpdata.target_ip),
+ m_current_ip, m_current_mac);
WriteToQueue(response.Build());
}
@@ -231,10 +154,8 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleDHCP(const Common::UDPPacket& pack
const std::vector<u8> timeout_24h = {0, 1, 0x51, 0x80};
- const Common::MACAddress bba_mac =
- Common::BitCastPtr<Common::MACAddress>(&m_eth_ref->mBbaMem[BBA_NAFR_PAR0]);
Common::DHCPPacket reply;
- reply.body = Common::DHCPBody(request.transaction_id, bba_mac, m_current_ip, m_router_ip);
+ reply.body = Common::DHCPBody(request.transaction_id, m_current_mac, m_current_ip, m_router_ip);
// options
// send our emulated lan settings
@@ -253,7 +174,7 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleDHCP(const Common::UDPPacket& pack
reply.AddOption(3, ip_part); // router ip
reply.AddOption(255, {}); // end
- const Common::UDPPacket response(bba_mac, m_fake_mac, from, to, reply.Build());
+ const Common::UDPPacket response(m_current_mac, m_router_mac, from, to, reply.Build());
WriteToQueue(response.Build());
}
@@ -288,6 +209,80 @@ StackRef* CEXIETHERNET::BuiltInBBAInterface::GetTCPSlot(u16 src_port, u16 dst_po
return nullptr;
}
+std::optional<std::vector<u8>>
+CEXIETHERNET::BuiltInBBAInterface::TryGetDataFromSocket(StackRef* ref)
+{
+ size_t datasize = 0; // Set by socket.receive using a non-const reference
+ unsigned short remote_port;
+
+ switch (ref->type)
+ {
+ case IPPROTO_UDP:
+ {
+ std::array<u8, MAX_UDP_LENGTH> buffer;
+ ref->udp_socket.receive(buffer.data(), MAX_UDP_LENGTH, datasize, ref->target, remote_port);
+ if (datasize > 0)
+ {
+ ref->from.sin_port = htons(remote_port);
+ const u32 remote_ip = htonl(ref->target.toInteger());
+ ref->from.sin_addr.s_addr = remote_ip;
+ ref->my_mac = ResolveAddress(remote_ip);
+ const std::vector<u8> udp_data(buffer.begin(), buffer.begin() + datasize);
+ const Common::UDPPacket packet(ref->bba_mac, ref->my_mac, ref->from, ref->to, udp_data);
+ return packet.Build();
+ }
+ break;
+ }
+
+ case IPPROTO_TCP:
+ sf::Socket::Status st = sf::Socket::Status::Done;
+ TcpBuffer* tcp_buffer = nullptr;
+ for (auto& tcp_buf : ref->tcp_buffers)
+ {
+ if (tcp_buf.used)
+ continue;
+ tcp_buffer = &tcp_buf;
+ break;
+ }
+
+ // set default size to 0 to avoid issue
+ datasize = 0;
+ const bool can_go = (GetTickCountStd() - ref->poke_time > 100 || ref->window_size > 2000);
+ std::array<u8, MAX_TCP_LENGTH> buffer;
+ if (tcp_buffer != nullptr && ref->ready && can_go)
+ st = ref->tcp_socket.receive(buffer.data(), MAX_TCP_LENGTH, datasize);
+
+ if (datasize > 0)
+ {
+ Common::TCPPacket packet(ref->bba_mac, ref->my_mac, ref->from, ref->to, ref->seq_num,
+ ref->ack_num, TCP_FLAG_ACK);
+ packet.data = std::vector<u8>(buffer.begin(), buffer.begin() + datasize);
+
+ // build buffer
+ tcp_buffer->seq_id = ref->seq_num;
+ tcp_buffer->tick = GetTickCountStd();
+ tcp_buffer->data = packet.Build();
+ tcp_buffer->seq_id = ref->seq_num;
+ tcp_buffer->used = true;
+ ref->seq_num += static_cast<u32>(datasize);
+ ref->poke_time = GetTickCountStd();
+ return tcp_buffer->data;
+ }
+ if (GetTickCountStd() - ref->delay > 3000)
+ {
+ if (st == sf::Socket::Disconnected || st == sf::Socket::Error)
+ {
+ ref->ip = 0;
+ ref->tcp_socket.disconnect();
+ return BuildFINFrame(ref);
+ }
+ }
+ break;
+ }
+
+ return std::nullopt;
+}
+
void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket& packet)
{
const auto& [hwdata, ip_header, tcp_header, ip_options, tcp_options, data] = packet;
@@ -322,12 +317,13 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket&
ref->type = IPPROTO_TCP;
for (auto& tcp_buf : ref->tcp_buffers)
tcp_buf.used = false;
- ref->from.sin_addr.s_addr = Common::BitCast<u32>(ip_header.destination_addr);
+ const u32 destination_ip = Common::BitCast<u32>(ip_header.destination_addr);
+ ref->from.sin_addr.s_addr = destination_ip;
ref->from.sin_port = tcp_header.destination_port;
ref->to.sin_addr.s_addr = Common::BitCast<u32>(ip_header.source_addr);
ref->to.sin_port = tcp_header.source_port;
- ref->bba_mac = Common::BitCastPtr<Common::MACAddress>(&m_eth_ref->mBbaMem[BBA_NAFR_PAR0]);
- ref->my_mac = m_fake_mac;
+ ref->bba_mac = m_current_mac;
+ ref->my_mac = ResolveAddress(destination_ip);
ref->tcp_socket.setBlocking(false);
// reply with a sin_ack
@@ -337,7 +333,7 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket&
result.tcp_options = {0x02, 0x04, 0x05, 0xb4, 0x01, 0x01, 0x01, 0x01};
ref->seq_num++;
- target = sf::IpAddress(ntohl(Common::BitCast<u32>(ip_header.destination_addr)));
+ target = sf::IpAddress(ntohl(destination_ip));
ref->tcp_socket.connect(target, ntohs(tcp_header.destination_port));
ref->ready = false;
ref->ip = Common::BitCast<u32>(ip_header.destination_addr);
@@ -417,8 +413,8 @@ void CEXIETHERNET::BuiltInBBAInterface::InitUDPPort(u16 port)
ref->local = htons(port);
ref->remote = htons(port);
ref->type = IPPROTO_UDP;
- ref->bba_mac = Common::BitCastPtr<Common::MACAddress>(&m_eth_ref->mBbaMem[BBA_NAFR_PAR0]);
- ref->my_mac = m_fake_mac;
+ ref->bba_mac = m_current_mac;
+ ref->my_mac = m_router_mac;
ref->from.sin_addr.s_addr = 0;
ref->from.sin_port = htons(port);
ref->to.sin_addr.s_addr = m_current_ip;
@@ -447,8 +443,8 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleUDPFrame(const Common::UDPPacket&
ref->local = udp_header.source_port;
ref->remote = udp_header.destination_port;
ref->type = IPPROTO_UDP;
- ref->bba_mac = Common::BitCastPtr<Common::MACAddress>(&m_eth_ref->mBbaMem[BBA_NAFR_PAR0]);
- ref->my_mac = m_fake_mac;
+ ref->bba_mac = m_current_mac;
+ ref->my_mac = m_router_mac;
ref->from.sin_addr.s_addr = destination_addr;
ref->from.sin_port = udp_header.destination_port;
ref->to.sin_addr.s_addr = Common::BitCast<u32>(ip_header.source_addr);
@@ -488,6 +484,21 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleUDPFrame(const Common::UDPPacket&
ref->udp_socket.send(data.data(), data.size(), target, ntohs(udp_header.destination_port));
}
+const Common::MACAddress& CEXIETHERNET::BuiltInBBAInterface::ResolveAddress(u32 inet_ip)
+{
+ auto it = m_arp_table.lower_bound(inet_ip);
+ if (it != m_arp_table.end() && it->first == inet_ip)
+ {
+ return it->second;
+ }
+ else
+ {
+ return m_arp_table
+ .emplace_hint(it, inet_ip, Common::GenerateMacAddress(Common::MACConsumer::BBA))
+ ->second;
+ }
+}
+
bool CEXIETHERNET::BuiltInBBAInterface::SendFrame(const u8* frame, u32 size)
{
std::lock_guard<std::mutex> lock(m_mtx);
@@ -613,7 +624,7 @@ void CEXIETHERNET::BuiltInBBAInterface::ReadThreadHandler(CEXIETHERNET::BuiltInB
{
if (net_ref.ip == 0)
continue;
- const auto socket_data = TryGetDataFromSocket(&net_ref);
+ const auto socket_data = self->TryGetDataFromSocket(&net_ref);
if (socket_data.has_value())
{
datasize = socket_data->size();
diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h b/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h
index 3ca1f26b01..4a6c4019f5 100644
--- a/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h
+++ b/Source/Core/Core/HW/EXI/EXI_DeviceEthernet.h
@@ -4,6 +4,8 @@
#pragma once
#include <atomic>
+#include <map>
+#include <mutex>
#include <thread>
#include <vector>
@@ -13,7 +15,6 @@
#include <SFML/Network.hpp>
-#include <mutex>
#include "Common/Flag.h"
#include "Common/Network.h"
#include "Core/HW/EXI/BBA/BuiltIn.h"
@@ -444,7 +445,10 @@ private:
std::mutex m_mtx;
std::string m_local_ip;
u32 m_current_ip = 0;
+ Common::MACAddress m_current_mac{};
u32 m_router_ip = 0;
+ Common::MACAddress m_router_mac{};
+ std::map<u32, Common::MACAddress> m_arp_table;
#if defined(WIN32) || defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__)
std::array<StackRef, 10> network_ref{}; // max 10 at same time, i think most gc game had a
@@ -452,18 +456,19 @@ private:
std::thread m_read_thread;
Common::Flag m_read_enabled;
Common::Flag m_read_thread_shutdown;
- Common::MACAddress m_fake_mac{};
static void ReadThreadHandler(BuiltInBBAInterface* self);
#endif
void WriteToQueue(const std::vector<u8>& data);
StackRef* GetAvailableSlot(u16 port);
StackRef* GetTCPSlot(u16 src_port, u16 dst_port, u32 ip);
+ std::optional<std::vector<u8>> TryGetDataFromSocket(StackRef* ref);
void HandleARP(const Common::ARPPacket& packet);
void HandleDHCP(const Common::UDPPacket& packet);
void HandleTCPFrame(const Common::TCPPacket& packet);
void InitUDPPort(u16 port);
void HandleUDPFrame(const Common::UDPPacket& packet);
+ const Common::MACAddress& ResolveAddress(u32 inet_ip);
};
std::unique_ptr<NetworkInterface> m_network_interface;