#ifndef STF370_PacketFilterDissector_h
#define STF370_PacketFilterDissector_h

#include <string>
 
using namespace std;

struct EthernetHeader {
  unsigned char destination[6];
  unsigned char source[6];
  unsigned short type;
};

struct IpHeader {
#if BYTE_ORDER == LITTLE_ENDIAN
  unsigned char headerLength:4,    // 4-bit header length (in 32-bit words)
    version:4;                     // 4-bit IPv4 version
#else
#if BYTE_ORDER == BIG_ENDIAN
  unsigned char version:4,         // 4-bit IPv4 version
    headerLength:4;                // 4-bit header length (in 32-bit words)
#endif
#endif
  unsigned char  tos;              // IP type of service
  unsigned short totalLength;      // Total length
  unsigned short id;               // Unique identifier 
    
  unsigned char  fragOffset   :5;  // Fragment offset field
    
  unsigned char  moreFragment :1;
  unsigned char  dontFragment :1;
  unsigned char  reservedZero :1;
    
  unsigned char  fragOffset1;      //fragment offset
    
  unsigned char  ttl;              // Time to live
  unsigned char  protocol;         // Protocol(TCP,UDP etc)
  unsigned short checksum;         // IP checksum
  unsigned char  srcAddr[4];       // Source address
  unsigned char  destAddr[4];      // Source address
}; // End of struct IpHeader

struct IpV6Header {
#if BYTE_ORDER == LITTLE_ENDIAN
  unsigned char msbDS:4,    // 4-bit for MSB DS byte
    						version:4;  // 4-bit IPv6 version, and will thus contain the number 6
  unsigned char msbFlowLabel:4,	 // 4-bit for MSB flow label (i.e. Label for a data flow)
  							lsbDS:4; 	 // 4-bit for LSB DS byte
#else
#if BYTE_ORDER == BIG_ENDIAN
  unsigned char version:4, // 4-bit IPv6 version, and will thus contain the number 6
    						msbDS:4;	 // 4-bit for MSB DS byte
  unsigned char lsbDS:4, 	 			 // 4-bit for LSB DS byte
    						msbFlowLabel:4;	 // 4-bit for MSB flow label (i.e. Label for a data flow)
#endif
#endif
  unsigned short lsbFlowLabel;  // Label for a data flow
  unsigned short payloadLength; // Indicates the length of the packet data field
  unsigned char  tos;           // Identifies the type of header immediately following the IPv6 header
  unsigned char  hopLimit;      // Decremented by one by each node that forwards the packet. When the hop limit field reaches zero, the packet is discarded.
  unsigned char  srcAddr[16];       // The address of the originator of the packet
  unsigned char  destAddr[16];      // Source address
}; // End of struct IpV6Header

struct UdpHeader
{
  unsigned short srcPort;         // Source port no.
  unsigned short destPort;        // Dest. port no.
  unsigned short length;          // UDP packet length
  unsigned short checksum;        // UDP checksum (optional)
};

struct TcpHeader 
{
  unsigned short srcPort;          // source port 
  unsigned short destPort;         // destination port 
  unsigned int   sequence;         // sequence number - 32 bits 
  unsigned int   acknowledge;      // acknowledgement number - 32 bits 
        
  unsigned char  ns   :1;          //Nonce Sum Flag Added in RFC 3540.
  unsigned char  reservedPart1:3;  //according to rfc
  unsigned char  dataOffset:4;     //number of dwords in the TCP header. 
    
  unsigned char  fin  :1;          //Finish Flag
  unsigned char  syn  :1;          //Synchronise Flag
  unsigned char  rst  :1;          //Reset Flag
  unsigned char  psh  :1;          //Push Flag 
  unsigned char  ack  :1;          //Acknowledgement Flag 
  unsigned char  urg  :1;          //Urgent Flag
    
  unsigned char  ecn  :1;          //ECN-Echo Flag
  unsigned char  cwr  :1;          //Congestion Window Reduced Flag
        
  unsigned short window;           // window 
  unsigned short checksum;         // checksum 
  unsigned short urgentPointer;    // urgent pointer 
};


#define ETH_TYPE_IP     8
#define ETH_TYPE_IPv6   0xdd86
#define IP_PROTO_TCP    6
#define IP_PROTO_UDP    17

enum HeaderId {
  e_NoHeader,
  e_Ethernet,
  e_Ip,
  e_Tcp,
  e_Udp
};

enum FieldId {
  e_NoField,
  e_Addr,
  e_Src,
  e_Dst,
  e_Port,
  e_SrcPort,
  e_DstPort,
  e_Proto
};

class PacketDissector {

 public:
  PacketDissector(const char* psPacket = "");
  virtual ~PacketDissector();
  bool Match(const HeaderId& header, const FieldId& sField, const string& sValue) const;

 private:
  EthernetHeader *m_ethHdr;
  IpHeader *m_ipHdr;
  IpV6Header *m_ipv6Hdr;
  UdpHeader *m_udpHdr;
  TcpHeader *m_tcpHdr;
  char *m_payload;
};

#endif
