#include "stdio.h"
#include <iostream.h>
#include "c:/ixp1200/include/hashsv.h"
#include "c:/ixp1200/include/uclo.h"
#include "c:/ixp1200/include/libd.h"
#include "c:/ixp1200/include/hal_sram.h"


#define MAX_ENTRIES 32



typedef struct {
  int internal_ip;
  int external_ip;
  int cksum_d;
  int padding;
 } nat_entry_t;


typedef struct {
  int external_port;
  int internal_ip;
  int internal_port;
  int cksum_d;
  int tcp_d;
  int padding[3];
 } inv_entry_t;

 typedef struct {
  int internal_port;
  int external_port;
  int tcp_d;
  int internal_ip;
 }port_entry_t;

 typedef struct {
   int command;
   int argument;
   int argument2;
 }command_t;

union packet{
 nat_entry_t nat_entry;

 inv_entry_t inv_entry;

 port_entry_t port_entry;

 command_t command;

} packet;

#define NAT_ADDR 0x2200
#define INV_ADDR 0x2280
#define PORT_ADDR (INV_ADDR+MAX_ENTRIES*sizeof(inv_entry_t))

unsigned int ocaw( unsigned int a, unsigned int b=0);
unsigned int ocas( unsigned int a, unsigned int b);

static SramUnit* sram;

/*typedef struct {
   unsigned int hi32;
   unsigned short lo16;
} hsv_Data48;
*/
LibHandle *library;
int myId=11;
void *objHandle;

int hash(int thingy){

//hsv_Data in, out;

//in.lo32=thingy&0xffff;
//in.hi32=thingy>>16;

//HashSv_Exec48(library, &in, &out);

//return ((out.lo32 & out.hi32<<16) % 32);

return(thingy & 0x1f);
}



/*unsigned int checksum(unsigned int a, unsigned int b){

unsigned int one, two, three, four;
unsigned int res_one, res_two, res_three;

one=(a&0xffff);
two=(a&0xffff0000)>>16;
res_one=one+two;
if ((res_one)>(1<<16)) res_one=(res_one+1)&0xffff;
else res_one=res_one&0xffff;

three=(b&0xffff);
four=(b&0xffff0000)>>16;
res_two=three+four;
if ((res_two)>(1<<16)) res_two=(res_two+1)&0xffff;
else res_two=res_two&0xffff;

res_three=res_two-res_one;
if ((res_three)>(1<<16)) res_three=(res_three+1)&0xffff;
else res_three=res_three&0xffff;

return(res_three);

}

*/

int scan_ip(){
 int a, b, c, d;
 scanf("%i.%i.%i.%i", &a, &b, &c, &d);
 printf("\n%i.%i.%i.%i\n", a, b, c, d);
 return((a<<24)+(b<<16)+(c<<8)+d);
}

unsigned int ocaw( unsigned int a, unsigned int b=0)
{
  return (ocas (
       ocas ( a>>16, a & 0xffff),
       ocas ( b>>16, b & 0xffff)
       ));
}


unsigned int add( unsigned int a, unsigned int b )
{
  ocaw( a, b );
}

unsigned int ocas( unsigned int a, unsigned int b)
{
  unsigned int retval = a + b;
  if (retval >= (1<<16))
    return ((retval+1)& 0xffff);
  else
    return retval;
}


unsigned int get_checksum_diff ( unsigned int new_ip, unsigned int old_ip )
{
  
  unsigned int retval=add ( new_ip, ocas( (~(old_ip >> 16))&0xffff, (~(old_ip & 0xffff))&0xffff ));
  cout << retval << endl;
  return retval;
}
  


void get_nat(){
cout << endl<< "Please enter the internal IP: "<< endl;

packet.nat_entry.internal_ip=scan_ip();
cout << endl<< "Please enter the external IP: "<< endl;
packet.nat_entry.external_ip=scan_ip();
packet.nat_entry.cksum_d=get_checksum_diff(packet.nat_entry.external_ip,packet.nat_entry.internal_ip);
int baseaddr=NAT_ADDR+(hash(packet.nat_entry.internal_ip)-1)*sizeof(int);
sram->write(baseaddr,packet.nat_entry.internal_ip);
sram->write(baseaddr+1,packet.nat_entry.external_ip);
sram->write(baseaddr+2,packet.nat_entry.cksum_d);
sram->write(baseaddr+3,0);
}

void get_inv(){
int temp;

cout << endl<< "Please enter the external port: "<< endl;
cin >> packet.inv_entry.external_port;
cout << endl<< "Please enter the internal port: "<< endl;
cin >> packet.inv_entry.internal_port;
cout << endl<< "Please enter the internal IP: "<< endl;
packet.inv_entry.internal_ip=scan_ip();
cout << endl<< "Please enter the external IP: "<< endl;
temp=scan_ip();

packet.inv_entry.cksum_d=get_checksum_diff(temp,packet.inv_entry.internal_ip);
packet.inv_entry.tcp_d=get_checksum_diff(packet.inv_entry.internal_port,packet.inv_entry.external_port);

int baseaddr=INV_ADDR+(hash(temp)-1)*2*sizeof(int);
sram->write(baseaddr,temp);
sram->write(baseaddr+1,packet.inv_entry.internal_ip);
sram->write(baseaddr+2,packet.inv_entry.internal_port);
sram->write(baseaddr+3,packet.inv_entry.cksum_d);
sram->write(baseaddr+4,packet.inv_entry.tcp_d);
sram->write(baseaddr+5,0);
sram->write(baseaddr+6,0);
sram->write(baseaddr+7,0);


}

