#include "StdAfx.h"
#include "ipbridgeimpl.h"
#include "protocolsdefs.h"



bpf_insn _Adapter::m_TargetTamplate[]={
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 2, 0x00000800 },
{ 0x20, 0, 0, 0x0000001a },
{ 0x15, 4, 5, 0xffffffff },
{ 0x15, 1, 0, 0x00000806 },
{ 0x15, 0, 3, 0x00008035 },
{ 0x20, 0, 0, 0x0000001c },
{ 0x15, 0, 1, 0xffffffff },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 },
};

bpf_insn _Adapter::m_SourceTamplate[]={
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 2, 0x00000800 },
{ 0x20, 0, 0, 0x0000001e },
{ 0x15, 4, 5, 0xffffffff },
{ 0x15, 1, 0, 0x00000806 },
{ 0x15, 0, 3, 0x00008035 },
{ 0x20, 0, 0, 0x00000026 },
{ 0x15, 0, 1, 0xffffffff },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 },
};

_Adapter::_Adapter()
{
	m_pPacketBuf=NULL;
	m_pAdapter=NULL;
	m_pInPacket=NULL;
	m_pBPFCode=NULL;
}

_Adapter::~_Adapter()
{
	Close();
}

void _Adapter::Open(const char *sName,DWORD dwIPFilter,bool bTargetSide)
{
	m_bTarget=bTargetSide;
	m_dwIPFilter=dwIPFilter;
	m_dwLastMulticast=0;
//	ip sample;
//	arphdr arp;
	int nBPFProgramLen=0;
	if(bTargetSide)
	{
		m_dwARPOffSet=0x1c;//((DWORD)&arp.__ar_sip)-((DWORD)&arp)+sizeof(ether_header);
		m_dwIPOffSet=0x1a;//(((DWORD)&sample.ip_src.S_un.S_addr)-((DWORD)&sample))+sizeof(ether_header);
		nBPFProgramLen=sizeof(_Adapter::m_TargetTamplate)/sizeof(bpf_insn);
		m_pBPFCode=new bpf_insn[nBPFProgramLen];
		memcpy(m_pBPFCode,_Adapter::m_TargetTamplate,sizeof(_Adapter::m_TargetTamplate));
		m_pBPFCode[3].k=m_dwIPFilter;
		m_pBPFCode[7].k=m_dwIPFilter;
	}
	else
	{
		m_dwARPOffSet=0x26;//((DWORD)&arp.__ar_tip)-((DWORD)&arp)+sizeof(ether_header);
		m_dwIPOffSet=0x1e;//((DWORD)&sample.ip_dst.S_un.S_addr)-((DWORD)&sample)+sizeof(ether_header);
		nBPFProgramLen=sizeof(_Adapter::m_SourceTamplate)/sizeof(bpf_insn);
		m_pBPFCode=new bpf_insn[nBPFProgramLen];
		memcpy(m_pBPFCode,_Adapter::m_SourceTamplate,sizeof(_Adapter::m_SourceTamplate));
		m_pBPFCode[3].k=m_dwIPFilter;
		m_pBPFCode[7].k=m_dwIPFilter;
	}
	std::string sFullName=std::string("\\Device\\NPF_")+std::string(sName);
	m_pAdapter=PacketOpenAdapter((char *)sFullName.c_str());

	if(!m_pAdapter)
	{
		throw "error opening the adapter";
	}
	m_sName=sFullName;
	m_pPacketBuf=(BYTE *)::GlobalAlloc(GPTR,CAPTURE_BUF_SIZE);
	PacketSetHwFilter(m_pAdapter,NDIS_PACKET_TYPE_PROMISCUOUS);
	PacketSetBuff(m_pAdapter,CAPTURE_BUF_SIZE);
	PacketSetMinToCopy(m_pAdapter,1);
	m_pInPacket=PacketAllocatePacket();
	if(!m_pInPacket)
	{
		throw "error allocating the in packet";
	}
	m_bpfProgram.bf_len=nBPFProgramLen;
	m_bpfProgram.bf_insns=m_pBPFCode;
	//PacketSetBpf(m_pAdapter,&m_bpfProgram);
	PacketInitPacket(m_pInPacket,(char*)m_pPacketBuf,CAPTURE_BUF_SIZE); 
}

