diff --git a/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp b/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp index 78ba89bc78..e3e4220196 100644 --- a/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp +++ b/Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp @@ -12,12 +12,123 @@ namespace ExpansionInterface { +namespace +{ u64 GetTickCountStd() { using namespace std::chrono; return duration_cast(steady_clock::now().time_since_epoch()).count(); } +std::vector BuildFINFrame(StackRef* ref) +{ + const Common::TCPPacket result(ref->bba_mac, ref->my_mac, ref->from, ref->to, ref->seq_num, + ref->ack_num, TCP_FLAG_FIN | TCP_FLAG_ACK | TCP_FLAG_RST); + + for (auto& tcp_buf : ref->tcp_buffers) + tcp_buf.used = false; + return result.Build(); +} + +std::vector BuildAckFrame(StackRef* ref) +{ + const Common::TCPPacket result(ref->bba_mac, ref->my_mac, ref->from, ref->to, ref->seq_num, + ref->ack_num, TCP_FLAG_ACK); + return result.Build(); +} + +// Change the IP identification and recompute the checksum +void SetIPIdentification(u8* ptr, std::size_t size, u16 value) +{ + if (size < Common::EthernetHeader::SIZE + Common::IPv4Header::SIZE) + return; + + u8* const ip_ptr = ptr + Common::EthernetHeader::SIZE; + const u8 ip_header_size = (*ip_ptr & 0xf) * 4; + if (size < Common::EthernetHeader::SIZE + ip_header_size) + return; + + u8* const ip_id_ptr = ip_ptr + offsetof(Common::IPv4Header, identification); + Common::BitCastPtr(ip_id_ptr) = htons(value); + + u8* const ip_checksum_ptr = ip_ptr + offsetof(Common::IPv4Header, header_checksum); + auto checksum_bitcast_ptr = Common::BitCastPtr(ip_checksum_ptr); + checksum_bitcast_ptr = u16(0); + checksum_bitcast_ptr = htons(Common::ComputeNetworkChecksum(ip_ptr, ip_header_size)); +} + +std::optional> 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 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 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 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(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(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() { if (IsActivated()) @@ -177,23 +288,6 @@ StackRef* CEXIETHERNET::BuiltInBBAInterface::GetTCPSlot(u16 src_port, u16 dst_po return nullptr; } -std::vector BuildFINFrame(StackRef* ref) -{ - const Common::TCPPacket result(ref->bba_mac, ref->my_mac, ref->from, ref->to, ref->seq_num, - ref->ack_num, TCP_FLAG_FIN | TCP_FLAG_ACK | TCP_FLAG_RST); - - for (auto& tcp_buf : ref->tcp_buffers) - tcp_buf.used = false; - return result.Build(); -} - -std::vector BuildAckFrame(StackRef* ref) -{ - const Common::TCPPacket result(ref->bba_mac, ref->my_mac, ref->from, ref->to, ref->seq_num, - ref->ack_num, TCP_FLAG_ACK); - return result.Build(); -} - void CEXIETHERNET::BuiltInBBAInterface::HandleTCPFrame(const Common::TCPPacket& packet) { const auto& [hwdata, ip_header, tcp_header, ip_options, tcp_options, data] = packet; @@ -482,97 +576,6 @@ bool CEXIETHERNET::BuiltInBBAInterface::SendFrame(const u8* frame, u32 size) return true; } -std::optional> 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 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 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 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(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(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; -} - -// Change the IP identification and recompute the checksum -static void SetIPIdentification(u8* ptr, std::size_t size, u16 value) -{ - if (size < Common::EthernetHeader::SIZE + Common::IPv4Header::SIZE) - return; - - u8* const ip_ptr = ptr + Common::EthernetHeader::SIZE; - const u8 ip_header_size = (*ip_ptr & 0xf) * 4; - if (size < Common::EthernetHeader::SIZE + ip_header_size) - return; - - u8* const ip_id_ptr = ip_ptr + offsetof(Common::IPv4Header, identification); - Common::BitCastPtr(ip_id_ptr) = htons(value); - - u8* const ip_checksum_ptr = ip_ptr + offsetof(Common::IPv4Header, header_checksum); - auto checksum_bitcast_ptr = Common::BitCastPtr(ip_checksum_ptr); - checksum_bitcast_ptr = u16(0); - checksum_bitcast_ptr = htons(Common::ComputeNetworkChecksum(ip_ptr, ip_header_size)); -} - void CEXIETHERNET::BuiltInBBAInterface::ReadThreadHandler(CEXIETHERNET::BuiltInBBAInterface* self) { while (!self->m_read_thread_shutdown.IsSet())