Expand Up
@@ -12,12 +12,123 @@
namespace ExpansionInterface
{
namespace
{
u64 GetTickCountStd ()
{
using namespace std ::chrono;
return duration_cast<milliseconds>(steady_clock::now ().time_since_epoch ()).count ();
}
std::vector<u8> 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<u8> 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<u16>(ip_id_ptr) = htons (value);
u8* const ip_checksum_ptr = ip_ptr + offsetof (Common::IPv4Header, header_checksum);
auto checksum_bitcast_ptr = Common::BitCastPtr<u16>(ip_checksum_ptr);
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 ()
{
if (IsActivated ())
Expand Down
Expand Up
@@ -142,7 +253,7 @@ void CEXIETHERNET::BuiltInBBAInterface::HandleDHCP(const Common::UDPPacket& pack
reply.AddOption (3 , ip_part); // router ip
reply.AddOption (255 , {}); // end
Common::UDPPacket response (bba_mac, m_fake_mac, from, to, reply.Build ());
const Common::UDPPacket response (bba_mac, m_fake_mac, from, to, reply.Build ());
WriteToQueue (response.Build ());
}
Expand Down
Expand Up
@@ -177,23 +288,6 @@ StackRef* CEXIETHERNET::BuiltInBBAInterface::GetTCPSlot(u16 src_port, u16 dst_po
return nullptr ;
}
std::vector<u8> BuildFINFrame (StackRef* ref)
{
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<u8> BuildAckFrame (StackRef* ref)
{
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;
Expand Down
Expand Up
@@ -482,97 +576,6 @@ bool CEXIETHERNET::BuiltInBBAInterface::SendFrame(const u8* frame, u32 size)
return true ;
}
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);
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;
}
// 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<u16>(ip_id_ptr) = htons (value);
u8* const ip_checksum_ptr = ip_ptr + offsetof (Common::IPv4Header, header_checksum);
auto checksum_bitcast_ptr = Common::BitCastPtr<u16>(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 ())
Expand Down