void _Adapter::Close()
{
	m_bDone=true;
	if(m_pAdapter)
	{
		 PacketCloseAdapter(m_pAdapter);
		 m_pAdapter=NULL;
	}
	if(m_pInPacket)
	{
		PacketFreePacket(m_pInPacket);
		m_pInPacket=NULL;
	}
	if(m_pPacketBuf)
	{
		::GlobalFree(m_pPacketBuf);
		m_pPacketBuf=NULL;
	}
	if(m_pBPFCode)
	{
		delete[] m_pBPFCode;
		m_pBPFCode=NULL;
	}
}

bool _Adapter::SendPacket(BYTE *pData,DWORD dwSize)
{
	LPPACKET packet;
	packet=PacketAllocatePacket();
	PacketInitPacket(packet,pData,dwSize);
	if(PacketSendPacket(m_pAdapter,packet,TRUE)==FALSE)
	{
		PacketFreePacket(packet);
		return false;
	}
	PacketFreePacket(packet);
	return true;
}

bool _Adapter::Process(CIPBridgeImpl *pParent)
{
	m_bDone=false;
	BYTE *pBuf=NULL;
	BYTE *pData=NULL;
	UINT nSize=0;
	UINT nReceived;
	UINT off;
	bpf_hdr *hdr=NULL;
	ether_header *eth=NULL;
	int ethoffset=sizeof(ether_header);
	while(!m_bDone)
	{
		pBuf=NULL;
		pData=NULL;
		off=0;
		BOOL b=PacketReceivePacket(m_pAdapter,m_pInPacket,TRUE);
		if(!b) {
			printf("error in PacketReceivePacket\n");
			continue;
		}
		nReceived=m_pInPacket->ulBytesReceived;
		pBuf=(BYTE *)m_pInPacket->Buffer;
		DWORD dwIP=0;
		ether_header *eth;
		unsigned char tPacket[8000];
		while(off<nReceived)
		{
			hdr=(bpf_hdr *)(pBuf+off);
			off+=hdr->bh_hdrlen;
            pData=(BYTE *)(pBuf+off);
			nSize=hdr->bh_datalen;
			off=Packet_WORDALIGN(off+hdr->bh_caplen);
			
			//printf("packet\n");
			//classify the packet
			eth=(ether_header *)pData;
			/*if(pData[0]==0x01){ //multicast
				if((::GetTickCount()-m_dwLastMulticast)>500){
					m_dwLastMulticast=::GetTickCount();
					memcpy(tPacket,pData,nSize);
					pParent->OnPacket(tPacket,nSize,m_bTarget);
				}
				continue;
			}*/
			switch(eth->ether_type)
			{
				case ETHERTYPE_IP:
					dwIP=*((DWORD*)(&pData[m_dwIPOffSet]));
				break;
				case ETHERTYPE_ARP:
				case ETHERTYPE_REVARP:
					dwIP=*((DWORD*)(&pData[m_dwARPOffSet]));
				break;
				default:
					printf("Unrecognized packet type [eth type :0x%04X]\n",eth->ether_type);
				continue;
				break;
			}
			if(dwIP==m_dwIPFilter)
			{
				//do stuff with the packet
		//		printf("packet accepted received [%d]\n",nSize);
				memcpy(tPacket,pData,nSize);
				pParent->OnPacket(tPacket,nSize,m_bTarget);
				continue;
			}
			//check for multicast addresses
			if((dwIP&0x000000FF)==0xe0)
			{
				if((::GetTickCount()-m_dwLastMulticast)>500)
				{
					printf("multicast packet received [%d]\n",nSize);
					m_dwLastMulticast=::GetTickCount();
					memcpy(tPacket,pData,nSize);
					pParent->OnPacket(tPacket,nSize,m_bTarget);
				}
			}
		//	printf("packet discasrded [%d]\n",nSize);
			
		}
	}
	return true;
}