mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
633 lines
18 KiB
C++
633 lines
18 KiB
C++
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#include "common/RedtapeWindows.h"
|
|
#include "common/RedtapeWilCom.h"
|
|
#include "common/StringUtil.h"
|
|
|
|
#include "fmt/format.h"
|
|
|
|
#include <stdio.h>
|
|
#include <WinSock2.h>
|
|
#include <WS2tcpip.h>
|
|
#include <iphlpapi.h>
|
|
|
|
#include <Netcfgx.h>
|
|
#include <devguid.h>
|
|
|
|
#include <tchar.h>
|
|
#include "tap.h"
|
|
#include "DEV9/DEV9.h"
|
|
#include <string>
|
|
|
|
#include <wil/com.h>
|
|
#include <wil/resource.h>
|
|
|
|
#include "DEV9/PacketReader/MAC_Address.h"
|
|
#include "DEV9/AdapterUtils.h"
|
|
|
|
//=============
|
|
// TAP IOCTLs
|
|
//=============
|
|
|
|
#define TAP_CONTROL_CODE(request, method) \
|
|
CTL_CODE(FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
|
|
|
|
// clang-format off
|
|
#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED)
|
|
#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE(2, METHOD_BUFFERED)
|
|
#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE(3, METHOD_BUFFERED)
|
|
#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE(4, METHOD_BUFFERED)
|
|
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE(5, METHOD_BUFFERED)
|
|
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, METHOD_BUFFERED)
|
|
#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE(7, METHOD_BUFFERED)
|
|
#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE(8, METHOD_BUFFERED)
|
|
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE(9, METHOD_BUFFERED)
|
|
// clang-format on
|
|
|
|
//=================
|
|
// Registry keys
|
|
//=================
|
|
|
|
#define ADAPTER_KEY L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
|
|
|
#define NETWORK_CONNECTIONS_KEY L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
|
|
|
|
//======================
|
|
// Filesystem prefixes
|
|
//======================
|
|
|
|
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
|
|
#define TAPSUFFIX ".tap"
|
|
|
|
#define TAP_COMPONENT_ID "tap0901"
|
|
|
|
bool IsTAPDevice(const TCHAR* guid)
|
|
{
|
|
wil::unique_hkey netcard_key;
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ, netcard_key.put()) != ERROR_SUCCESS)
|
|
return false;
|
|
|
|
int i = 0;
|
|
for (;;)
|
|
{
|
|
TCHAR enum_name[256];
|
|
TCHAR unit_string[256];
|
|
TCHAR component_id_string[] = _T("ComponentId");
|
|
TCHAR component_id[256];
|
|
TCHAR net_cfg_instance_id_string[] = _T("NetCfgInstanceId");
|
|
TCHAR net_cfg_instance_id[256];
|
|
DWORD data_type;
|
|
|
|
DWORD len = std::size(enum_name);
|
|
LSTATUS status = RegEnumKeyEx(netcard_key.get(), i, enum_name, &len, nullptr, nullptr, nullptr, nullptr);
|
|
|
|
if (status == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
else if (status != ERROR_SUCCESS)
|
|
return false;
|
|
|
|
_stprintf_s(unit_string, _T("%s\\%s"), ADAPTER_KEY, enum_name);
|
|
|
|
wil::unique_hkey unit_key;
|
|
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit_string, 0, KEY_READ, unit_key.put());
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
len = sizeof(component_id);
|
|
status = RegQueryValueEx(unit_key.get(), component_id_string, nullptr, &data_type,
|
|
(LPBYTE)component_id, &len);
|
|
|
|
if (!(status != ERROR_SUCCESS || data_type != REG_SZ))
|
|
{
|
|
len = sizeof(net_cfg_instance_id);
|
|
status = RegQueryValueEx(unit_key.get(), net_cfg_instance_id_string, nullptr, &data_type,
|
|
(LPBYTE)net_cfg_instance_id, &len);
|
|
|
|
if (status == ERROR_SUCCESS && data_type == REG_SZ)
|
|
{
|
|
// tap_ovpnconnect, tap0901 or root\tap, no clue why
|
|
if ((!wcsncmp(component_id, L"tap", 3) || !wcsncmp(component_id, L"root\\tap", 8)) && !_tcscmp(net_cfg_instance_id, guid))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
++i;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
std::vector<AdapterEntry> TAPAdapter::GetAdapters()
|
|
{
|
|
std::vector<AdapterEntry> tap_nic;
|
|
DWORD len;
|
|
DWORD cSubKeys = 0;
|
|
|
|
wil::unique_hkey control_net_key;
|
|
LSTATUS status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ | KEY_QUERY_VALUE,
|
|
control_net_key.put());
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
return tap_nic;
|
|
|
|
status = RegQueryInfoKey(control_net_key.get(), nullptr, nullptr, nullptr, &cSubKeys, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr);
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
return tap_nic;
|
|
|
|
for (DWORD i = 0; i < cSubKeys; i++)
|
|
{
|
|
TCHAR enum_name[256];
|
|
TCHAR connection_string[256];
|
|
TCHAR name_data[256];
|
|
DWORD name_type;
|
|
const TCHAR name_string[] = _T("Name");
|
|
|
|
len = std::size(enum_name);
|
|
status = RegEnumKeyEx(control_net_key.get(), i, enum_name, &len, nullptr, nullptr, nullptr, nullptr);
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
continue;
|
|
|
|
_stprintf_s(connection_string, _T("%s\\%s\\Connection"),
|
|
NETWORK_CONNECTIONS_KEY, enum_name);
|
|
|
|
wil::unique_hkey connection_key;
|
|
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ, connection_key.put());
|
|
|
|
if (status == ERROR_SUCCESS)
|
|
{
|
|
len = sizeof(name_data);
|
|
status = RegQueryValueEx(connection_key.get(), name_string, nullptr, &name_type, (LPBYTE)name_data,
|
|
&len);
|
|
|
|
if (status != ERROR_SUCCESS || name_type != REG_SZ)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (IsTAPDevice(enum_name))
|
|
{
|
|
AdapterEntry t;
|
|
t.type = Pcsx2Config::DEV9Options::NetApi::TAP;
|
|
t.name = StringUtil::WideStringToUTF8String(std::wstring(name_data));
|
|
t.guid = StringUtil::WideStringToUTF8String(std::wstring(enum_name));
|
|
tap_nic.push_back(t);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return tap_nic;
|
|
}
|
|
|
|
AdapterOptions TAPAdapter::GetAdapterOptions()
|
|
{
|
|
return AdapterOptions::None;
|
|
}
|
|
|
|
static int TAPGetMACAddress(HANDLE handle, PacketReader::MAC_Address* addr)
|
|
{
|
|
DWORD len = 0;
|
|
|
|
return DeviceIoControl(handle, TAP_IOCTL_GET_MAC,
|
|
addr, 6,
|
|
addr, 6, &len, NULL);
|
|
}
|
|
|
|
//Set the connection status
|
|
static int TAPSetStatus(HANDLE handle, int status)
|
|
{
|
|
DWORD len = 0;
|
|
|
|
return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
|
|
&status, sizeof(status),
|
|
&status, sizeof(status), &len, NULL);
|
|
}
|
|
//Open the TAP adapter and set the connection to enabled :)
|
|
HANDLE TAPOpen(const std::string& device_guid)
|
|
{
|
|
struct
|
|
{
|
|
unsigned long major;
|
|
unsigned long minor;
|
|
unsigned long debug;
|
|
} version;
|
|
LONG version_len;
|
|
|
|
std::string device_path = USERMODEDEVICEDIR + device_guid + TAPSUFFIX;
|
|
|
|
wil::unique_hfile handle(CreateFileA(
|
|
device_path.c_str(),
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
0,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
|
|
0));
|
|
|
|
if (!handle)
|
|
{
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
const BOOL bret = DeviceIoControl(handle.get(), TAP_IOCTL_GET_VERSION,
|
|
&version, sizeof(version),
|
|
&version, sizeof(version), (LPDWORD)&version_len, NULL);
|
|
|
|
if (bret == FALSE)
|
|
{
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (!TAPSetStatus(handle.get(), TRUE))
|
|
{
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return handle.release();
|
|
}
|
|
|
|
PIP_ADAPTER_ADDRESSES FindAdapterViaIndex(PIP_ADAPTER_ADDRESSES adapterList, int ifIndex)
|
|
{
|
|
PIP_ADAPTER_ADDRESSES currentAdapter = adapterList;
|
|
do
|
|
{
|
|
if (currentAdapter->IfIndex == ifIndex)
|
|
break;
|
|
|
|
currentAdapter = currentAdapter->Next;
|
|
} while (currentAdapter);
|
|
return currentAdapter;
|
|
}
|
|
|
|
//IP_ADAPTER_ADDRESSES is a structure that contains ptrs to data in other regions
|
|
//of the buffer, se we need to return both so the caller can free the buffer
|
|
//after it's finished reading the needed data from IP_ADAPTER_ADDRESSES
|
|
bool TAPGetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, AdapterUtils::AdapterBuffer* buffer)
|
|
{
|
|
//GAA_FLAG_INCLUDE_ALL_INTERFACES needed to get Tap when bridged
|
|
AdapterUtils::AdapterBuffer adapterInfo;
|
|
PIP_ADAPTER_ADDRESSES pAdapterFirst = AdapterUtils::GetAllAdapters(&adapterInfo, true);
|
|
if (pAdapterFirst == nullptr)
|
|
return false;
|
|
|
|
PIP_ADAPTER_ADDRESSES pAdapter = pAdapterFirst;
|
|
do
|
|
{
|
|
if (0 == strcmp(pAdapter->AdapterName, name.c_str()))
|
|
break;
|
|
|
|
pAdapter = pAdapter->Next;
|
|
} while (pAdapter);
|
|
|
|
if (pAdapter == nullptr)
|
|
return false;
|
|
|
|
//If we are bridged, then we won't show up without GAA_FLAG_INCLUDE_ALL_INTERFACES
|
|
AdapterUtils::AdapterBuffer adapterInfoReduced;
|
|
PIP_ADAPTER_ADDRESSES pAdapterReducedFirst = AdapterUtils::GetAllAdapters(&adapterInfoReduced, false);
|
|
|
|
//If we find our adapter in the reduced list, we are not bridged
|
|
if (FindAdapterViaIndex(pAdapterReducedFirst, pAdapter->IfIndex) != nullptr)
|
|
{
|
|
*adapter = *pAdapter;
|
|
buffer->swap(adapterInfo);
|
|
return true;
|
|
}
|
|
|
|
//We must be bridged
|
|
Console.WriteLn("DEV9: Current adapter is probably bridged");
|
|
Console.WriteLn(fmt::format("DEV9: Adapter Display name: {}", StringUtil::WideStringToUTF8String(pAdapter->FriendlyName)));
|
|
|
|
//We will need to find the bridge adapter that out adapter is
|
|
//as the IP information of the tap adapter is null
|
|
//connected to, the method used to do this is undocumented and windows 8+
|
|
|
|
//Only solution found is detailed in this MSDN fourm post by Jeffrey Tippet[MSFT], with a sectin copyied below
|
|
//Some adjustments to the method where required before this would work on my system.
|
|
//https://social.msdn.microsoft.com/Forums/vstudio/en-US/6dc9097e-0c33-427c-8e1b-9e2c81fad367/how-to-detect-if-network-interface-is-part-of-ethernet-bridge-?forum=wdk
|
|
/* To detect the newer LWF driver, it's trickier, since the binding over the NIC would be to the generic IM platform.
|
|
* Knowing that a NIC is bound to the generic IM platform tells you that it's being used for some fancy thing,
|
|
* but it doesn't tell you whether it's a bridge or an LBFO team or something more exotic.
|
|
* The way to distinguish exactly which flavor of ms_implat you have is to look at which LWF driver is bound to the *virtual miniport* above the IM driver.
|
|
* This is two steps then.
|
|
*
|
|
* 1. Given a physical NIC, you first want to determine which virtual NIC is layered over it.
|
|
* 2. Given a virtual NIC, you want to determine whether ms_bridge is bound to it.
|
|
*
|
|
* To get the first part, look through the interface stack table (GetIfStackTable). Search the stack table for any entry where the lower is the IfIndex of the physical NIC.
|
|
* For any such entry (there will probably be a few), check if that entry's upper IfIndex is the IfIndex for a virtual miniport with component ID "COMPOSITEBUS\MS_IMPLAT_MP".
|
|
* If you find such a thing, that means the physical NIC is a member of a bridge/LBFO/something-else-fancy.
|
|
* If you don't find it, then you know the NIC isn't part of the bridge that comes with Windows 8 / Windows 10.
|
|
*
|
|
* To get the second part, just use the same INetCfg code above on the *virtual* NIC's component. If the ms_bridge component is bound to the virtual NIC,
|
|
* then that virtual NIC is doing bridging. Otherwise, it's doing something else (like LBFO).
|
|
*/
|
|
|
|
//Step 1
|
|
//Find any rows that how our adapter as the lower index
|
|
//check if the upper adapter has a non-null address
|
|
//If not, we repeat the search with the upper adapter
|
|
//If multiple rows have our adapter, we check all of them
|
|
std::vector<NET_IFINDEX> potentialBridges;
|
|
std::vector<NET_IFINDEX> searchList;
|
|
searchList.push_back(pAdapter->IfIndex);
|
|
|
|
PMIB_IFSTACK_TABLE table;
|
|
GetIfStackTable(&table);
|
|
//Note that we append to the collection during iteration
|
|
for (size_t vi = 0; vi < searchList.size(); vi++)
|
|
{
|
|
for (ULONG i = 0; i < table->NumEntries; i++)
|
|
{
|
|
int targetIndex = searchList[vi];
|
|
MIB_IFSTACK_ROW row = table->Table[i];
|
|
if (row.LowerLayerInterfaceIndex == targetIndex)
|
|
{
|
|
const PIP_ADAPTER_ADDRESSES potentialAdapter = FindAdapterViaIndex(pAdapterReducedFirst, row.HigherLayerInterfaceIndex);
|
|
if (potentialAdapter != nullptr)
|
|
{
|
|
Console.WriteLn(fmt::format("DEV9: {} is possible bridge (Check 1 passed)", StringUtil::WideStringToUTF8String(potentialAdapter->Description)));
|
|
potentialBridges.push_back(row.HigherLayerInterfaceIndex);
|
|
}
|
|
else
|
|
searchList.push_back(row.HigherLayerInterfaceIndex);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//Cleanup
|
|
FreeMibTable(table);
|
|
pAdapterReducedFirst = nullptr;
|
|
adapterInfoReduced.reset();
|
|
|
|
//Step 2
|
|
//Init COM
|
|
HRESULT cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
|
if (cohr == RPC_E_CHANGED_MODE)
|
|
cohr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
|
if (!SUCCEEDED(cohr))
|
|
return false;
|
|
|
|
PIP_ADAPTER_ADDRESSES bridgeAdapter = nullptr;
|
|
|
|
//Create Instance of INetCfg
|
|
if (auto netcfg = wil::CoCreateInstanceNoThrow<INetCfg>(CLSID_CNetCfg))
|
|
{
|
|
HRESULT hr = netcfg->Initialize(nullptr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//Get the bridge component
|
|
//The bridged adapter should have this bound
|
|
wil::com_ptr_nothrow<INetCfgComponent> bridge;
|
|
hr = netcfg->FindComponent(L"ms_bridge", bridge.put());
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//Get a List of network adapters via INetCfg
|
|
wil::com_ptr_nothrow<IEnumNetCfgComponent> components;
|
|
hr = netcfg->EnumComponents(&GUID_DEVCLASS_NET, components.put());
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//Search possible bridge adapters
|
|
for (const auto& index : potentialBridges)
|
|
{
|
|
//We need to match the adapter index to an INetCfgComponent
|
|
//We do this by matching IP_ADAPTER_ADDRESSES.AdapterName
|
|
//with the INetCfgComponent Instance GUID
|
|
PIP_ADAPTER_ADDRESSES cAdapterInfo = FindAdapterViaIndex(pAdapterFirst, index);
|
|
|
|
if (cAdapterInfo == nullptr || cAdapterInfo->AdapterName == nullptr)
|
|
continue;
|
|
|
|
//Convert Name to GUID
|
|
wchar_t wName[40] = {0};
|
|
mbstowcs(wName, cAdapterInfo->AdapterName, 39);
|
|
GUID nameGuid;
|
|
hr = IIDFromString(wName, &nameGuid);
|
|
if (!SUCCEEDED(hr))
|
|
continue;
|
|
|
|
//Loop through components
|
|
wil::com_ptr_nothrow<INetCfgComponent> component;
|
|
while (true)
|
|
{
|
|
if (components->Next(1, component.put(), nullptr) != S_OK)
|
|
break;
|
|
|
|
GUID comInstGuid;
|
|
hr = component->GetInstanceGuid(&comInstGuid);
|
|
|
|
if (SUCCEEDED(hr) && IsEqualGUID(nameGuid, comInstGuid))
|
|
{
|
|
wil::unique_cotaskmem_string comId;
|
|
hr = component->GetId(comId.put());
|
|
if (!SUCCEEDED(hr))
|
|
continue;
|
|
|
|
//The bridge adapter for Win8+ has this ComponentID
|
|
//However not every adapter with this componentID is a bridge
|
|
if (wcscmp(L"compositebus\\ms_implat_mp", comId.get()) == 0)
|
|
{
|
|
wil::unique_cotaskmem_string dispName;
|
|
hr = component->GetDisplayName(dispName.put());
|
|
if (SUCCEEDED(hr))
|
|
Console.WriteLn(fmt::format("DEV9: {} is possible bridge (Check 2 passed)", StringUtil::WideStringToUTF8String(dispName.get())));
|
|
|
|
//Check if adapter has the ms_bridge component bound to it.
|
|
auto bindings = bridge.try_query<INetCfgComponentBindings>();
|
|
if (!bindings)
|
|
continue;
|
|
|
|
hr = bindings->IsBoundTo(component.get());
|
|
if (hr != S_OK)
|
|
continue;
|
|
|
|
hr = component->GetDisplayName(dispName.put());
|
|
if (SUCCEEDED(hr))
|
|
Console.WriteLn(fmt::format("DEV9: {} is bridge (Check 3 passed)", StringUtil::WideStringToUTF8String(dispName.get())));
|
|
|
|
bridgeAdapter = cAdapterInfo;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
components->Reset();
|
|
if (bridgeAdapter != nullptr)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
netcfg->Uninitialize();
|
|
}
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
if (bridgeAdapter != nullptr)
|
|
{
|
|
*adapter = *bridgeAdapter;
|
|
buffer->swap(adapterInfo);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
TAPAdapter::TAPAdapter()
|
|
: NetAdapter()
|
|
{
|
|
if (!EmuConfig.DEV9.EthEnable)
|
|
return;
|
|
htap = TAPOpen(EmuConfig.DEV9.EthDevice);
|
|
|
|
read.Offset = 0;
|
|
read.OffsetHigh = 0;
|
|
read.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
write.Offset = 0;
|
|
write.OffsetHigh = 0;
|
|
write.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
cancel = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
PacketReader::MAC_Address hostMAC;
|
|
PacketReader::MAC_Address newMAC;
|
|
|
|
TAPGetMACAddress(htap, &hostMAC);
|
|
newMAC = ps2MAC;
|
|
|
|
//Lets take the hosts last 2 bytes to make it unique on Xlink
|
|
newMAC.bytes[5] = hostMAC.bytes[4];
|
|
newMAC.bytes[4] = hostMAC.bytes[5];
|
|
|
|
SetMACAddress(&newMAC);
|
|
|
|
IP_ADAPTER_ADDRESSES adapter;
|
|
AdapterUtils::AdapterBuffer buffer;
|
|
if (TAPGetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
|
InitInternalServer(&adapter);
|
|
else
|
|
{
|
|
Console.Error("DEV9: Failed to get adapter information");
|
|
InitInternalServer(nullptr);
|
|
}
|
|
|
|
isActive = true;
|
|
}
|
|
|
|
bool TAPAdapter::blocks()
|
|
{
|
|
return true; //we use blocking io
|
|
}
|
|
bool TAPAdapter::isInitialised()
|
|
{
|
|
return (htap != NULL);
|
|
}
|
|
//gets a packet.rv :true success
|
|
bool TAPAdapter::recv(NetPacket* pkt)
|
|
{
|
|
DWORD read_size;
|
|
BOOL result = ReadFile(htap,
|
|
pkt->buffer,
|
|
sizeof(pkt->buffer),
|
|
&read_size,
|
|
&read);
|
|
|
|
if (!result)
|
|
{
|
|
const DWORD dwError = GetLastError();
|
|
if (dwError == ERROR_IO_PENDING)
|
|
{
|
|
HANDLE readHandles[]{read.hEvent, cancel};
|
|
const DWORD waitResult = WaitForMultipleObjects(2, readHandles, FALSE, INFINITE);
|
|
|
|
if (waitResult == WAIT_OBJECT_0 + 1)
|
|
{
|
|
CancelIo(htap);
|
|
//Wait for the I/O subsystem to acknowledge our cancellation
|
|
result = GetOverlappedResult(htap, &read, &read_size, TRUE);
|
|
}
|
|
else
|
|
result = GetOverlappedResult(htap, &read, &read_size, FALSE);
|
|
}
|
|
}
|
|
|
|
if (result && VerifyPkt(pkt, read_size))
|
|
{
|
|
InspectRecv(pkt);
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
//sends the packet .rv :true success
|
|
bool TAPAdapter::send(NetPacket* pkt)
|
|
{
|
|
InspectSend(pkt);
|
|
if (NetAdapter::send(pkt))
|
|
return true;
|
|
|
|
DWORD writen;
|
|
BOOL result = WriteFile(htap,
|
|
pkt->buffer,
|
|
pkt->size,
|
|
&writen,
|
|
&write);
|
|
|
|
if (!result)
|
|
{
|
|
const DWORD dwError = GetLastError();
|
|
if (dwError == ERROR_IO_PENDING)
|
|
{
|
|
WaitForSingleObject(write.hEvent, INFINITE);
|
|
result = GetOverlappedResult(htap, &write, &writen, FALSE);
|
|
}
|
|
}
|
|
|
|
if (result)
|
|
{
|
|
if (writen != pkt->size)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void TAPAdapter::reloadSettings()
|
|
{
|
|
IP_ADAPTER_ADDRESSES adapter;
|
|
AdapterUtils::AdapterBuffer buffer;
|
|
if (TAPGetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
|
ReloadInternalServer(&adapter);
|
|
else
|
|
ReloadInternalServer(nullptr);
|
|
}
|
|
|
|
void TAPAdapter::close()
|
|
{
|
|
SetEvent(cancel);
|
|
}
|
|
TAPAdapter::~TAPAdapter()
|
|
{
|
|
if (!isActive)
|
|
return;
|
|
CloseHandle(read.hEvent);
|
|
CloseHandle(write.hEvent);
|
|
CloseHandle(cancel);
|
|
TAPSetStatus(htap, FALSE);
|
|
CloseHandle(htap);
|
|
isActive = false;
|
|
} |