diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt
index cdedf6eb19..012ddd56b0 100644
--- a/pcsx2/CMakeLists.txt
+++ b/pcsx2/CMakeLists.txt
@@ -356,6 +356,10 @@ set(pcsx2DEV9Sources
DEV9/InternalServers/DHCP_Server.cpp
DEV9/InternalServers/DNS_Logger.cpp
DEV9/InternalServers/DNS_Server.cpp
+ DEV9/PacketReader/ARP/ARP_Packet.cpp
+ DEV9/PacketReader/IP/ICMP/ICMP_Packet.cpp
+ DEV9/PacketReader/IP/TCP/TCP_Options.cpp
+ DEV9/PacketReader/IP/TCP/TCP_Packet.cpp
DEV9/PacketReader/IP/UDP/DHCP/DHCP_Options.cpp
DEV9/PacketReader/IP/UDP/DHCP/DHCP_Packet.cpp
DEV9/PacketReader/IP/UDP/DNS/DNS_Classes.cpp
@@ -381,6 +385,10 @@ set(pcsx2DEV9Headers
DEV9/InternalServers/DNS_Logger.h
DEV9/InternalServers/DNS_Server.h
DEV9/net.h
+ DEV9/PacketReader/ARP/ARP_Packet.h
+ DEV9/PacketReader/IP/ICMP/ICMP_Packet.h
+ DEV9/PacketReader/IP/TCP/TCP_Options.h
+ DEV9/PacketReader/IP/TCP/TCP_Packet.h
DEV9/PacketReader/IP/UDP/DHCP/DHCP_Options.h
DEV9/PacketReader/IP/UDP/DHCP/DHCP_Packet.h
DEV9/PacketReader/IP/UDP/DNS/DNS_Classes.h
diff --git a/pcsx2/DEV9/PacketReader/ARP/ARP_Packet.cpp b/pcsx2/DEV9/PacketReader/ARP/ARP_Packet.cpp
new file mode 100644
index 0000000000..818687bd91
--- /dev/null
+++ b/pcsx2/DEV9/PacketReader/ARP/ARP_Packet.cpp
@@ -0,0 +1,98 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#include "PrecompiledHeader.h"
+
+#include "ARP_Packet.h"
+#include "DEV9/PacketReader/NetLib.h"
+
+namespace PacketReader::ARP
+{
+ ARP_Packet::ARP_Packet(u8 hwAddrLen, u8 procAddrLen)
+ : hardwareAddressLength{hwAddrLen}
+ , protocolAddressLength{procAddrLen}
+ , senderHardwareAddress{std::make_unique(hwAddrLen)}
+ , senderProtocolAddress{std::make_unique(procAddrLen)}
+ , targetHardwareAddress{std::make_unique(hwAddrLen)}
+ , targetProtocolAddress{std::make_unique(procAddrLen)}
+ {
+ }
+
+ ARP_Packet::ARP_Packet(u8* buffer, int bufferSize)
+ {
+ int offset = 0;
+
+ NetLib::ReadUInt16(buffer, &offset, &hardwareType);
+ NetLib::ReadUInt16(buffer, &offset, &protocol);
+ //
+ NetLib::ReadByte08(buffer, &offset, &hardwareAddressLength);
+ NetLib::ReadByte08(buffer, &offset, &protocolAddressLength);
+
+ NetLib::ReadUInt16(buffer, &offset, &op);
+
+ //Allocate arrays
+ senderHardwareAddress = std::make_unique(hardwareAddressLength);
+ senderProtocolAddress = std::make_unique(protocolAddressLength);
+ targetHardwareAddress = std::make_unique(hardwareAddressLength);
+ targetProtocolAddress = std::make_unique(protocolAddressLength);
+
+ //Assume normal MAC/IP address lengths for logging
+
+ NetLib::ReadByteArray(buffer, &offset, hardwareAddressLength, senderHardwareAddress.get());
+ NetLib::ReadByteArray(buffer, &offset, protocolAddressLength, senderProtocolAddress.get());
+
+ NetLib::ReadByteArray(buffer, &offset, hardwareAddressLength, targetHardwareAddress.get());
+ NetLib::ReadByteArray(buffer, &offset, protocolAddressLength, targetProtocolAddress.get());
+ }
+ ARP_Packet::ARP_Packet(const ARP_Packet& original)
+ : hardwareType{original.hardwareType}
+ , protocol{original.protocol}
+ , hardwareAddressLength{original.hardwareAddressLength}
+ , protocolAddressLength{original.protocolAddressLength}
+ , op{original.protocol}
+ , senderHardwareAddress{std::make_unique(original.hardwareAddressLength)}
+ , senderProtocolAddress{std::make_unique(original.protocolAddressLength)}
+ , targetHardwareAddress{std::make_unique(original.hardwareAddressLength)}
+ , targetProtocolAddress{std::make_unique(original.protocolAddressLength)}
+ {
+ memcpy(senderHardwareAddress.get(), original.senderHardwareAddress.get(), hardwareAddressLength);
+ memcpy(senderProtocolAddress.get(), original.senderProtocolAddress.get(), protocolAddressLength);
+ memcpy(targetHardwareAddress.get(), original.targetHardwareAddress.get(), hardwareAddressLength);
+ memcpy(targetProtocolAddress.get(), original.targetProtocolAddress.get(), protocolAddressLength);
+ }
+
+ int ARP_Packet::GetLength()
+ {
+ return 8 + 2 * hardwareAddressLength + 2 * protocolAddressLength;
+ }
+
+ void ARP_Packet::WriteBytes(u8* buffer, int* offset)
+ {
+ NetLib::WriteUInt16(buffer, offset, hardwareType);
+ NetLib::WriteUInt16(buffer, offset, protocol);
+ NetLib::WriteByte08(buffer, offset, hardwareAddressLength);
+ NetLib::WriteByte08(buffer, offset, protocolAddressLength);
+ NetLib::WriteUInt16(buffer, offset, op);
+ NetLib::WriteByteArray(buffer, offset, hardwareAddressLength, senderHardwareAddress.get());
+ NetLib::WriteByteArray(buffer, offset, protocolAddressLength, senderProtocolAddress.get());
+ NetLib::WriteByteArray(buffer, offset, hardwareAddressLength, targetHardwareAddress.get());
+ NetLib::WriteByteArray(buffer, offset, protocolAddressLength, targetProtocolAddress.get());
+ }
+
+ ARP_Packet* ARP_Packet::Clone() const
+ {
+ return new ARP_Packet(*this);
+ }
+} // namespace PacketReader::ARP
diff --git a/pcsx2/DEV9/PacketReader/ARP/ARP_Packet.h b/pcsx2/DEV9/PacketReader/ARP/ARP_Packet.h
new file mode 100644
index 0000000000..64517f66f1
--- /dev/null
+++ b/pcsx2/DEV9/PacketReader/ARP/ARP_Packet.h
@@ -0,0 +1,44 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#pragma once
+#include
+
+#include "DEV9/PacketReader/Payload.h"
+
+namespace PacketReader::ARP
+{
+ class ARP_Packet : public Payload
+ {
+ public:
+ u16 hardwareType;
+ u16 protocol;
+ u8 hardwareAddressLength = 6;
+ u8 protocolAddressLength = 4;
+ u16 op;
+ std::unique_ptr senderHardwareAddress;
+ std::unique_ptr senderProtocolAddress;
+ std::unique_ptr targetHardwareAddress;
+ std::unique_ptr targetProtocolAddress;
+
+ ARP_Packet(u8 hwAddrLen, u8 procAddrLen);
+ ARP_Packet(u8* buffer, int bufferSize);
+ ARP_Packet(const ARP_Packet&);
+
+ virtual int GetLength();
+ virtual void WriteBytes(u8* buffer, int* offset);
+ virtual ARP_Packet* Clone() const;
+ };
+} // namespace PacketReader::ARP
diff --git a/pcsx2/DEV9/PacketReader/IP/ICMP/ICMP_Packet.cpp b/pcsx2/DEV9/PacketReader/IP/ICMP/ICMP_Packet.cpp
new file mode 100644
index 0000000000..44aa35cab6
--- /dev/null
+++ b/pcsx2/DEV9/PacketReader/IP/ICMP/ICMP_Packet.cpp
@@ -0,0 +1,124 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#include "PrecompiledHeader.h"
+
+#include "ICMP_Packet.h"
+#include "DEV9/PacketReader/NetLib.h"
+
+namespace PacketReader::IP::ICMP
+{
+ ICMP_Packet::ICMP_Packet(Payload* data)
+ : payload{data}
+ {
+ }
+ ICMP_Packet::ICMP_Packet(u8* buffer, int bufferSize)
+ {
+ int offset = 0;
+ //Bits 0-31
+ NetLib::ReadByte08(buffer, &offset, &type);
+ NetLib::ReadByte08(buffer, &offset, &code);
+ NetLib::ReadUInt16(buffer, &offset, &checksum);
+
+ //Bits 32-63
+ NetLib::ReadByteArray(buffer, &offset, 4, headerData);
+
+ //Bits 64+
+ payload = std::make_unique(&buffer[offset], bufferSize - offset);
+ //AllDone
+ }
+ ICMP_Packet::ICMP_Packet(const ICMP_Packet& original)
+ : type{original.type}
+ , code{original.code}
+ , checksum{original.checksum}
+ , payload{original.payload->Clone()}
+ {
+ memcpy(headerData, original.headerData, 4);
+ }
+
+ Payload* ICMP_Packet::GetPayload()
+ {
+ return payload.get();
+ }
+
+ int ICMP_Packet::GetLength()
+ {
+ return headerLength + payload->GetLength();
+ }
+
+ void ICMP_Packet::WriteBytes(u8* buffer, int* offset)
+ {
+ NetLib::WriteByte08(buffer, offset, type);
+ NetLib::WriteByte08(buffer, offset, code);
+ NetLib::WriteUInt16(buffer, offset, checksum);
+ NetLib::WriteByteArray(buffer, offset, 4, headerData);
+
+ payload->WriteBytes(buffer, offset);
+ }
+
+ ICMP_Packet* ICMP_Packet::Clone() const
+ {
+ return new ICMP_Packet(*this);
+ }
+
+ u8 ICMP_Packet::GetProtocol()
+ {
+ return (u8)protocol;
+ }
+
+ void ICMP_Packet::CalculateChecksum(IP_Address srcIP, IP_Address dstIP)
+ {
+ int pHeaderLen = headerLength + payload->GetLength();
+ if ((pHeaderLen & 1) != 0)
+ {
+ pHeaderLen += 1;
+ }
+
+ u8* segment = new u8[pHeaderLen];
+ int counter = 0;
+
+ checksum = 0;
+ WriteBytes(segment, &counter);
+
+ //Zero alignment byte
+ if (counter != pHeaderLen)
+ NetLib::WriteByte08(segment, &counter, 0);
+
+ checksum = IP_Packet::InternetChecksum(segment, pHeaderLen);
+ delete[] segment;
+ }
+ bool ICMP_Packet::VerifyChecksum(IP_Address srcIP, IP_Address dstIP)
+ {
+ int pHeaderLen = headerLength + payload->GetLength();
+ if ((pHeaderLen & 1) != 0)
+ {
+ pHeaderLen += 1;
+ }
+
+ u8* segment = new u8[pHeaderLen];
+ int counter = 0;
+
+ WriteBytes(segment, &counter);
+
+ //Zero alignment byte
+ if (counter != pHeaderLen)
+ NetLib::WriteByte08(segment, &counter, 0);
+
+ u16 csumCal = IP_Packet::InternetChecksum(segment, pHeaderLen);
+ delete[] segment;
+
+ return (csumCal == 0);
+ }
+} // namespace PacketReader::IP::ICMP
diff --git a/pcsx2/DEV9/PacketReader/IP/ICMP/ICMP_Packet.h b/pcsx2/DEV9/PacketReader/IP/ICMP/ICMP_Packet.h
new file mode 100644
index 0000000000..bb1b0641e3
--- /dev/null
+++ b/pcsx2/DEV9/PacketReader/IP/ICMP/ICMP_Packet.h
@@ -0,0 +1,56 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#pragma once
+#include "DEV9/PacketReader/IP/IP_Packet.h"
+
+namespace PacketReader::IP::ICMP
+{
+ class ICMP_Packet : public IP_Payload
+ {
+ public:
+ u8 type;
+ u8 code;
+
+ private:
+ u16 checksum;
+
+ public:
+ u8 headerData[4];
+
+ private:
+ const static int headerLength = 8;
+ const static IP_Type protocol = IP_Type::ICMP;
+
+ std::unique_ptr payload;
+
+ public:
+ //Takes ownership of payload
+ ICMP_Packet(Payload* data);
+ ICMP_Packet(u8* buffer, int bufferSize);
+ ICMP_Packet(const ICMP_Packet&);
+
+ Payload* GetPayload();
+
+ virtual int GetLength();
+ virtual void WriteBytes(u8* buffer, int* offset);
+ virtual ICMP_Packet* Clone() const;
+
+ virtual u8 GetProtocol();
+
+ virtual bool VerifyChecksum(IP_Address srcIP, IP_Address dstIP);
+ virtual void CalculateChecksum(IP_Address srcIP, IP_Address dstIP);
+ };
+} // namespace PacketReader::IP::ICMP
diff --git a/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Options.cpp b/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Options.cpp
new file mode 100644
index 0000000000..069ab42bd4
--- /dev/null
+++ b/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Options.cpp
@@ -0,0 +1,76 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#include "PrecompiledHeader.h"
+
+#include "TCP_Options.h"
+#include "DEV9/PacketReader/NetLib.h"
+
+namespace PacketReader::IP::TCP
+{
+ TCPopMSS::TCPopMSS(u16 mss)
+ : maxSegmentSize{mss}
+ {
+ }
+ TCPopMSS::TCPopMSS(u8* data, int offset)
+ {
+ offset += 2;
+ NetLib::ReadUInt16(data, &offset, &maxSegmentSize);
+ }
+ void TCPopMSS::WriteBytes(u8* buffer, int* offset)
+ {
+ NetLib::WriteByte08(buffer, offset, GetCode());
+ NetLib::WriteByte08(buffer, offset, GetLength());
+
+ NetLib::WriteUInt16(buffer, offset, maxSegmentSize);
+ }
+
+ TCPopWS::TCPopWS(u8 ws)
+ : windowScale{ws}
+ {
+ }
+ TCPopWS::TCPopWS(u8* data, int offset)
+ {
+ offset += 2;
+ NetLib::ReadByte08(data, &offset, &windowScale);
+ }
+ void TCPopWS::WriteBytes(u8* buffer, int* offset)
+ {
+ NetLib::WriteByte08(buffer, offset, GetCode());
+ NetLib::WriteByte08(buffer, offset, GetLength());
+
+ NetLib::WriteByte08(buffer, offset, windowScale);
+ }
+
+ TCPopTS::TCPopTS(u32 senderTS, u32 echoTS)
+ : senderTimeStamp{senderTS}
+ , echoTimeStamp{echoTS}
+ {
+ }
+ TCPopTS::TCPopTS(u8* data, int offset)
+ {
+ offset += 2;
+ NetLib::ReadUInt32(data, &offset, &senderTimeStamp);
+ NetLib::ReadUInt32(data, &offset, &echoTimeStamp);
+ }
+ void TCPopTS::WriteBytes(u8* buffer, int* offset)
+ {
+ NetLib::WriteByte08(buffer, offset, GetCode());
+ NetLib::WriteByte08(buffer, offset, GetLength());
+
+ NetLib::WriteUInt32(buffer, offset, senderTimeStamp);
+ NetLib::WriteUInt32(buffer, offset, echoTimeStamp);
+ }
+} // namespace PacketReader::IP::TCP
diff --git a/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Options.h b/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Options.h
new file mode 100644
index 0000000000..0b93f02d93
--- /dev/null
+++ b/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Options.h
@@ -0,0 +1,96 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#pragma once
+
+#include "DEV9/PacketReader/IP/IP_Options.h"
+
+namespace PacketReader::IP::TCP
+{
+ class TCPopNOP : public BaseOption
+ {
+ virtual u8 GetLength() { return 1; }
+ virtual u8 GetCode() { return 1; }
+
+ virtual void WriteBytes(u8* buffer, int* offset)
+ {
+ buffer[*offset] = GetCode();
+ (*offset)++;
+ }
+
+ virtual TCPopNOP* Clone() const
+ {
+ return new TCPopNOP(*this);
+ }
+ };
+
+ class TCPopMSS : public BaseOption
+ {
+ public:
+ u16 maxSegmentSize;
+
+ TCPopMSS(u16 mss);
+ TCPopMSS(u8* data, int offset); //Offset will include Kind and Len
+
+ virtual u8 GetLength() { return 4; }
+ virtual u8 GetCode() { return 2; }
+
+ virtual void WriteBytes(u8* buffer, int* offset);
+
+ virtual TCPopMSS* Clone() const
+ {
+ return new TCPopMSS(*this);
+ }
+ };
+
+ class TCPopWS : public BaseOption
+ {
+ public:
+ u8 windowScale;
+
+ TCPopWS(u8 ws);
+ TCPopWS(u8* data, int offset); //Offset will include Kind and Len
+
+ virtual u8 GetLength() { return 3; }
+ virtual u8 GetCode() { return 3; }
+
+ virtual void WriteBytes(u8* buffer, int* offset);
+
+ virtual TCPopWS* Clone() const
+ {
+ return new TCPopWS(*this);
+ }
+ };
+
+ class TCPopTS : public BaseOption
+ {
+ public:
+ u32 senderTimeStamp;
+ u32 echoTimeStamp;
+
+ TCPopTS(u32 senderTS, u32 echoTS);
+ TCPopTS(u8* data, int offset); //Offset will include Kind and Len
+
+ virtual u8 GetLength() { return 10; }
+ virtual u8 GetCode() { return 8; }
+
+ virtual void WriteBytes(u8* buffer, int* offset);
+
+ virtual TCPopTS* Clone() const
+ {
+ return new TCPopTS(*this);
+ }
+ };
+} // namespace PacketReader::IP::TCP
diff --git a/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Packet.cpp b/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Packet.cpp
new file mode 100644
index 0000000000..ba7651b1be
--- /dev/null
+++ b/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Packet.cpp
@@ -0,0 +1,313 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#include "PrecompiledHeader.h"
+
+#include "TCP_Packet.h"
+#include "DEV9/PacketReader/NetLib.h"
+
+namespace PacketReader::IP::TCP
+{
+ //Need flags
+ bool TCP_Packet::GetNS()
+ {
+ return (dataOffsetAndNS_Flag & 1);
+ }
+ void TCP_Packet::SetNS(bool value)
+ {
+ dataOffsetAndNS_Flag = (dataOffsetAndNS_Flag & ~0x1) | (value & 0x1);
+ }
+
+ bool TCP_Packet::GetCWR()
+ {
+ return (flags & (1 << 7));
+ }
+ void TCP_Packet::SetCWR(bool value)
+ {
+ flags = (flags & ~(0x1 << 7)) | ((value & 0x1) << 7);
+ }
+
+ bool TCP_Packet::GetECE()
+ {
+ return (flags & (1 << 6));
+ }
+ void TCP_Packet::SetECE(bool value)
+ {
+ flags = (flags & ~(0x1 << 6)) | ((value & 0x1) << 6);
+ }
+
+ bool TCP_Packet::GetURG()
+ {
+ return (flags & (1 << 5));
+ }
+ void TCP_Packet::SetURG(bool value)
+ {
+ flags = (flags & ~(0x1 << 5)) | ((value & 0x1) << 5);
+ }
+
+ bool TCP_Packet::GetACK()
+ {
+ return (flags & (1 << 4));
+ }
+ void TCP_Packet::SetACK(bool value)
+ {
+ flags = (flags & ~(0x1 << 4)) | ((value & 0x1) << 4);
+ }
+
+ bool TCP_Packet::GetPSH()
+ {
+ return (flags & (1 << 3));
+ }
+ void TCP_Packet::SetPSH(bool value)
+ {
+ flags = (flags & ~(0x1 << 3)) | ((value & 0x1) << 3);
+ }
+
+ bool TCP_Packet::GetRST()
+ {
+ return (flags & (1 << 2));
+ }
+ void TCP_Packet::SetRST(bool value)
+ {
+ flags = (flags & ~(0x1 << 2)) | ((value & 0x1) << 2);
+ }
+
+ bool TCP_Packet::GetSYN()
+ {
+ return (flags & (1 << 1));
+ }
+ void TCP_Packet::SetSYN(bool value)
+ {
+ flags = (flags & ~(0x1 << 1)) | ((value & 0x1) << 1);
+ }
+
+ bool TCP_Packet::GetFIN()
+ {
+ return (flags & 1);
+ }
+ void TCP_Packet::SetFIN(bool value)
+ {
+ flags = (flags & ~0x1) | (value & 0x1);
+ }
+
+ TCP_Packet::TCP_Packet(Payload* data)
+ : headerLength{20}
+ , payload{data}
+ {
+ }
+ TCP_Packet::TCP_Packet(u8* buffer, int bufferSize)
+ {
+ int offset = 0;
+ //Bits 0-31
+ NetLib::ReadUInt16(buffer, &offset, &sourcePort);
+ NetLib::ReadUInt16(buffer, &offset, &destinationPort);
+
+ //Bits 32-63
+ NetLib::ReadUInt32(buffer, &offset, &sequenceNumber);
+
+ //Bits 64-95
+ NetLib::ReadUInt32(buffer, &offset, &acknowledgementNumber);
+
+ //Bits 96-127
+ NetLib::ReadByte08(buffer, &offset, &dataOffsetAndNS_Flag);
+ headerLength = (dataOffsetAndNS_Flag >> 4) << 2;
+ NetLib::ReadByte08(buffer, &offset, &flags);
+ NetLib::ReadUInt16(buffer, &offset, &windowSize);
+
+ //Bits 127-159
+ NetLib::ReadUInt16(buffer, &offset, &checksum);
+ NetLib::ReadUInt16(buffer, &offset, &urgentPointer);
+
+ //Bits 160+
+ if (headerLength > 20) //TCP options
+ {
+ bool opReadFin = false;
+ do
+ {
+ u8 opKind = buffer[offset];
+ u8 opLen = buffer[offset + 1];
+ switch (opKind)
+ {
+ case 0:
+ opReadFin = true;
+ break;
+ case 1:
+ options.push_back(new TCPopNOP());
+ offset += 1;
+ continue;
+ case 2:
+ options.push_back(new TCPopMSS(buffer, offset));
+ break;
+ case 3:
+ options.push_back(new TCPopWS(buffer, offset));
+ break;
+ case 8:
+ options.push_back(new TCPopTS(buffer, offset));
+ break;
+ default:
+ Console.Error("Got Unknown TCP Option %d with len %d", opKind, opLen);
+ options.push_back(new IPopUnk(buffer, offset));
+ break;
+ }
+ offset += opLen;
+ if (offset == headerLength)
+ opReadFin = true;
+ } while (opReadFin == false);
+ }
+ offset = headerLength;
+
+ payload = std::make_unique(&buffer[offset], bufferSize - offset);
+ //AllDone
+ }
+
+ TCP_Packet::TCP_Packet(const TCP_Packet& original)
+ : sourcePort{original.sourcePort}
+ , destinationPort{original.destinationPort}
+ , sequenceNumber{original.sequenceNumber}
+ , acknowledgementNumber{original.acknowledgementNumber}
+ , dataOffsetAndNS_Flag{original.dataOffsetAndNS_Flag}
+ , headerLength{original.headerLength}
+ , flags{original.flags}
+ , windowSize{original.windowSize}
+ , checksum{original.checksum}
+ , urgentPointer{original.urgentPointer}
+ , payload{original.payload->Clone()}
+ {
+ //Clone options
+ options.reserve(original.options.size());
+ for (size_t i = 0; i < options.size(); i++)
+ options.push_back(original.options[i]->Clone());
+ }
+
+ Payload* TCP_Packet::GetPayload()
+ {
+ return payload.get();
+ }
+
+ int TCP_Packet::GetLength()
+ {
+ ReComputeHeaderLen();
+ return headerLength + payload->GetLength();
+ }
+
+ void TCP_Packet::WriteBytes(u8* buffer, int* offset)
+ {
+ int startOff = *offset;
+ NetLib::WriteUInt16(buffer, offset, sourcePort);
+ NetLib::WriteUInt16(buffer, offset, destinationPort);
+ NetLib::WriteUInt32(buffer, offset, sequenceNumber);
+ NetLib::WriteUInt32(buffer, offset, acknowledgementNumber);
+ NetLib::WriteByte08(buffer, offset, dataOffsetAndNS_Flag);
+ NetLib::WriteByte08(buffer, offset, flags);
+ NetLib::WriteUInt16(buffer, offset, windowSize);
+ NetLib::WriteUInt16(buffer, offset, checksum);
+ NetLib::WriteUInt16(buffer, offset, urgentPointer);
+
+ //options
+ for (size_t i = 0; i < options.size(); i++)
+ options[i]->WriteBytes(buffer, offset);
+
+ //Zero alignment bytes
+ if (*offset != startOff + headerLength)
+ memset(&buffer[*offset], 0, startOff + headerLength - *offset);
+
+ *offset = startOff + headerLength;
+
+ payload->WriteBytes(buffer, offset);
+ }
+
+ TCP_Packet* TCP_Packet::Clone() const
+ {
+ return new TCP_Packet(*this);
+ }
+
+ u8 TCP_Packet::GetProtocol()
+ {
+ return (u8)protocol;
+ }
+
+ void TCP_Packet::ReComputeHeaderLen()
+ {
+ int opOffset = 20;
+ for (size_t i = 0; i < options.size(); i++)
+ opOffset += options[i]->GetLength();
+
+ opOffset += opOffset % 4; //needs to be a whole number of 32bits
+ headerLength = opOffset;
+
+ //Also write into dataOffsetAndNS_Flag
+ u8 ns = dataOffsetAndNS_Flag & 1;
+ dataOffsetAndNS_Flag = (headerLength >> 2) << 4;
+ dataOffsetAndNS_Flag |= ns;
+ }
+
+ void TCP_Packet::CalculateChecksum(IP_Address srcIP, IP_Address dstIP)
+ {
+ ReComputeHeaderLen();
+ int pHeaderLen = (12) + headerLength + payload->GetLength();
+ if ((pHeaderLen & 1) != 0)
+ pHeaderLen += 1;
+
+ u8* headerSegment = new u8[pHeaderLen];
+ int counter = 0;
+
+ NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
+ NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
+ NetLib::WriteByte08(headerSegment, &counter, 0);
+ NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
+ NetLib::WriteUInt16(headerSegment, &counter, GetLength());
+
+ //Pseudo Header added
+ //Rest of data is normal Header+data (with zerored checksum feild)
+ checksum = 0;
+ WriteBytes(headerSegment, &counter);
+
+ //Zero alignment byte
+ if (counter != pHeaderLen)
+ NetLib::WriteByte08(headerSegment, &counter, 0);
+
+ checksum = IP_Packet::InternetChecksum(headerSegment, pHeaderLen);
+ delete[] headerSegment;
+ }
+ bool TCP_Packet::VerifyChecksum(IP_Address srcIP, IP_Address dstIP)
+ {
+ ReComputeHeaderLen();
+ int pHeaderLen = (12) + headerLength + payload->GetLength();
+ if ((pHeaderLen & 1) != 0)
+ pHeaderLen += 1;
+
+ u8* headerSegment = new u8[pHeaderLen];
+ int counter = 0;
+
+ NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
+ NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
+ NetLib::WriteByte08(headerSegment, &counter, 0);
+ NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
+ NetLib::WriteUInt16(headerSegment, &counter, GetLength());
+
+ //Pseudo Header added
+ //Rest of data is normal Header+data
+ WriteBytes(headerSegment, &counter);
+
+ //Zero alignment byte
+ if (counter != pHeaderLen)
+ NetLib::WriteByte08(headerSegment, &counter, 0);
+
+ u16 csumCal = IP_Packet::InternetChecksum(headerSegment, pHeaderLen);
+ delete[] headerSegment;
+
+ return (csumCal == 0);
+ }
+} // namespace PacketReader::IP::TCP
diff --git a/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Packet.h b/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Packet.h
new file mode 100644
index 0000000000..ebc82470e1
--- /dev/null
+++ b/pcsx2/DEV9/PacketReader/IP/TCP/TCP_Packet.h
@@ -0,0 +1,99 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2021 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+#pragma once
+
+#include "TCP_Options.h"
+#include "DEV9/PacketReader/IP/IP_Packet.h"
+
+namespace PacketReader::IP::TCP
+{
+ class TCP_Packet : public IP_Payload
+ {
+ public:
+ u16 sourcePort;
+ u16 destinationPort;
+ u32 sequenceNumber;
+ u32 acknowledgementNumber;
+
+ private:
+ u8 dataOffsetAndNS_Flag = 0;
+ int headerLength; //Can have varying Header Len
+ u8 flags = 0;
+
+ public:
+ u16 windowSize;
+
+ private:
+ u16 checksum;
+ u16 urgentPointer = 0;
+
+ public:
+ std::vector options;
+
+ private:
+ const static IP_Type protocol = IP_Type::TCP;
+
+ std::unique_ptr payload;
+
+ public:
+ //Flags
+ bool GetNS();
+ void SetNS(bool value);
+
+ bool GetCWR();
+ void SetCWR(bool value);
+
+ bool GetECE();
+ void SetECE(bool value);
+
+ bool GetURG();
+ void SetURG(bool value);
+
+ bool GetACK();
+ void SetACK(bool value);
+
+ bool GetPSH();
+ void SetPSH(bool value);
+
+ bool GetRST();
+ void SetRST(bool value);
+
+ bool GetSYN();
+ void SetSYN(bool value);
+
+ bool GetFIN();
+ void SetFIN(bool value);
+
+ //Takes ownership of payload
+ TCP_Packet(Payload* data);
+ TCP_Packet(u8* buffer, int bufferSize);
+ TCP_Packet(const TCP_Packet&);
+
+ Payload* GetPayload();
+
+ virtual int GetLength();
+ virtual void WriteBytes(u8* buffer, int* offset);
+ virtual TCP_Packet* Clone() const;
+
+ virtual u8 GetProtocol();
+
+ virtual bool VerifyChecksum(IP_Address srcIP, IP_Address dstIP);
+ virtual void CalculateChecksum(IP_Address srcIP, IP_Address dstIP);
+
+ private:
+ void ReComputeHeaderLen();
+ };
+} // namespace PacketReader::IP::TCP
diff --git a/pcsx2/pcsx2.vcxproj b/pcsx2/pcsx2.vcxproj
index de8dbb9398..7abaeac36b 100644
--- a/pcsx2/pcsx2.vcxproj
+++ b/pcsx2/pcsx2.vcxproj
@@ -293,7 +293,11 @@
+
+
+
+
@@ -739,7 +743,11 @@
+
+
+
+
diff --git a/pcsx2/pcsx2.vcxproj.filters b/pcsx2/pcsx2.vcxproj.filters
index d39f65ef8b..32e968e1c1 100644
--- a/pcsx2/pcsx2.vcxproj.filters
+++ b/pcsx2/pcsx2.vcxproj.filters
@@ -184,9 +184,18 @@
{57c4be94-9a2c-469b-9b02-b3b324857fc5}
+
+ {12c15e0b-4647-4ce2-9bc4-89e6e9e8f531}
+
{a0723e13-c839-464d-8cfa-6c440ae03537}
+
+ {928400ad-4db4-44ca-9a6d-c65e489c8ea0}
+
+
+ {7c01f24d-2141-4054-b3f9-1d9c67ae7ad6}
+
{db2fc75d-6552-4991-9155-885abd8796e4}
@@ -1223,6 +1232,18 @@
System\Ps2\DEV9\InternalServers
+
+ System\Ps2\DEV9\PacketReader\ARP
+
+
+ System\Ps2\DEV9\PacketReader\IP\ICMP
+
+
+ System\Ps2\DEV9\PacketReader\IP\TCP
+
+
+ System\Ps2\DEV9\PacketReader\IP\TCP
+
System\Ps2\DEV9\PacketReader\IP\UDP\DHCP
@@ -2290,6 +2311,18 @@
System\Ps2\DEV9
+
+ System\Ps2\DEV9\PacketReader\ARP
+
+
+ System\Ps2\DEV9\PacketReader\IP\ICMP
+
+
+ System\Ps2\DEV9\PacketReader\IP\TCP
+
+
+ System\Ps2\DEV9\PacketReader\IP\TCP
+
System\Ps2\DEV9\PacketReader\IP\UDP\DHCP
diff --git a/pcsx2/pcsx2core.vcxproj b/pcsx2/pcsx2core.vcxproj
index 7c2b6736fa..67c683a82b 100644
--- a/pcsx2/pcsx2core.vcxproj
+++ b/pcsx2/pcsx2core.vcxproj
@@ -156,7 +156,11 @@
+
+
+
+
@@ -456,7 +460,11 @@
+
+
+
+
diff --git a/pcsx2/pcsx2core.vcxproj.filters b/pcsx2/pcsx2core.vcxproj.filters
index 4b946e09dc..eb7167f705 100644
--- a/pcsx2/pcsx2core.vcxproj.filters
+++ b/pcsx2/pcsx2core.vcxproj.filters
@@ -142,9 +142,18 @@
{57c4be94-9a2c-469b-9b02-b3b324857fc5}
+
+ {12c15e0b-4647-4ce2-9bc4-89e6e9e8f531}
+
{a0723e13-c839-464d-8cfa-6c440ae03537}
+
+ {928400ad-4db4-44ca-9a6d-c65e489c8ea0}
+
+
+ {7c01f24d-2141-4054-b3f9-1d9c67ae7ad6}
+
{db2fc75d-6552-4991-9155-885abd8796e4}
@@ -878,6 +887,18 @@
System\Ps2\DEV9\InternalServers
+
+ System\Ps2\DEV9\PacketReader\ARP
+
+
+ System\Ps2\DEV9\PacketReader\IP\ICMP
+
+
+ System\Ps2\DEV9\PacketReader\IP\TCP
+
+
+ System\Ps2\DEV9\PacketReader\IP\TCP
+
System\Ps2\DEV9\PacketReader\IP\UDP\DHCP
@@ -1619,6 +1640,18 @@
System\Ps2\DEV9
+
+ System\Ps2\DEV9\PacketReader\ARP
+
+
+ System\Ps2\DEV9\PacketReader\IP\ICMP
+
+
+ System\Ps2\DEV9\PacketReader\IP\TCP
+
+
+ System\Ps2\DEV9\PacketReader\IP\TCP
+
System\Ps2\DEV9\PacketReader\IP\UDP\DHCP