ethernet_pcap: Move NE2000 pcap code to PcapEthernetConnection

This change separates the pcap code out of the NE2000 code to its own
EthernetConnection backend, and modifies the NE2000 to use the
EthernetConnection abstraction.
This commit is contained in:
Jookia
2021-03-04 10:12:13 +11:00
parent ca9111abc2
commit 9a2af73a2a
7 changed files with 340 additions and 229 deletions

View File

@@ -1,9 +1,5 @@
#include "config.h"
#if defined(WIN32)
#define HAVE_REMOTE
#endif
#include "dosbox.h"
#include <string.h>
#include <stdio.h>
@@ -51,34 +47,11 @@
#include "ne2000.h"
#include "ethernet.h"
EthernetConnection* ethernet = nullptr;
static void NE2000_TX_Event(Bitu val);
#ifdef C_PCAP
#include "pcap.h"
// Handle to WinPCap device
pcap_t *adhandle = 0;
#ifdef WIN32
// DLL loading
#define pcap_sendpacket(A,B,C) PacketSendPacket(A,B,C)
#define pcap_close(A) PacketClose(A)
#define pcap_freealldevs(A) PacketFreealldevs(A)
#define pcap_open(A,B,C,D,E,F) PacketOpen(A,B,C,D,E,F)
#define pcap_next_ex(A,B,C) PacketNextEx(A,B,C)
#define pcap_findalldevs_ex(A,B,C,D) PacketFindALlDevsEx(A,B,C,D)
int (*PacketSendPacket)(pcap_t *, const u_char *, int) = 0;
void (*PacketClose)(pcap_t *) = 0;
void (*PacketFreealldevs)(pcap_if_t *) = 0;
pcap_t* (*PacketOpen)(char const *,int,int,int,struct pcap_rmtauth *,char *) = 0;
int (*PacketNextEx)(pcap_t *, struct pcap_pkthdr **, const u_char **) = 0;
int (*PacketFindALlDevsEx)(char *, struct pcap_rmtauth *, pcap_if_t **, char *) = 0;
#endif
#endif
//Never completely fill the ne2k ring so that we never
// hit the unclear completely full buffer condition.
#define BX_NE2K_NEVER_FULL_RING (1)
@@ -304,9 +277,7 @@ bx_ne2k_c::write_cr(uint32_t value)
// Send the packet to the system driver
/* TODO: Transmit packet */
//BX_NE2K_THIS ethdev->sendpkt(& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART], BX_NE2K_THIS s.tx_bytes);
#ifdef C_PCAP
pcap_sendpacket(adhandle,&s.mem[s.tx_page_start*256 - BX_NE2K_MEMSTART], s.tx_bytes);
#endif
ethernet->SendPacket(&s.mem[s.tx_page_start*256 - BX_NE2K_MEMSTART], s.tx_bytes);
// some more debug
if (BX_NE2K_THIS s.tx_timer_active) {
BX_PANIC(("CR write, tx timer still active"));
@@ -1473,25 +1444,15 @@ static void NE2000_TX_Event(Bitu val) {
}
static void NE2000_Poller(void) {
#ifdef C_PCAP
int res;
struct pcap_pkthdr *header;
u_char *pkt_data;
//#if 0
while((res = pcap_next_ex( adhandle, &header, (const u_char **)&pkt_data)) > 0) {
ethernet->GetPackets([](const uint8_t* packet, int len) {
//LOG_MSG("NE2000: Received %d bytes", header->len);
// don't receive in loopback modes
if((theNE2kDevice->s.DCR.loop == 0) || (theNE2kDevice->s.TCR.loop_cntl != 0))
return;
theNE2kDevice->rx_frame(pkt_data, header->len);
}
//#endif
#endif
theNE2kDevice->rx_frame(packet, len);
});
}
#ifdef WIN32
#include <windows.h>
#endif
extern std::string niclist;
@@ -1516,67 +1477,12 @@ public:
return;
}
#ifndef C_PCAP
LOG_MSG("pcap support not enabled, disabling ne2000");
load_success = false;
return;
#endif
#ifdef C_PCAP
#ifdef WIN32
/*
int (*PacketSendPacket)(pcap_t *, const u_char *, int);
void (*PacketClose)(pcap_t *);
void (*PacketFreealldevs)(pcap_if_t *);
pcap_t* (*PacketOpen)(char const *,int,int,int,struct pcap_rmtauth *,char *);
int (*PacketNextEx)(pcap_t *, struct pcap_pkthdr **, const u_char **);
int (*PacketFindALlDevsEx)(char *, struct pcap_rmtauth *, pcap_if_t **, char *);
*/
// init the library
HINSTANCE pcapinst;
pcapinst = LoadLibrary("WPCAP.DLL");
if(pcapinst==NULL) {
niclist = "WinPcap has to be installed for the NE2000 to work.";
LOG_MSG(niclist.c_str());
ethernet = OpenEthernetConnection("pcap");
if(!ethernet)
{
load_success = false;
return;
}
FARPROC psp;
psp = GetProcAddress(pcapinst,"pcap_sendpacket");
if(!PacketSendPacket) PacketSendPacket =
(int (__cdecl *)(pcap_t *,const u_char *,int))psp;
psp = GetProcAddress(pcapinst,"pcap_close");
if(!PacketClose) PacketClose =
(void (__cdecl *)(pcap_t *)) psp;
psp = GetProcAddress(pcapinst,"pcap_freealldevs");
if(!PacketFreealldevs) PacketFreealldevs =
(void (__cdecl *)(pcap_if_t *)) psp;
psp = GetProcAddress(pcapinst,"pcap_open");
if(!PacketOpen) PacketOpen =
(pcap_t* (__cdecl *)(char const *,int,int,int,struct pcap_rmtauth *,char *)) psp;
psp = GetProcAddress(pcapinst,"pcap_next_ex");
if(!PacketNextEx) PacketNextEx =
(int (__cdecl *)(pcap_t *, struct pcap_pkthdr **, const u_char **)) psp;
psp = GetProcAddress(pcapinst,"pcap_findalldevs_ex");
if(!PacketFindALlDevsEx) PacketFindALlDevsEx =
(int (__cdecl *)(char *, struct pcap_rmtauth *, pcap_if_t **, char *)) psp;
if(PacketFindALlDevsEx==0 || PacketNextEx==0 || PacketOpen==0 ||
PacketFreealldevs==0 || PacketClose==0 || PacketSendPacket==0) {
niclist = "Incorrect or non-functional WinPcap version.";
LOG_MSG(niclist.c_str());
load_success = false;
return;
}
#endif
#endif
// get irq and base
Bitu irq = (Bitu)section->Get_int("nicirq");
@@ -1605,120 +1511,6 @@ public:
mac[4]=macint[4]; mac[5]=macint[5];
}
#ifdef C_PCAP
// find out which pcap device to use
const char* realnicstring=section->Get_string("realnic");
pcap_if_t *alldevs;
pcap_if_t *currentdev = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
unsigned int userdev;
#ifdef WIN32
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
#else
if (pcap_findalldevs(&alldevs, errbuf) == -1)
#endif
{
niclist = "Cannot enumerate network interfaces: "+std::string(errbuf);
LOG_MSG("%s", niclist.c_str());
load_success = false;
return;
}
{
Bitu i = 0;
niclist = "Network Interface List\n-------------------------------------------------------------\n";
for(currentdev=alldevs; currentdev!=NULL; currentdev=currentdev->next) {
const char* desc = "no description";
if(currentdev->description) desc=currentdev->description;
i++;
niclist+=(i<10?"0":"")+std::to_string(i)+" "+currentdev->name+"\n ("+desc+")\n";
}
}
if (!strcasecmp(realnicstring,"list")) {
// print list and quit
std::istringstream in(("\n"+niclist+"\n").c_str());
if (in) for (std::string line; std::getline(in, line); )
LOG_MSG("%s", line.c_str());
pcap_freealldevs(alldevs);
load_success = false;
return;
} else if(1==sscanf(realnicstring,"%u",&userdev)) {
// user passed us a number
Bitu i = 0;
currentdev=alldevs;
while(currentdev!=NULL) {
i++;
if(i==userdev) break;
else currentdev=currentdev->next;
}
} else {
// user might have passed a piece of name
for(currentdev=alldevs; currentdev!=NULL; currentdev=currentdev->next) {
if(strstr(currentdev->name,realnicstring)) {
break;
}else if(currentdev->description!=NULL &&
strstr(currentdev->description,realnicstring)) {
break;
}
}
}
if(currentdev==NULL) {
LOG_MSG("Unable to find network interface - check realnic parameter\n");
load_success = false;
pcap_freealldevs(alldevs);
return;
}
// print out which interface we are going to use
const char* desc = "no description";
if(currentdev->description) desc=currentdev->description;
LOG_MSG("Using Network interface:\n%s\n(%s)\n",currentdev->name,desc);
const char *timeoutstr = section->Get_string("pcaptimeout");
char *end;
int timeout = -1;
if (!strlen(timeoutstr)||timeoutstr[0]!='-'&&!isdigit(timeoutstr[0])) { // Default timeout values
#ifdef WIN32
timeout = -1; // For Windows, use -1 which appears to be specific to WinPCap and means "non-blocking mode"
#else
timeout = 3000; // For other platforms, use 3000ms as the timeout which should work for platforms like macOS
#endif
} else
timeout = strtoul(timeoutstr,&end,10);
// attempt to open it
#ifdef WIN32
if ( (adhandle= pcap_open(
currentdev->name, // name of the device
65536, // portion of the packet to capture
// 65536 = whole packet
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
timeout, // read timeout
NULL, // authentication on the remote machine
errbuf // error buffer
) ) == NULL)
#else
/*pcap_t *pcap_open_live(const char *device, int snaplen,
int promisc, int to_ms, char *errbuf)*/
if ( (adhandle= pcap_open_live(
currentdev->name, // name of the device
65536, // portion of the packet to capture
// 65536 = whole packet
true, // promiscuous mode
timeout, // read timeout
errbuf // error buffer
) ) == NULL)
#endif
{
LOG_MSG("\nUnable to open the interface: %s.", errbuf);
pcap_freealldevs(alldevs);
load_success = false;
return;
}
pcap_freealldevs(alldevs);
#ifndef WIN32
pcap_setnonblock(adhandle,1,errbuf);
#endif
#endif
// create the bochs NIC class
theNE2kDevice = new bx_ne2k_c ();
memcpy(theNE2kDevice->s.physaddr, mac, 6);
@@ -1739,10 +1531,8 @@ public:
}
~NE2K() {
#ifdef C_PCAP
if(adhandle) pcap_close(adhandle);
adhandle=0;
#endif
if(ethernet != 0) delete ethernet;
ethernet=0;
if(theNE2kDevice != 0) delete theNE2kDevice;
theNE2kDevice=0;
TIMER_DelTickHandler(NE2000_Poller);

View File

@@ -3,4 +3,4 @@ AM_CPPFLAGS = -I$(top_srcdir)/include "-DRESDIR=\"$(resdir)\""
resdir = $(datarootdir)/dosbox-x
noinst_LIBRARIES = libmisc.a
libmisc_a_SOURCES = cross.cpp ethernet.cpp messages.cpp programs.cpp setup.cpp support.cpp regionalloctracking.cpp savestates.cpp shiftjis.cpp iconvpp.cpp
libmisc_a_SOURCES = cross.cpp ethernet.cpp ethernet_pcap.cpp messages.cpp programs.cpp setup.cpp support.cpp regionalloctracking.cpp savestates.cpp shiftjis.cpp iconvpp.cpp

View File

@@ -17,10 +17,31 @@
*/
#include "ethernet.h"
#include "ethernet_pcap.h"
#include <cstring>
#include "dosbox.h"
EthernetConnection* OpenEthernetConnection(const std::string& backend)
{
// We currently have no backends, so return nothing at the moment.
(void)backend;
return nullptr;
EthernetConnection* conn = nullptr;
#ifdef C_PCAP
if (backend == "pcap")
{
conn = ((EthernetConnection*)new PcapEthernetConnection);
}
#endif
if (!conn)
{
LOG_MSG("ETHERNET: Unknown ethernet backend: %s", backend.c_str());
return nullptr;
}
if (conn->Initialize())
{
return conn;
}
else
{
delete conn;
return nullptr;
}
}

237
src/misc/ethernet_pcap.cpp Normal file
View File

@@ -0,0 +1,237 @@
/*
* Copyright (C) 2021 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "config.h"
#if C_PCAP
#include "ethernet_pcap.h"
#include "dosbox.h"
#include "support.h" /* strcasecmp */
#include <cstring>
extern std::string niclist;
#ifdef WIN32
#include <windows.h>
// DLL loading
#define pcap_sendpacket(A,B,C) PacketSendPacket(A,B,C)
#define pcap_close(A) PacketClose(A)
#define pcap_freealldevs(A) PacketFreealldevs(A)
#define pcap_open(A,B,C,D,E,F) PacketOpen(A,B,C,D,E,F)
#define pcap_next_ex(A,B,C) PacketNextEx(A,B,C)
#define pcap_findalldevs_ex(A,B,C,D) PacketFindALlDevsEx(A,B,C,D)
int (*PacketSendPacket)(pcap_t *, const u_char *, int) = 0;
void (*PacketClose)(pcap_t *) = 0;
void (*PacketFreealldevs)(pcap_if_t *) = 0;
pcap_t* (*PacketOpen)(char const *,int,int,int,struct pcap_rmtauth *,char *) = 0;
int (*PacketNextEx)(pcap_t *, struct pcap_pkthdr **, const u_char **) = 0;
int (*PacketFindALlDevsEx)(char *, struct pcap_rmtauth *, pcap_if_t **, char *) = 0;
#endif
PcapEthernetConnection::PcapEthernetConnection()
: EthernetConnection()
{
}
PcapEthernetConnection::~PcapEthernetConnection()
{
if(adhandle) pcap_close(adhandle);
}
bool PcapEthernetConnection::Initialize()
{
/* TODO: grab from config */
const char* realnicstring = "list";
#ifdef WIN32
// init the library
HINSTANCE pcapinst;
pcapinst = LoadLibrary("WPCAP.DLL");
if(pcapinst==NULL) {
niclist = "WinPcap has to be installed for the NE2000 to work.";
LOG_MSG(niclist.c_str());
return false;
}
FARPROC psp;
psp = GetProcAddress(pcapinst,"pcap_sendpacket");
if(!PacketSendPacket) PacketSendPacket =
(int (__cdecl *)(pcap_t *,const u_char *,int))psp;
psp = GetProcAddress(pcapinst,"pcap_close");
if(!PacketClose) PacketClose =
(void (__cdecl *)(pcap_t *)) psp;
psp = GetProcAddress(pcapinst,"pcap_freealldevs");
if(!PacketFreealldevs) PacketFreealldevs =
(void (__cdecl *)(pcap_if_t *)) psp;
psp = GetProcAddress(pcapinst,"pcap_open");
if(!PacketOpen) PacketOpen =
(pcap_t* (__cdecl *)(char const *,int,int,int,struct pcap_rmtauth *,char *)) psp;
psp = GetProcAddress(pcapinst,"pcap_next_ex");
if(!PacketNextEx) PacketNextEx =
(int (__cdecl *)(pcap_t *, struct pcap_pkthdr **, const u_char **)) psp;
psp = GetProcAddress(pcapinst,"pcap_findalldevs_ex");
if(!PacketFindALlDevsEx) PacketFindALlDevsEx =
(int (__cdecl *)(char *, struct pcap_rmtauth *, pcap_if_t **, char *)) psp;
if(PacketFindALlDevsEx==0 || PacketNextEx==0 || PacketOpen==0 ||
PacketFreealldevs==0 || PacketClose==0 || PacketSendPacket==0) {
niclist = "Incorrect or non-functional WinPcap version.";
LOG_MSG(niclist.c_str());
pcapinst = NULL;
return false;
}
#endif
// find out which pcap device to use
pcap_if_t *alldevs;
pcap_if_t *currentdev = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
unsigned int userdev;
#ifdef WIN32
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
#else
if (pcap_findalldevs(&alldevs, errbuf) == -1)
#endif
{
niclist = "Cannot enumerate network interfaces: "+std::string(errbuf);
LOG_MSG("%s", niclist.c_str());
return false;
}
{
Bitu i = 0;
niclist = "Network Interface List\n-------------------------------------------------------------\n";
for(currentdev=alldevs; currentdev!=NULL; currentdev=currentdev->next) {
const char* desc = "no description";
if(currentdev->description) desc=currentdev->description;
i++;
niclist+=(i<10?"0":"")+std::to_string(i)+" "+currentdev->name+"\n ("+desc+")\n";
}
}
if (!strcasecmp(realnicstring,"list")) {
// print list and quit
std::istringstream in(("\n"+niclist+"\n").c_str());
if (in) for (std::string line; std::getline(in, line); )
LOG_MSG("%s", line.c_str());
pcap_freealldevs(alldevs);
return false;
} else if(1==sscanf(realnicstring,"%u",&userdev)) {
// user passed us a number
Bitu i = 0;
currentdev=alldevs;
while(currentdev!=NULL) {
i++;
if(i==userdev) break;
else currentdev=currentdev->next;
}
} else {
// user might have passed a piece of name
for(currentdev=alldevs; currentdev!=NULL; currentdev=currentdev->next) {
if(strstr(currentdev->name,realnicstring)) {
break;
}else if(currentdev->description!=NULL &&
strstr(currentdev->description,realnicstring)) {
break;
}
}
}
if(currentdev==NULL) {
LOG_MSG("Unable to find network interface - check realnic parameter\n");
pcap_freealldevs(alldevs);
return false;
}
// print out which interface we are going to use
const char* desc = "no description";
if(currentdev->description) desc=currentdev->description;
LOG_MSG("Using Network interface:\n%s\n(%s)\n",currentdev->name,desc);
const char *timeoutstr = section->Get_string("pcaptimeout");
char *end;
int timeout = -1;
if (!strlen(timeoutstr)||timeoutstr[0]!='-'&&!isdigit(timeoutstr[0])) { // Default timeout values
#ifdef WIN32
timeout = -1; // For Windows, use -1 which appears to be specific to WinPCap and means "non-blocking mode"
#else
timeout = 3000; // For other platforms, use 3000ms as the timeout which should work for platforms like macOS
#endif
} else
timeout = strtoul(timeoutstr,&end,10);
// attempt to open it
#ifdef WIN32
if ( (adhandle= pcap_open(
currentdev->name, // name of the device
65536, // portion of the packet to capture
// 65536 = whole packet
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
timeout, // read timeout
NULL, // authentication on the remote machine
errbuf // error buffer
) ) == NULL)
#else
/*pcap_t *pcap_open_live(const char *device, int snaplen,
int promisc, int to_ms, char *errbuf)*/
if ( (adhandle= pcap_open_live(
currentdev->name, // name of the device
65536, // portion of the packet to capture
// 65536 = whole packet
true, // promiscuous mode
timeout, // read timeout
errbuf // error buffer
) ) == NULL)
#endif
{
LOG_MSG("\nUnable to open the interface: %s.", errbuf);
pcap_freealldevs(alldevs);
return false;
}
pcap_freealldevs(alldevs);
#ifndef WIN32
pcap_setnonblock(adhandle,1,errbuf);
#endif
return true;
}
void PcapEthernetConnection::SendPacket(const uint8_t* packet, int len)
{
pcap_sendpacket(adhandle, packet, len);
}
void PcapEthernetConnection::GetPackets(std::function<void(const uint8_t*, int)> callback)
{
int res;
struct pcap_pkthdr *header;
u_char *pkt_data;
//#if 0
while((res = pcap_next_ex( adhandle, &header, (const u_char **)&pkt_data)) > 0) {
callback(pkt_data, header->len);
}
//#endif
}
#endif

55
src/misc/ethernet_pcap.h Normal file
View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2021 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DOSBOX_ETHERNET_PCAP_H
#define DOSBOX_ETHERNET_PCAP_H
#include "config.h"
#if C_PCAP
#include "ethernet.h"
#ifdef WIN32
#define HAVE_REMOTE
#endif
#include "support.h" /* Prevents snprintf conflict with pcap on Windows */
#include "pcap.h"
/** A PCAP-based Ethernet connection
* This backend uses a physical Ethernet device. All types of traffic
* such as IPX, TCP, NetBIOS work over this interface.
* This requires libpcap or WinPcap to be installed and your selected
* network interface to support promiscious operation.
*/
class PcapEthernetConnection : public EthernetConnection {
public:
PcapEthernetConnection();
~PcapEthernetConnection();
bool Initialize();
void SendPacket(const uint8_t* packet, int len);
void GetPackets(std::function<void(const uint8_t*, int)> callback);
private:
pcap_t* adhandle = 0; /*!< The pcap handle used for this device */
};
#endif
#endif

View File

@@ -1297,6 +1297,7 @@ copy "$(SolutionDir)\..\contrib\windows\shaders\*.*" "$(OutputPath)\shaders\"</C
<ClCompile Include="..\src\misc\cross.cpp" />
<ClCompile Include="..\src\misc\ethernet.cpp" />
<ClCompile Include="..\src\misc\messages.cpp" />
<ClCompile Include="..\src\misc\ethernet_pcap.cpp" />
<ClCompile Include="..\src\misc\programs.cpp" />
<ClCompile Include="..\src\ints\qcow2_disk.cpp" />
<ClCompile Include="..\src\misc\regionalloctracking.cpp" />
@@ -1638,6 +1639,7 @@ copy "$(SolutionDir)\..\contrib\windows\shaders\*.*" "$(OutputPath)\shaders\"</C
<ClInclude Include="..\src\libs\mt32\TVA.h" />
<ClInclude Include="..\src\libs\mt32\TVF.h" />
<ClInclude Include="..\src\libs\mt32\TVP.h" />
<ClInclude Include="..\src\misc\ethernet_pcap.h" />
<ClInclude Include="..\src\output\direct3d\d3d_components.h" />
<ClInclude Include="..\src\output\direct3d\direct3d.h" />
<ClInclude Include="..\src\output\direct3d\hq2x_d3d.h" />
@@ -1656,4 +1658,4 @@ copy "$(SolutionDir)\..\contrib\windows\shaders\*.*" "$(OutputPath)\shaders\"</C
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@@ -618,6 +618,9 @@
<ClCompile Include="..\src\misc\messages.cpp">
<Filter>Sources\misc</Filter>
</ClCompile>
<ClCompile Include="..\src\misc\ethernet_pcap.cpp">
<Filter>Sources\misc</Filter>
</ClCompile>
<ClCompile Include="..\src\misc\regionalloctracking.cpp">
<Filter>Sources\misc</Filter>
</ClCompile>
@@ -1787,6 +1790,9 @@
<ClInclude Include="..\src\libs\mt32\sha1\sha1.h">
<Filter>Sources\libs\mt32\sha1</Filter>
</ClInclude>
<ClInclude Include="..\src\misc\ethernet_pcap.h">
<Filter>Sources\misc</Filter>
</ClInclude>
<ClInclude Include="..\src\hardware\reSID\envelope.h">
<Filter>Sources\hardware\reSID</Filter>
</ClInclude>
@@ -2411,4 +2417,4 @@
<Filter>Sources</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
</Project>