2014-04-06 13:11:19 +00:00
|
|
|
/* PCSX2 - PS2 Emulator for PCs
|
|
|
|
* Copyright (C) 2002-2014 David Quintana [gigaherz]
|
|
|
|
*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2013-03-19 22:01:41 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "pcap.h"
|
|
|
|
#include "pcap_io.h"
|
|
|
|
|
|
|
|
#include "dev9.h"
|
|
|
|
#include "net.h"
|
|
|
|
|
|
|
|
#include <Iphlpapi.h>
|
|
|
|
|
|
|
|
enum pcap_m_e
|
|
|
|
{
|
|
|
|
switched,
|
|
|
|
bridged
|
|
|
|
};
|
|
|
|
pcap_m_e pcap_mode=switched;
|
|
|
|
mac_address virtual_mac = { 0x76, 0x6D, 0x61, 0x63, 0x30, 0x31 };
|
|
|
|
//mac_address virtual_mac = { 0x6D, 0x76, 0x63, 0x61, 0x31, 0x30 };
|
|
|
|
mac_address broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
2015-06-24 00:36:01 +00:00
|
|
|
mac_address gateway_mac = { 0x76, 0x6D, 0x61, 0x63, 0x31, 0x32 };
|
2013-03-19 22:01:41 +00:00
|
|
|
|
|
|
|
ip_address virtual_ip = { 192, 168, 1, 4};
|
|
|
|
|
|
|
|
pcap_t *adhandle;
|
|
|
|
int pcap_io_running=0;
|
2015-06-24 00:36:01 +00:00
|
|
|
extern u8 eeprom[];
|
2013-03-19 22:01:41 +00:00
|
|
|
char errbuf[PCAP_ERRBUF_SIZE];
|
|
|
|
|
|
|
|
char namebuff[256];
|
|
|
|
|
|
|
|
FILE*packet_log;
|
|
|
|
|
|
|
|
pcap_dumper_t *dump_pcap;
|
|
|
|
|
|
|
|
mac_address host_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
|
|
|
|
// Fetches the MAC address and prints it
|
|
|
|
int GetMACAddress(char *adapter, mac_address* addr)
|
|
|
|
{
|
|
|
|
static IP_ADAPTER_INFO AdapterInfo[128]; // Allocate information
|
|
|
|
// for up to 128 NICs
|
|
|
|
static PIP_ADAPTER_INFO pAdapterInfo;
|
|
|
|
ULONG dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
|
|
|
|
|
|
|
|
DWORD dwStatus = GetAdaptersInfo( // Call GetAdapterInfo
|
|
|
|
AdapterInfo, // [out] buffer to receive data
|
|
|
|
&dwBufLen); // [in] size of receive data buffer
|
|
|
|
if(dwStatus != ERROR_SUCCESS) // Verify return value is
|
|
|
|
return 0; // valid, no buffer overflow
|
|
|
|
|
|
|
|
pAdapterInfo = AdapterInfo; // Contains pointer to
|
|
|
|
// current adapter info
|
|
|
|
do {
|
|
|
|
if(strcmp(pAdapterInfo->AdapterName,adapter+12)==0)
|
|
|
|
{
|
|
|
|
memcpy(addr,pAdapterInfo->Address,6);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pAdapterInfo = pAdapterInfo->Next; // Progress through
|
|
|
|
}
|
|
|
|
while(pAdapterInfo); // Terminate if last adapter
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pcap_io_init(char *adapter)
|
|
|
|
{
|
|
|
|
int dlt;
|
|
|
|
char *dlt_name;
|
|
|
|
emu_printf("Opening adapter '%s'...",adapter);
|
2015-06-24 00:36:01 +00:00
|
|
|
u16 checksum;
|
2013-03-19 22:01:41 +00:00
|
|
|
GetMACAddress(adapter,&host_mac);
|
2014-01-09 22:39:23 +00:00
|
|
|
|
2015-06-24 00:36:01 +00:00
|
|
|
//Near copy of the host mac, butchered slightly, should be pretty good!
|
|
|
|
eeprom[0] = host_mac.bytes[0];
|
|
|
|
eeprom[1] = host_mac.bytes[1];
|
|
|
|
eeprom[2] = host_mac.bytes[2];
|
|
|
|
eeprom[3] = host_mac.bytes[2];
|
|
|
|
eeprom[4] = host_mac.bytes[5];
|
|
|
|
eeprom[5] = host_mac.bytes[4];
|
|
|
|
|
2015-06-24 21:14:50 +00:00
|
|
|
virtual_mac.bytes[0] = host_mac.bytes[0];
|
|
|
|
virtual_mac.bytes[1] = host_mac.bytes[1];
|
|
|
|
virtual_mac.bytes[2] = host_mac.bytes[2];
|
2015-06-24 22:42:28 +00:00
|
|
|
virtual_mac.bytes[3] = host_mac.bytes[2];
|
|
|
|
virtual_mac.bytes[4] = host_mac.bytes[5];
|
|
|
|
virtual_mac.bytes[5] = host_mac.bytes[4];
|
2015-06-24 00:36:01 +00:00
|
|
|
//The checksum seems to be all the values of the mac added up in 16bit chunks
|
|
|
|
checksum = dev9.eeprom[0] + dev9.eeprom[1] + dev9.eeprom[2] & 0xffff;
|
|
|
|
|
|
|
|
dev9.eeprom[3] = checksum;
|
|
|
|
|
|
|
|
//emu_printf("eeprom Mac set to %x %x %x %x %x %x", eeprom[0], eeprom[1], eeprom[2], eeprom[3], eeprom[4], eeprom[5]);
|
|
|
|
//emu_printf("Checksum %x %x", eeprom[6], eeprom[7]);
|
|
|
|
|
2013-03-19 22:01:41 +00:00
|
|
|
/* Open the adapter */
|
|
|
|
if ((adhandle= pcap_open_live(adapter, // name of the device
|
|
|
|
65536, // portion of the packet to capture.
|
|
|
|
// 65536 grants that the whole packet will be captured on all the MACs.
|
|
|
|
pcap_mode==switched?1:0, // promiscuous mode (nonzero means promiscuous)
|
|
|
|
1, // read timeout
|
|
|
|
errbuf // error buffer
|
|
|
|
)) == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", adapter);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dlt = pcap_datalink(adhandle);
|
|
|
|
dlt_name = (char*)pcap_datalink_val_to_name(dlt);
|
|
|
|
|
|
|
|
fprintf(stderr,"Device uses DLT %d: %s\n",dlt,dlt_name);
|
|
|
|
switch(dlt)
|
|
|
|
{
|
|
|
|
case DLT_EN10MB :
|
|
|
|
//case DLT_IEEE802_11:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SysMessage("ERROR: Unsupported DataLink Type (%d): %s",dlt,dlt_name);
|
|
|
|
pcap_close(adhandle);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pcap_setnonblock(adhandle,1,errbuf)==-1)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"WARNING: Error setting non-blocking mode. Default mode will be used.\n");
|
|
|
|
}
|
|
|
|
|
2015-06-11 22:18:25 +00:00
|
|
|
//Changing the LogSetting might not affect logging
|
|
|
|
//directory of winPcap logs if done after Open()
|
|
|
|
const std::string pfile(s_strLogPath + "/packet.log");
|
|
|
|
packet_log = fopen(pfile.c_str(), "w");
|
2013-03-19 22:01:41 +00:00
|
|
|
|
2015-06-11 22:18:25 +00:00
|
|
|
const std::string plfile(s_strLogPath + "/pkt_log.pcap");
|
|
|
|
dump_pcap = pcap_dump_open(adhandle, plfile.c_str());
|
2013-03-19 22:01:41 +00:00
|
|
|
|
|
|
|
pcap_io_running=1;
|
|
|
|
emu_printf("Ok.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int gettimeofday (struct timeval *tv, void* tz)
|
|
|
|
{
|
|
|
|
unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */
|
|
|
|
|
|
|
|
GetSystemTimeAsFileTime((LPFILETIME)&ns100);
|
|
|
|
tv->tv_usec = (long) ((ns100 / 10L) % 1000000L);
|
|
|
|
tv->tv_sec = (long) ((ns100 - 116444736000000000L) / 10000000L);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int pcap_io_send(void* packet, int plen)
|
|
|
|
{
|
|
|
|
struct pcap_pkthdr ph;
|
|
|
|
|
|
|
|
if(pcap_io_running<=0)
|
|
|
|
return -1;
|
|
|
|
emu_printf(" * pcap io: Sending %d byte packet.\n",plen);
|
|
|
|
|
|
|
|
if (pcap_mode==bridged)
|
|
|
|
{
|
|
|
|
if(((ethernet_header*)packet)->protocol == 0x0008) //IP
|
|
|
|
{
|
|
|
|
#ifndef PLOT_VERSION
|
|
|
|
virtual_ip = ((ip_header*)((u8*)packet+sizeof(ethernet_header)))->src;
|
|
|
|
#endif
|
|
|
|
virtual_mac = ((ethernet_header*)packet)->src;
|
|
|
|
}
|
|
|
|
if(((ethernet_header*)packet)->protocol == 0x0608) //ARP
|
|
|
|
{
|
|
|
|
#ifndef PLOT_VERSION
|
|
|
|
virtual_ip = ((arp_packet*)((u8*)packet+sizeof(ethernet_header)))->p_src;
|
|
|
|
#endif
|
|
|
|
virtual_mac = ((ethernet_header*)packet)->src;
|
|
|
|
|
|
|
|
((arp_packet*)((u8*)packet+sizeof(ethernet_header)))->h_src = host_mac;
|
|
|
|
}
|
|
|
|
((ethernet_header*)packet)->src = host_mac;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(dump_pcap)
|
|
|
|
{
|
|
|
|
gettimeofday(&ph.ts,NULL);
|
|
|
|
ph.caplen=plen;
|
|
|
|
ph.len=plen;
|
|
|
|
pcap_dump((u_char*)dump_pcap,&ph,(u_char*)packet);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(packet_log)
|
|
|
|
{
|
|
|
|
int i=0;
|
|
|
|
int n=0;
|
|
|
|
|
|
|
|
fprintf(packet_log,"PACKET SEND: %d BYTES\n",plen);
|
|
|
|
for(i=0,n=0;i<plen;i++)
|
|
|
|
{
|
|
|
|
fprintf(packet_log,"%02x",((unsigned char*)packet)[i]);
|
|
|
|
n++;
|
|
|
|
if(n==16)
|
|
|
|
{
|
|
|
|
fprintf(packet_log,"\n");
|
|
|
|
n=0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fprintf(packet_log," ");
|
|
|
|
}
|
|
|
|
fprintf(packet_log,"\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pcap_mode==switched)
|
|
|
|
{
|
|
|
|
if(mac_compare(((ethernet_header*)packet)->dst,broadcast_mac)==0)
|
|
|
|
{
|
|
|
|
static char pack[65536];
|
|
|
|
memcpy(pack,packet,plen);
|
|
|
|
|
|
|
|
((ethernet_header*)packet)->dst=host_mac;
|
|
|
|
pcap_sendpacket(adhandle, (u_char*)pack, plen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pcap_sendpacket(adhandle, (u_char*)packet, plen);
|
|
|
|
}
|
|
|
|
|
|
|
|
int pcap_io_recv(void* packet, int max_len)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
struct pcap_pkthdr *header;
|
|
|
|
const u_char *pkt_data1;
|
|
|
|
static u_char pkt_data[32768];
|
|
|
|
|
|
|
|
if(pcap_io_running<=0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if((res = pcap_next_ex(adhandle, &header, &pkt_data1)) > 0)
|
|
|
|
{
|
|
|
|
ethernet_header *ph=(ethernet_header*)pkt_data;
|
|
|
|
|
|
|
|
memcpy(pkt_data,pkt_data1,header->len);
|
|
|
|
|
|
|
|
if (pcap_mode==bridged)
|
|
|
|
{
|
|
|
|
if(((ethernet_header*)pkt_data)->protocol == 0x0008)
|
|
|
|
{
|
|
|
|
ip_header *iph=((ip_header*)((u8*)pkt_data+sizeof(ethernet_header)));
|
|
|
|
if(ip_compare(iph->dst,virtual_ip)==0)
|
|
|
|
{
|
|
|
|
((ethernet_header*)pkt_data)->dst = virtual_mac;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(((ethernet_header*)pkt_data)->protocol == 0x0608)
|
|
|
|
{
|
|
|
|
arp_packet *aph=((arp_packet*)((u8*)pkt_data+sizeof(ethernet_header)));
|
|
|
|
if(ip_compare(aph->p_dst,virtual_ip)==0)
|
|
|
|
{
|
|
|
|
((ethernet_header*)pkt_data)->dst = virtual_mac;
|
|
|
|
((arp_packet*)((u8*)packet+sizeof(ethernet_header)))->h_dst = virtual_mac;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if((memcmp(pkt_data,dev9.eeprom,6)!=0)&&(memcmp(pkt_data,&broadcast_mac,6)!=0))
|
|
|
|
{
|
|
|
|
//ignore strange packets
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(memcmp(pkt_data+6,dev9.eeprom,6)==0)
|
|
|
|
{
|
|
|
|
//avoid pcap looping packets
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(packet,pkt_data,header->len);
|
|
|
|
|
|
|
|
if(dump_pcap)
|
|
|
|
pcap_dump((u_char*)dump_pcap,header,(u_char*)packet);
|
|
|
|
|
|
|
|
|
|
|
|
if(packet_log)
|
|
|
|
{
|
|
|
|
int i=0;
|
|
|
|
int n=0;
|
|
|
|
int plen=header->len;
|
|
|
|
|
|
|
|
fprintf(packet_log,"PACKET RECV: %d BYTES\n",plen);
|
|
|
|
for(i=0,n=0;i<plen;i++)
|
|
|
|
{
|
|
|
|
fprintf(packet_log,"%02x",((unsigned char*)packet)[i]);
|
|
|
|
n++;
|
|
|
|
if(n==16)
|
|
|
|
{
|
|
|
|
fprintf(packet_log,"\n");
|
|
|
|
n=0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fprintf(packet_log," ");
|
|
|
|
}
|
|
|
|
fprintf(packet_log,"\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return header->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pcap_io_close()
|
|
|
|
{
|
|
|
|
if(packet_log)
|
|
|
|
fclose(packet_log);
|
|
|
|
if(dump_pcap)
|
|
|
|
pcap_dump_close(dump_pcap);
|
|
|
|
pcap_close(adhandle);
|
|
|
|
pcap_io_running=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pcap_io_get_dev_num()
|
|
|
|
{
|
|
|
|
pcap_if_t *alldevs;
|
|
|
|
pcap_if_t *d;
|
|
|
|
int i=0;
|
|
|
|
|
|
|
|
if(pcap_findalldevs(&alldevs, errbuf) == -1)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
d=alldevs;
|
|
|
|
while(d!=NULL) {d=d->next; i++;}
|
|
|
|
|
|
|
|
pcap_freealldevs(alldevs);
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* pcap_io_get_dev_name(int num,int md)
|
|
|
|
{
|
|
|
|
pcap_if_t *alldevs;
|
|
|
|
pcap_if_t *d;
|
|
|
|
int i=0;
|
|
|
|
|
|
|
|
if(pcap_findalldevs(&alldevs, errbuf) == -1)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
d=alldevs;
|
|
|
|
while(d!=NULL) {
|
|
|
|
if(num==i)
|
|
|
|
{
|
|
|
|
if (!md)
|
|
|
|
strcpy(namebuff,"pcap switch:");
|
|
|
|
else
|
|
|
|
strcpy(namebuff,"pcap bridge:");
|
|
|
|
strcat(namebuff,d->name);
|
|
|
|
pcap_freealldevs(alldevs);
|
|
|
|
return namebuff;
|
|
|
|
}
|
|
|
|
d=d->next; i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcap_freealldevs(alldevs);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* pcap_io_get_dev_desc(int num,int md)
|
|
|
|
{
|
|
|
|
pcap_if_t *alldevs;
|
|
|
|
pcap_if_t *d;
|
|
|
|
int i=0;
|
|
|
|
|
|
|
|
if(pcap_findalldevs(&alldevs, errbuf) == -1)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
d=alldevs;
|
|
|
|
while(d!=NULL) {
|
|
|
|
if(num==i)
|
|
|
|
{
|
|
|
|
if (!md)
|
|
|
|
strcpy(namebuff,"pcap switch:");
|
|
|
|
else
|
|
|
|
strcpy(namebuff,"pcap bridge:");
|
|
|
|
strcat(namebuff,d->description);
|
|
|
|
pcap_freealldevs(alldevs);
|
|
|
|
return namebuff;
|
|
|
|
}
|
|
|
|
d=d->next; i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcap_freealldevs(alldevs);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PCAPAdapter::PCAPAdapter()
|
|
|
|
{
|
|
|
|
//if (config.ethEnable == 0) return; //whut? nada!
|
|
|
|
if (config.Eth[5]=='s')
|
|
|
|
pcap_mode=switched;
|
|
|
|
else
|
|
|
|
pcap_mode=bridged;
|
|
|
|
|
|
|
|
if (pcap_io_init(config.Eth+12) == -1) {
|
|
|
|
SysMessage("Can't open Device '%s'\n", config.Eth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool PCAPAdapter::blocks()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
//gets a packet.rv :true success
|
|
|
|
bool PCAPAdapter::recv(NetPacket* pkt)
|
|
|
|
{
|
|
|
|
int size=pcap_io_recv(pkt->buffer,sizeof(pkt->buffer));
|
|
|
|
if(size<=0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pkt->size=size;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//sends the packet .rv :true success
|
|
|
|
bool PCAPAdapter::send(NetPacket* pkt)
|
|
|
|
{
|
|
|
|
if(pcap_io_send(pkt->buffer,pkt->size))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PCAPAdapter::~PCAPAdapter()
|
|
|
|
{
|
|
|
|
pcap_io_close();
|
|
|
|
}
|