void get_port(){
cout << endl<< "Please enter the internal port: "<< endl;
cin >> packet.port_entry.internal_port;
cout << endl<< "Please enter the external port: "<< endl;
cin >> packet.port_entry.external_port;
cout << endl<< "Please enter the internal IP: "<< endl;
packet.port_entry.internal_ip=scan_ip();
packet.port_entry.tcp_d=get_checksum_diff(packet.port_entry.internal_port,packet.port_entry.external_port);

int baseaddr=INV_ADDR+(sizeof(port_entry_t)*(packet.port_entry.internal_ip&0x1f))+hash(packet.port_entry.internal_port);
sram->write(baseaddr,packet.port_entry.internal_port);
sram->write(baseaddr+1,packet.inv_entry.external_port);
sram->write(baseaddr+2,packet.port_entry.tcp_d);
sram->write(baseaddr+3,packet.port_entry.internal_ip);

}


void del_nat(){
cout << endl<< "Please enter the internal IP: "<< endl;
packet.nat_entry.internal_ip=scan_ip();

int baseaddr=NAT_ADDR+hash(packet.nat_entry.internal_ip);
sram->write(baseaddr,packet.nat_entry.internal_ip);
sram->write(baseaddr+1,0);
sram->write(baseaddr+2,0);
sram->write(baseaddr+3,0);


}

void del_inv(){
cout << endl<< "Please enter the external port: "<< endl;
cin >> packet.inv_entry.external_port;

int baseaddr=INV_ADDR+hash(packet.inv_entry.external_port);
sram->write(baseaddr,packet.inv_entry.external_port);
sram->write(baseaddr+1,0);
sram->write(baseaddr+2,0);
sram->write(baseaddr+3,0);
sram->write(baseaddr+4,0);
sram->write(baseaddr+5,0);
sram->write(baseaddr+6,0);
sram->write(baseaddr+7,0);

}

void del_port(){
cout << endl<< "Please enter the internal port: "<< endl;
cin >> packet.port_entry.internal_port;
cout << endl<< "Please enter the internal IP: "<< endl;
packet.port_entry.internal_ip=scan_ip();


int baseaddr=INV_ADDR+(sizeof(port_entry_t)*(packet.port_entry.internal_ip&0x1f))+hash(packet.port_entry.internal_port);
sram->write(baseaddr,0);
sram->write(baseaddr+1,0);
sram->write(baseaddr+2,0);
sram->write(baseaddr+3,0);

}

void sram_read(int address){
unsigned int a;
sram->read(address,&a);
cout << a << endl;

}


void clear_tables(){
int baseaddr=NAT_ADDR;

for(int i=0;i<(MAX_ENTRIES*sizeof(nat_entry_t)+MAX_ENTRIES*sizeof(inv_entry_t)+MAX_ENTRIES*16*sizeof(port_entry_t));i++)
	sram->write(baseaddr+i,0);
}


int nat_admin(){
int choice;



       int status;

       sram = SRAM_Attach();



choice=1;
while(choice){

//initialization
packet.inv_entry.external_port=0;
packet.inv_entry.internal_ip=0;
packet.inv_entry.internal_port=0;
packet.inv_entry.cksum_d=0;
packet.inv_entry.tcp_d=0;

//menu choices

cout << endl << endl << "NAT Administrator Menu" << endl;
cout <<"(0) Quit" << endl;
cout <<"(1) Add NAT Entry" << endl;
cout <<"(2) Add Inverse NAT Entry" << endl;
cout <<"(3) Add Port Entry" << endl;
cout <<"(4) Delete NAT Entry" << endl;
cout <<"(5) Delete Inverse NAT Entry" << endl;
cout <<"(6) Delete Port Entry" << endl;
cout <<"(7) Clear All Tables" << endl;
cout <<"--->> ";
//scanf("%i", &choice);
cin >> choice;
cout << endl;
//do the choice
switch(choice){
        case 0: cout << "Thank you for using NAT Administrator" << endl; break;
        case 1: get_nat(); /*send_packet(1);*/ break;
        case 2: get_inv(); /*send_packet(2);*/ break;
        case 3: get_port(); /*send_packet(3);*/ break;
        case 4: del_nat(); /*send_packet(4);*/ break;
        case 5: del_inv(); /*send_packet(4);*/ break;
        case 6: del_port(); /*send_packet(4);*/ break;
        case 7: clear_tables(); /*send_packet(4);*/ break;
        default: cout << "Invalid Choice!" << endl; choice=1; 

}

}
return(0);

}