mirror of https://github.com/PCSX2/pcsx2.git
DEV9: Handle adapters that provide FCS in capture
This commit is contained in:
parent
6a37353565
commit
6aa57b7e87
|
@ -62,4 +62,9 @@ namespace PacketReader::ARP
|
|||
int offset = 8 + 2 * GetHardwareAddressLength() + GetProtocolAddressLength();
|
||||
return &basePkt->data[offset];
|
||||
}
|
||||
|
||||
int ARP_PacketEditor::GetLength()
|
||||
{
|
||||
return 8 + 2 * GetHardwareAddressLength() + 2 * GetProtocolAddressLength();
|
||||
}
|
||||
} // namespace PacketReader::ARP
|
||||
|
|
|
@ -13,7 +13,6 @@ namespace PacketReader::ARP
|
|||
PayloadPtr* basePkt;
|
||||
|
||||
public:
|
||||
|
||||
ARP_PacketEditor(PayloadPtr* pkt);
|
||||
|
||||
u16 GetHardwareType();
|
||||
|
@ -26,5 +25,7 @@ namespace PacketReader::ARP
|
|||
u8* SenderProtocolAddress();
|
||||
u8* TargetHardwareAddress();
|
||||
u8* TargetProtocolAddress();
|
||||
|
||||
int GetLength();
|
||||
};
|
||||
} // namespace PacketReader::ARP
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -124,9 +125,9 @@ bool PCAPAdapter::recv(NetPacket* pkt)
|
|||
// This delays getting packets we need, so instead loop untill a valid packet, or no packet, is returned from pcap_next_ex.
|
||||
while (pcap_next_ex(hpcap, &header, &pkt_data) > 0)
|
||||
{
|
||||
// 1514 is the largest etherframe we can get with an MTU of 1500 (assuming no VLAN tagging).
|
||||
// We don't (typically?) get the FCS, and we might need to strip it if we do.
|
||||
if (header->len > 1514)
|
||||
// 1518 is the largest Ethernet frame we can get using an MTU of 1500 (assuming no VLAN tagging).
|
||||
// This includes the FCS, which should be trimmed (PS2 SDK dosn't allow extra space for this).
|
||||
if (header->len > 1518)
|
||||
{
|
||||
Console.Error("DEV9: Dropped jumbo frame of size: %u", header->len);
|
||||
continue;
|
||||
|
@ -142,6 +143,15 @@ bool PCAPAdapter::recv(NetPacket* pkt)
|
|||
|
||||
if (VerifyPkt(pkt, header->len))
|
||||
{
|
||||
HandleFrameCheckSequence(pkt);
|
||||
|
||||
// FCS (if present) has been removed, apply correct limit
|
||||
if (pkt->size > 1514)
|
||||
{
|
||||
Console.Error("DEV9: Dropped jumbo frame of size: %u", pkt->size);
|
||||
continue;
|
||||
}
|
||||
|
||||
InspectRecv(pkt);
|
||||
return true;
|
||||
}
|
||||
|
@ -366,3 +376,76 @@ void PCAPAdapter::SetMACBridgedSend(NetPacket* pkt)
|
|||
}
|
||||
frame.SetSourceMAC(hostMAC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Strips the Frame Check Sequence if we manage to capture it.
|
||||
*
|
||||
* On Windows, (some?) Intel NICs can be configured to capture FCS.
|
||||
*
|
||||
* Linux can be configure to capture FCS, using `ethtool -K <interface> rx-fcs on` on supported devices.
|
||||
* Support for capturing FCS can be checked with `ethtool -k <interface> | grep rx-fcs`.
|
||||
* if it's `off [Fixed]`, then the interface/driver dosn't support capturing FCS.
|
||||
*
|
||||
* BSD based systems might capture FCS by default.
|
||||
*
|
||||
* Packets sent by host won't have FCS, We identify these packets by checking the source MAC address.
|
||||
* Packets sent by another application via packet injection also won't have FCS and may not match the adapter MAC.
|
||||
*/
|
||||
void PCAPAdapter::HandleFrameCheckSequence(NetPacket* pkt)
|
||||
{
|
||||
EthernetFrameEditor frame(pkt);
|
||||
if (frame.GetSourceMAC() == hostMAC)
|
||||
return;
|
||||
|
||||
// There is a (very) low chance of the last 4 bytes of payload somehow acting as a valid checksum for the whole Ethernet frame.
|
||||
// For EtherTypes we already can parse, trim the Ethernet frame based on the payload length.
|
||||
|
||||
int payloadSize = -1;
|
||||
if (frame.GetProtocol() == static_cast<u16>(EtherType::IPv4)) // IP
|
||||
{
|
||||
PayloadPtr* payload = frame.GetPayload();
|
||||
IP_Packet ippkt(payload->data, payload->GetLength());
|
||||
payloadSize = ippkt.GetLength();
|
||||
}
|
||||
if (frame.GetProtocol() == static_cast<u16>(EtherType::ARP)) // ARP
|
||||
{
|
||||
ARP_PacketEditor arpPkt(frame.GetPayload());
|
||||
payloadSize = arpPkt.GetLength();
|
||||
}
|
||||
|
||||
if (payloadSize != -1)
|
||||
{
|
||||
// Minumum frame size is 60 + 4 byte FCS.
|
||||
// Virtual NICs may omit this padding, so check we arn't increasing pkt size.
|
||||
payloadSize = std::min(std::max(payloadSize, 60 - frame.headerLength), pkt->size);
|
||||
|
||||
pkt->size = payloadSize + frame.headerLength;
|
||||
return;
|
||||
}
|
||||
|
||||
// Ethertype unknown, rely on checking for a FCS.
|
||||
if (ValidateEtherFrame(pkt))
|
||||
pkt->size -= 4;
|
||||
}
|
||||
|
||||
bool PCAPAdapter::ValidateEtherFrame(NetPacket* pkt)
|
||||
{
|
||||
u32 crc = 0xFFFFFFFF;
|
||||
|
||||
for (int i = 0; i < pkt->size; i++)
|
||||
{
|
||||
// Neads unsigned value
|
||||
crc = crc ^ static_cast<u8>(pkt->buffer[i]);
|
||||
for (int bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if ((crc & 1) != 0)
|
||||
crc = (crc >> 1) ^ 0xEDB88320;
|
||||
else
|
||||
crc = (crc >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
crc = ~crc;
|
||||
|
||||
return crc == 0x2144DF1C;
|
||||
}
|
||||
|
|
|
@ -42,4 +42,7 @@ private:
|
|||
|
||||
void SetMACBridgedRecv(NetPacket* pkt);
|
||||
void SetMACBridgedSend(NetPacket* pkt);
|
||||
|
||||
void HandleFrameCheckSequence(NetPacket* pkt);
|
||||
bool ValidateEtherFrame(NetPacket* pkt);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue