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();
|
int offset = 8 + 2 * GetHardwareAddressLength() + GetProtocolAddressLength();
|
||||||
return &basePkt->data[offset];
|
return &basePkt->data[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ARP_PacketEditor::GetLength()
|
||||||
|
{
|
||||||
|
return 8 + 2 * GetHardwareAddressLength() + 2 * GetProtocolAddressLength();
|
||||||
|
}
|
||||||
} // namespace PacketReader::ARP
|
} // namespace PacketReader::ARP
|
||||||
|
|
|
@ -13,7 +13,6 @@ namespace PacketReader::ARP
|
||||||
PayloadPtr* basePkt;
|
PayloadPtr* basePkt;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ARP_PacketEditor(PayloadPtr* pkt);
|
ARP_PacketEditor(PayloadPtr* pkt);
|
||||||
|
|
||||||
u16 GetHardwareType();
|
u16 GetHardwareType();
|
||||||
|
@ -26,5 +25,7 @@ namespace PacketReader::ARP
|
||||||
u8* SenderProtocolAddress();
|
u8* SenderProtocolAddress();
|
||||||
u8* TargetHardwareAddress();
|
u8* TargetHardwareAddress();
|
||||||
u8* TargetProtocolAddress();
|
u8* TargetProtocolAddress();
|
||||||
|
|
||||||
|
int GetLength();
|
||||||
};
|
};
|
||||||
} // namespace PacketReader::ARP
|
} // namespace PacketReader::ARP
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: LGPL-3.0+
|
// SPDX-License-Identifier: LGPL-3.0+
|
||||||
|
|
||||||
#include "common/Assertions.h"
|
#include "common/Assertions.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#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.
|
// 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)
|
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).
|
// 1518 is the largest Ethernet frame we can get using 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.
|
// This includes the FCS, which should be trimmed (PS2 SDK dosn't allow extra space for this).
|
||||||
if (header->len > 1514)
|
if (header->len > 1518)
|
||||||
{
|
{
|
||||||
Console.Error("DEV9: Dropped jumbo frame of size: %u", header->len);
|
Console.Error("DEV9: Dropped jumbo frame of size: %u", header->len);
|
||||||
continue;
|
continue;
|
||||||
|
@ -142,6 +143,15 @@ bool PCAPAdapter::recv(NetPacket* pkt)
|
||||||
|
|
||||||
if (VerifyPkt(pkt, header->len))
|
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);
|
InspectRecv(pkt);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -366,3 +376,76 @@ void PCAPAdapter::SetMACBridgedSend(NetPacket* pkt)
|
||||||
}
|
}
|
||||||
frame.SetSourceMAC(hostMAC);
|
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 SetMACBridgedRecv(NetPacket* pkt);
|
||||||
void SetMACBridgedSend(NetPacket* pkt);
|
void SetMACBridgedSend(NetPacket* pkt);
|
||||||
|
|
||||||
|
void HandleFrameCheckSequence(NetPacket* pkt);
|
||||||
|
bool ValidateEtherFrame(NetPacket* pkt);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue