Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BBA: Added BuiltIn device that allow BBA emulation without the need o… #10690

Merged
merged 2 commits into from Jul 9, 2022

Conversation

schthack
Copy link
Contributor

…f a TapDevice Configuration include a dns server setting

This is the squish of all the previous requests in the previous PR. I will try to not mess up the rebase on nexts requested changes....

Copy link
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A quick first pass at this PR. I'll check the more technical bit, asap, such as:

Source/Core/Core/HW/EXI/BBA/BuiltIn.h Show resolved Hide resolved
@@ -18,6 +18,8 @@
#include "Core/HW/EXI/EXI.h"
#include "Core/HW/Memmap.h"

//#define BBA_TRACK_PAGE_PTRS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be removed or added in Dolphin's config system.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The #ifdef for this is preexisting so you don't have to convert this to a setting, but yeah probably remove this commented out line at least.

@@ -48,6 +48,15 @@ void BroadbandAdapterSettingsDialog::InitControls()
window_title = tr("Broadband Adapter MAC Address");
break;

case Type::BuiltIn:
address_label = new QLabel(tr("Enter the DNS server to use:"));
address_placeholder = QString::fromStdString("8.8.8.8");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be QStringLiteral("8.8.8.8").

#include "Core/HW/EXI/EXI_Device.h"
#include "Core/HW/EXI/EXI_DeviceEthernet.h"

// #define BBA_TRACK_PAGE_PTRS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be removed or part of Dolphin's config system.

m_current_ip = htonl(ip);
m_router_ip = (m_current_ip & 0xFFFFFF) | 0x01000000;
// clear all ref
for (int i = 0; i < std::size(network_ref); i++)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since network_ref is now a std::array, you can use a range-based for loop:

for (auto& ref : network_ref)
  ref.ip = 0;

void CEXIETHERNET::BuiltInBBAInterface::WriteToQueue(const u8* data, int length)
{
queue_data[queue_write].resize(length);
std::memcpy(&queue_data[queue_write][0], data, length);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

queue_data[queue_write].data() should work.

for (int i = 0; i < std::size(network_ref); i++)
{
if (network_ref[i].ip != 0 && network_ref[i].local == port)
return &network_ref[i];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A range-based for loop can used.

for (int i = 0; i < std::size(network_ref); i++)
{
if (network_ref[i].ip == 0)
return &network_ref[i];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A range-based for loop can used.

for (int i = 0; i < std::size(network_ref); i++)
{
if (network_ref[i].ip == ip && network_ref[i].remote == dst_port &&
network_ref[i].local == src_port)
{
return &network_ref[i];
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A range-based for loop can used.

if (self->queue_read != self->queue_write)
{
datasize = self->queue_data[self->queue_read].size();
std::memcpy(self->m_eth_ref->mRecvBuffer.get(), &self->queue_data[self->queue_read][0],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self->queue_data[self->queue_read].data() should work.

@@ -413,6 +418,60 @@ class CEXIETHERNET : public IEXIDevice
#endif
};

class BuiltInBBAInterface : public NetworkInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The member order in this class doesn't match our coding style guide, so unless there's a specific reason you have them like this please reorder them.

Also all of the member variables should have a prefixed m_, only some of them do currently.

@@ -706,4 +712,4 @@ endif()
if(MSVC)
# Add precompiled header
target_link_libraries(core PRIVATE use_pch)
endif()
endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You removed the end-of-file newline here.

ref->ip = 0x08080808; // change for ip
ref->local = htons(port);
ref->remote = htons(port);
ref->type = 17;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a magic number, can you name what this is?

ref->ip = *(u32*)ipdata->destination_addr; // change for ip
ref->local = udpdata->source_port;
ref->remote = udpdata->destination_port;
ref->type = 17;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

void HandleARP(Common::EthernetHeader* hwdata, Common::ARPHeader* arpdata);
void HandleDHCP(Common::EthernetHeader* hwdata, Common::UDPHeader* udpdata,
Common::DHCPBody* request);
StackRef* GetAvaibleSlot(u16 port);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo, Available.

InitUDPPort(26512); // MK DD and 1080
InitUDPPort(26502); // Air Ride
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you check/handle if these succeeded? Also, does it make sense to always open both of these?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they are opened only if port 1900 is used, there is no way to tell the game playing from the BBA point of view. This is also a hack to facilitate the communication, it's not 100% required to work. if you have a way to popup a warning without killing dolphin i would add a check. for now only an error log is displayed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want PanicAlertFmt().

}

std::tuple<Common::EthernetHeader*, Common::IPv4Header*, Common::TCPHeader*>
getTcpHeaders(u8* data, Common::MACAddress dest, Common::MACAddress src)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetTCPHeaders() per our coding guidelines.

}

std::tuple<Common::EthernetHeader*, Common::IPv4Header*, Common::UDPHeader*>
getUdpHeaders(u8* data, Common::MACAddress dest, Common::MACAddress src)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetUDPHeaders() per our coding guidelines.

Source/Core/Core/HW/EXI/BBA/BuiltIn.h Show resolved Hide resolved
// raise back if there is still data
if (page_ptr(BBA_RRP) != page_ptr(BBA_RWP))
{
if (mBbaMem[BBA_IMR] & INT_R)
{
mBbaMem[BBA_IR] |= INT_R;

exi_status.interrupt |= exi_status.TRANSFER;
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and a few other changes in this file look like bugfixes to the existing Ethernet device implementation, rather than directly part of your new built-in BBA implementation. Can you make a separate PR or at least a separate commit for this?

StackRef* ref = GetAvaibleSlot(htons(port));
if (ref == nullptr || ref->ip != 0)
return;
ref->ip = 0x08080808; // change for ip
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this use the configured DNS instead of a fixed IP...?

@nolrinale
Copy link
Contributor

Several other users and myself had been testing these builds throughly this whole month and it has been super stable on macOS, Linux and Windows as most of the deal breaker bugs have been squashed already weeks ago, functionality wise I think the feature is working as intended without side effects. And i've been running this for almost 24 hours permanently connected online most days just to make sure.

As a suggestion, in the current state, can this be merged into master as a first version? with the possibility to iterate from there in further PR's refining and optimising the code even more later on?

I would like to hear your thoughts about this

@JMC47
Copy link
Contributor

JMC47 commented May 23, 2022

Regardless of if it works or not, code quality issues need to be taken care of before it is merged.

@Arlisbloxer05
Copy link

yeah but like, at this point this is starting to seem more like suggestions rather than proper bug checking...

@AdmiralCurtiss
Copy link
Contributor

It's about maintainability, not just bug checking. You want to be able in 5 years to look back on this change and still understand why the code was written like it was, what it is doing, and why it is doing it. And while you can never be sure that this is true, since it's hard to predict the future and all, there's several places here that could stand to be improved with those criteria in mind.

void CEXIETHERNET::BuiltInBBAInterface::HandleARP(Common::EthernetHeader* hwdata,
Common::ARPHeader* arpdata)
{
std::memset(m_in_frame.get(), 0, 0x30);
Common::EthernetHeader* hwpart = (Common::EthernetHeader*)m_in_frame.get();
*hwpart = Common::EthernetHeader(ARP_PROTOCOL);
hwpart->destination = *(Common::MACAddress*)&m_eth_ref->mBbaMem[BBA_NAFR_PAR0];
hwpart->source = fake_mac;

Common::ARPHeader* arppart = (Common::ARPHeader*)&m_in_frame[14];
Common::MACAddress bba_mac = *(Common::MACAddress*)&m_eth_ref->mBbaMem[BBA_NAFR_PAR0];
if (arpdata->target_ip == m_current_ip)
{
// game asked for himself, reply with his mac address
*arppart = Common::ARPHeader(arpdata->target_ip, bba_mac, m_current_ip, bba_mac);
}
else
{
*arppart = Common::ARPHeader(arpdata->target_ip, fake_mac, m_current_ip, bba_mac);
}

WriteToQueue(&m_in_frame[0], 0x2a);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like, take this function for example. Regardless of if it works or not, there's several issues here that make it difficult to understand and possibly change in the future:

  • Magic numbers. Why is this memsetting 0x30 bytes to zero, but then only writing 0x2a of them? What do those bytes represent, even?
  • Lots of type punning that violates the C++ spec.
  • Even if it were allowed, it's hard to mentally process. The writes to hwpart and arppart do indirectly affect the data stored in m_in_frame!
  • And last but not least, why is this even writing to m_in_frame? Does something else rely on those 0x30 bytes being written? If so, where, and why is there no comment explaining that? If not, why is this not just a 0x30 bytes array on the stack instead?

This code is (unfortunately) full of things like this. These need to be fixed before it can be merged, or we're just creating headaches for future maintainers of this project.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i understands all those issue, sadly im far from being a guru of C++ and the code im digging in right now is far from your todays standard. Since it look like there is still tones of changes to do, I will push one last commit for most of what was requested today, then it would be nice if someone more knoledgeable in C++ could take over....
I can provide information on what it does, like in this case 0x30 fill is to clear the memory to ensure you get the proper value, the original reply was 0x30 and got reduced in the revisions, so 0x30 can now beacome 0x2a, i will review the size.

Most of the code was based on the tapdevice code as a starting point, why i use m_in_frame? beacause it was like that in the tap or xlink device. Im not saying this is the the right way, and i could of just reallocate a new buffer every time, just tought it was faster cpu side to not free/alloc memory, and it looked like this was used like that elsewhere too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's totally fair! The TAP code in particular is probably 10 years old and our standards were very different back then. And genuinely, I'm impressed you managed to get this to work at all if you're not very C++ knowledgeable.

If you want, someone else can definitely take this over and fix it up for you as long as you're willing to answer any questions we might have about the code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All valid points guys, thank you all for your hard work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can provide my Discord id to the team or the one taking over. I will be happy to awnser and fallow the result to learn more about c++.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devs usually hang out on IRC (Libera.Chat, #dolphin-dev), but if you prefer Discord join the unofficial Dolphin server and ask for some devs there, some of us are also there.

Copy link
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more comments regarding the code. I'll try find alternatives to get rid of these undefined behaviours.

{
int offset = 0;

std::memcpy(m_out_frame.get(), frame, size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_out_frame is only used here, so it doesn't need to be a member of the structure. This code should be equivalent:

int offset = 0;
std::vector<u8> out_frame(frame, frame+size);

The size is also never checked when inspecting the frame bytes so a buffer overflow can occur. I'll try to find a way to address this and the UB parts this code.

defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__)
std::array<StackRef, 10> network_ref{}; // max 10 at same time, i think most gc game had a
// limit of 8 in the gc framework
std::unique_ptr<u8[]> m_in_frame;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_in_frame is only used in Handle* methods when creating the frame to be sent. It can be created (as std::vector<u8>) in these Handle* methods instead of being a member variable.

// process queue file first
if (self->m_queue_read != self->m_queue_write)
{
datasize = self->m_queue_data[self->m_queue_read].size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT, mRecvBuffer size is BBA_RECV_SIZE and datasize isn't checked against it.

switch (ref->type)
{
case IPPROTO_UDP:
ref->udp_socket.receive(&buffer[0x2a], 1500, datasize, ref->target, remote_port);
Copy link
Contributor

@sepalani sepalani May 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does 1500 come from?

datasize = 0;
const bool can_go = (GetTickCountStd() - ref->poke_time > 100 || ref->window_size > 2000);
if (tcp_buffer != nullptr && ref->ready && can_go)
st = ref->tcp_socket.receive(&buffer[0x36], 440, datasize);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does 440 come from?

@AdmiralCurtiss
Copy link
Contributor

AdmiralCurtiss commented May 23, 2022

Tip: You can rebase this on current master (which now has the #10691 merged) by doing

git fetch upstream
git rebase upstream/master

(if you don't have upstream set first do git remote add upstream https://github.com/dolphin-emu/dolphin.git)

Then verify that it rebased properly, and if so

git push --force

to push it to this PR.

@sepalani
Copy link
Contributor

@AdmiralCurtiss @schthack
What do you think of this approach (master...sepalani:pr10690) to address the strict-aliasing and type-puning issues?

I used the PacketView class to read specific bytes in the stream. When enough information is gathered about the type of packet, BitCastPtr is used to return the specialised structure. For simplicity, I haven't implemented the options fields for the IPv4 and TCP header. I also tried my best not to change the code logic and refactor only the part using out_frame to illustrate this approach.

The code compiles, unfortunately, I have no way to test it to make sure I didn't introduce regressions. I also spotted endianness issues when accessing some structures like the EthernetHeader::ethertype and TCPHeader::properties that were accessed but not converted to the host endianness.

@schthack
Copy link
Contributor Author

So i guess something similar would be done to write the frame too?
IP and TCP header have variable size so some of the test need to be adjusted i think, and nice find for the endianness

@AdmiralCurtiss
Copy link
Contributor

AdmiralCurtiss commented May 24, 2022

Yes, I think that should work. I've made a few comments on the commit itself, too, and I think I spotted one behavior change, though it's unclear to me whether that behavior was intentional in the first place.

@sepalani
Copy link
Contributor

Yes, I think that should work. I've made a few comments on the commit itself, too, and I think I spotted one behavior change, though it's unclear to me whether that behavior was intentional in the first place.

Good catch, that was an oversight on my end.

So i guess something similar would be done to write the frame too?
IP and TCP header have variable size so some of the test need to be adjusted i think

Yeah, ideally something similar should be done when writing a frame. Regarding the TCP and IP header variable size, they can be taken into account. However, by doing so, it will make increase the code complexity (due to the variable size structure). If you're sure both are needed, I can implement them.

@schthack
Copy link
Contributor Author

However, by doing so, it will make increase the code complexity (due to the variable size structure). If you're sure both are needed, I can implement them.

including the extra data isnt needed, but adjusting the size test and data begining is needed. i havent ran into a special sized IP header but it can happen, for the TCP header i had multiple issue where the data is pushed futher beacause of partial ack and other TCP options

also if you want i can probably take that new code and test/fix

@sepalani
Copy link
Contributor

including the extra data isnt needed, but adjusting the size test and data begining is needed. i havent ran into a special sized IP header but it can happen, for the TCP header i had multiple issue where the data is pushed futher beacause of partial ack and other TCP options

also if you want i can probably take that new code and test/fix

Sure feel free to do so as I'm unable to test it unfortunately. You should be able to git cherry-pick and amend it if needed.

@schthack
Copy link
Contributor Author

schthack commented Jun 4, 2022

@AdmiralCurtiss @sepalani what do you think of those changes?

Copy link
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the reading approach is better. We came with similar approach (master...sepalani:pr10690) which makes me believe we are toward the right direction. I think I spotted some typos/mistakes (see my branch or the PR review).

I do believe that the packet building part can be improved (I haven't reach that part yet on my branch). For instance, when creating a TCP packet, we can fill the IP header with a lot of information since we know the IPProto (TCP) and might have the data to compute most fields. Ditto for the UDP packet building.

Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the time and effort you're putting into this. I found some other points that need to be addressed.

Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
datasize = socket_data.value().size();
std::memcpy(self->m_eth_ref->mRecvBuffer.get(), socket_data.value().data(), datasize);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

socket_data->size() and socket_data->data() should work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tryed, but VS is piss off

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is your error? The following piece of code works fine on my VS:

datasize = socket_data->size();
std::memcpy(self->m_eth_ref->mRecvBuffer.get(), socket_data->data(), datasize);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'data' n'est pas membre de 'std::optional<std::vector<u8,std::allocatorsf::Uint8>>'

in english: data is not a member of std.....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure you're using socket_data->data() instead of socket_data.data(). The former gets the vector contained inside the optional and then calls vector's data() function (which is what you want), while the latter tries to call optional's non-existent data() function.

Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
@nolrinale
Copy link
Contributor

Just to let you know, I continue testing rebuilding Dolphin with the latest changes of this branch every time a new commit appears, and so far, the BBA tapless mode has been working without issues with PSO Online even with all the refactoring you guys are doing.

As sepalani mentioned earlier, thank you for your hard work and patience.

@nolrinale
Copy link
Contributor

nolrinale commented Jun 8, 2022

There's a crash that happens with PSO very randomly (only with PSO Episode 1&2 btw) where the game freezes and cannot continue normal operation but Dolphin continues operating as usual.

I was told it could be useful for you to post these pics here in the exact memory pointers as it might be related to something that was included within the commits of this tapless PR

Frozen Frame (in-game) (notice the 0 FPS, the sound goes brrrrrrrrrrrrrrrrrrrrrrrrrrrr)
image

Affected Memory Address
Screenshot 2022-06-08 at 23 53 24

Affected Register
image

For the record this is from the latest binary I built from your very latest commit under macOS 12.4 0b9de57

@AdmiralCurtiss
Copy link
Contributor

So what's the status here?

@Kayak555
Copy link

Good question, we have many users using this and wondering when a merge is happening.

@schthack
Copy link
Contributor Author

havent had the time to work much on it, still have to change the way dhcp work + all those changes apear to have introduce some issue that we need to hunt

Copy link
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some improvements based on the latest commit changes.

I'll try to find the remaining lines of code infringing Dolphin coding style, asap. After that, I believe the code would be good enough for a some final review/comments before being tested and merged.

Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Common/Network.h Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
@schthack
Copy link
Contributor Author

change made. Also this morning i was looking at what someone did a while ago on android. and the "tap less" work fine
image

If it get merge at some point adding a menu for BBA might be nice

@nolrinale
Copy link
Contributor

Maybe you can add it to the [...] button under the Gamecube settings tab of the tapless adapter? Where you set the DNS's and such?

image

plenty of space to add the extra functionality that you currently have hidden such as the Mac Address setup, the settings for the local LAN gameplay, etc.

It gives the final user more granularity to adjust settings related to the Tapless BBA inner workings.

Copy link
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I found most coding style issues and some concerns about parts of the network code. Feel free to ask if you need help on some of these parts, BTW.

Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
{
Common::IPv4Header* ipdata = (Common::IPv4Header*)&b[14];
ipdata->identification = ntohs(++self->m_ip_frame_id);
ipdata->header_checksum = 0;
ipdata->header_checksum = htons(Common::ComputeNetworkChecksum(ipdata, 20));
}
self->m_eth_ref->mRecvBufferLength = datasize > 64 ? (u32)datasize : 64;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have mixed feelings about this part, there might be an aliasing issue and a checksum issue.

const std::size_t ip_offset = EthernetHeader::SIZE;
const std::size_t frame_id_offset = ip_offset + offsetof(Common::IPv4Header, identification);
Common::BitCastPtr<u16>(recv_buffer + frame_id_offset) = ntohs(++self->m_ip_frame_id);
const std::size_t ip_checksum_offset = ip_offset + offsetof(Common::IPv4Header, header_checksum);
// (...)
Common::BitCastPtr<u16>(recv_buffer + ip_checksum_offset) = ntohs(new_checksum);

Won't your current approach clobber the actual checksum and won't take into account the data stored after the IP header? Moreover, only a single uint16 which was zero initially was changed, can't a cheaper computation be done rather than computing the whole header checksum again?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The packet can be a resend, so the value isnt always 0, you have to recompute if it isnt. Also i will add support for options but those packet are made by the code and will never have options

Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
@AdmiralCurtiss
Copy link
Contributor

Uh, I dunno what you did but that was definitely not a rebase. The diff between this and current master is pretty clean at least so you could just take that and push that as a single commit, I guess?

@schthack
Copy link
Contributor Author

schthack commented Jul 1, 2022

@AdmiralCurtiss idid the fallowing:
git fetch upstream
git rebase upstream/master

nvm, i forgot to use git push --force instead of git push....
any idea on what can be done to fix that?

@AdmiralCurtiss
Copy link
Contributor

AdmiralCurtiss commented Jul 2, 2022

3d664454cbd52a0f9fc3bfea21a09059699aa04a is the last good commit I've seen, so starting from there:

git checkout BBA-tapless
git reset --hard 3d664454cbd52a0f9fc3bfea21a09059699aa04a
git cherry-pick f43a35b8e803c8cb3499d8ba92d2deb461fac61f

Then verify that you're in a correct state. If yes, rebase/push as normal. If no, you can go back to the current state with git reset --hard c330680bba2ddd95c7880bfeeccee66306543c0d.

…f a TapDevice Configuration include a dns server setting
@AdmiralCurtiss
Copy link
Contributor

Note for merge: I would prefer if at least 01ada38 stayed in the history of the merged PR so we have a reference to how this looked before the refactoring. So please don't squash into that.

@Kayak555
Copy link

Kayak555 commented Jul 6, 2022

So, what is the status of this?

@schthack
Copy link
Contributor Author

schthack commented Jul 6, 2022

@AdmiralCurtiss @sepalani Anything else you think need reworks?

Copy link
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beside these nitpicks and the commit history mentioned by @AdmiralCurtiss, the code looks mostly good to me.

Source/Core/Core/HW/EXI/EXI_DeviceEthernet.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
@AdmiralCurtiss
Copy link
Contributor

AdmiralCurtiss commented Jul 7, 2022

To be clear, I don't really care about how the rest of the commit history looks (there's a lot of commits in there that could certainly be squashed but whatever), but I do care that 01ada38 stays in the commit history as-is to have a pre-refactor reference in case we end up discovering a bug in the refactored code.

@AdmiralCurtiss
Copy link
Contributor

@sepalani Anything else? Otherwise we just need someone to test the current state and then I think we're good to go.

Source/Core/Common/Network.cpp Outdated Show resolved Hide resolved
Source/Core/Core/HW/EXI/BBA/BuiltIn.cpp Outdated Show resolved Hide resolved
void ChangeIPId(u8* buffer, const std::size_t size, const u16 new_val)
{
if (size < Common::EthernetHeader::SIZE + Common::IPv4Header::SIZE)
return;
Common::IPv4Header ip_header =
Common::BitCastPtr<Common::IPv4Header>(buffer + Common::EthernetHeader::SIZE);
ip_header.identification = htons(new_val);
ip_header.header_checksum = 0;
ip_header.header_checksum =
htons(Common::ComputeNetworkChecksum(&ip_header, ip_header.DefinedSize()));
Common::BitCastPtr<Common::IPv4Header>(buffer + Common::EthernetHeader::SIZE) = ip_header;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By having it there you won't need to pass the buffer and size parameters and can use m_ptr/m_size directly. This would give something like this:

void PacketView::SetIPIdentification(u16 value)
{
  if (m_size < Common::EthernetHeader::SIZE + Common::IPv4Header::SIZE)
    return;
  u8* ip_ptr = m_ptr + Common::EthernetHeader::SIZE;
  Common::IPv4Header ip_header = Common::BitCastPtr<Common::IPv4Header>(ip_ptr);
  ip_header.identification = htons(value);
  ip_header.header_checksum = 0;
  ip_header.header_checksum =
      htons(Common::ComputeNetworkChecksum(&ip_header, ip_header.DefinedSize()));
  Common::BitCastPtr<Common::IPv4Header>(ip_ptr) = ip_header;
}

I have one concern regarding the current approach, though. Won't this clobber the IPv4 options and result to an invalid checksum? Won't an approach using offsetof be safer?

@nolrinale
Copy link
Contributor

nolrinale commented Jul 8, 2022

@sepalani Anything else? Otherwise we just need someone to test the current state and then I think we're good to go.

Tested heavily after rebuilding this afternoon with the latest changes and it was still running as intended. No errors to report from my side.

At this point, several people had already tested this for several weeks in all 3 big platforms and from a functionality perspective is pretty solid, so it's more of a code compliance thing the three of you have to find a common ground on and decide the breakpoint between "good (and safe) enough" and what can be "Iterated/Improved at a later time" to proceed with the merge into master.

Copy link
Contributor

@sepalani sepalani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I unfortunately can't test this PR. The code SGTM regarding the coding style and I don't think it's UB anymore.

@AdmiralCurtiss
Copy link
Contributor

Can you squash the last commit into the one before it?

Changed access for offsetof + some clean up
@AdmiralCurtiss AdmiralCurtiss merged commit 5a7759e into dolphin-emu:master Jul 9, 2022
11 checks passed
@JMC47
Copy link
Contributor

JMC47 commented Jul 9, 2022

Congratulations on getting it merged, and thank you for your work on this.

@schthack
Copy link
Contributor Author

schthack commented Jul 9, 2022

@AdmiralCurtiss @sepalani Thank you for helping and your patience!

@JMC47
Copy link
Contributor

JMC47 commented Jul 24, 2022

I know this is a bit late, but I was testing this to get screenshots for the Progress Report, and I can't get Kirby Air Ride to connect. It errors out once the two GameCubes see one another. I'm using LAN because of the port issue when using a single computer. Any advice would be appreciated. I reported an issue with it if anyone else is interested. If there's any logging or testing I could do, or a way to test it on a single computer more easily instead of having to hook up other computers.

@JMC47
Copy link
Contributor

JMC47 commented Jul 24, 2022

A second issue has cropped up that is possibly my fault. I had my Laptop, my Desktop, and my phone all together working, and I accidentally unlimited the framerate from my desktop and that predictably disconnected them.

But now my laptop and my desktop won't see each other period and I don't know why. My laptop will connect to my phone and my desktop will connect to my phone, but laptop refuses to even see the desktop. If I try to link all three, Laptop + Desktop see 2 devices, where as the phone will see 3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
8 participants