/* NAT_pkt_handler.c -  packet handler and table management functions */

#include <ix_rm.h>          /* Code uses the IXA Resource Manager       */
#undef LINUX                /* Prevents the compiler from complaining   */
#include <ix_cc.h>          /* Code uses the IXA CCI                    */
#include <ix_cci.h>
#include "NAT_shared_defs.h"
#include "NAT_types.h"
#include "NAT_net.h"

/* Macro to drop a packet and quit packet handler */
#define drop(arg_hBuffer) { ix_rm_buffer_free(arg_hBuffer);\
                            return IX_SUCCESS; }

/* Verbosity level */
extern int verb;

/* Static gateway IP address */
extern unsigned int gateway_ip;

/* Static network interface configuration */
extern net_if iface_table[];

/* Global NAT port */
static unsigned short global_nport=0;

/* Scratch rings */
extern ix_hw_ring_handle rxToNatRing, txScrRing[];

/* List of free buffers */
extern ix_buffer_free_list_handle hwFreeList;

/* Pointers to various run-time data structures */
extern nat_entry *f_nat_table, *r_nat_table;
extern unsigned int *f_index,*r_index;
extern arp_entry *arp_table;
extern unsigned char *f_timer, *r_timer;

/* Global procedures */
ix_error nat_pkt_handler(ix_buffer_handle,ix_uint32,void*);
ix_error resolve_arp(unsigned int);

/* Local procedures */
static void  process_arp_req(arp*,ix_hw_buffer_meta*,
                             ix_buffer_handle,eth*);
static void  process_arp_rep(arp*,ix_hw_buffer_meta*);
static void  send_icmp_echo_rep(ip*,icmp*,ix_hw_buffer_meta*,
                                ix_buffer_handle,eth*);
static int   process_icmp(icmp*,nat_entry*);
static int   process_udp(udp*,nat_entry*);
static int   process_tcp(tcp*,nat_entry*);
static char* find_arp_entry(unsigned int);
static int   add_arp_entry(arp_entry*);
static int   add_nat_entry(nat_entry*);
static void  add_r_nat_entry(unsigned int);
static void  del_nat_entry(unsigned int);
static int   set_new_nport(nat_entry*);
static void  send_pkt(void*, unsigned int, eth*,
                      unsigned char *, unsigned short);

/* Packet handler called when an exception packet arrives */
ix_error nat_pkt_handler(
	ix_buffer_handle arg_hBuffer,
	ix_uint32 arg_UserData,         /* Exception code */
	void* arg_pContext
	)
{
	ix_hw_buffer_meta *meta_data;
	void *buf;
	int cksum;
	eth *eth_pkt;
	arp *arp_pkt;
	arp_entry ae;
	ip* ip_pkt;
	icmp* icmp_pkt;
	tcp* tcp_pkt;
	udp* udp_pkt;
	nat_entry ne;
	char * gw_eth;
	ix_rm_buffer_get_data(arg_hBuffer, &buf);
	ix_rm_buffer_get_meta(arg_hBuffer, (void **)&meta_data);
	eth_pkt=(eth*)((int)buf+(int)(meta_data->m_Offset));
	if (eth_pkt->e_type == ETH_ARP) { /* Received ARP */
		if (verb == VERBOSE)
			printk("Received ARP packet\n");
		arp_pkt=(arp*)(eth_pkt->data);
		if ( arp_pkt->ar_op == ARP_REQ &&
		     arp_pkt->ar_tpa ==
		         iface_table[meta_data->m_InputPort].ip_addr) {
			/* Process ARP request */
			process_arp_req(arp_pkt,meta_data,
			                arg_hBuffer,eth_pkt);
			return IX_SUCCESS;
		} else
		if ( arp_pkt->ar_op == ARP_REP &&
		     arp_pkt->ar_tpa ==
		         iface_table[meta_data->m_InputPort].ip_addr) {
			/* Process an ARP reply */
			process_arp_rep(arp_pkt,meta_data);
			return IX_SUCCESS;
		} else drop(arg_hBuffer);
	}
	if (eth_pkt->e_type != ETH_IP)
		drop(arg_hBuffer);
	/* Received IP packet */
	ip_pkt=(ip*)(eth_pkt->data);
	if (verb == VERBOSE) {
		printk("Received IP packet\n");
		printk("\tIP src = %i.%i.%i.%i\n",IP2B(ip_pkt->ip_src));
		printk("\tIP dst = %i.%i.%i.%i\n",IP2B(ip_pkt->ip_dst));
		printk("\tprotocol: %i\n",ip_pkt->ip_p);
		printk("\tingress port = %i\n", meta_data->m_InputPort);
	}
	/* For simplicity, the code drops a datagram that */
	/*   contains IP options                          */
	if ( ip_pkt->ip_hl > 5)
	    drop(arg_hBuffer);
	if ( ip_pkt->ip_dst ==
	      iface_table[meta_data->m_InputPort].ip_addr) {
	    /* The packet is destined to the NAT box itself */
		if (ip_pkt->ip_p == IPT_ICMP) { /* Received ICMP */
			icmp_pkt=(icmp*)(ip_pkt->data);
			if (icmp_pkt->icmp_type == ICMP_ECHO_REQ) {
				/* Received ping */
	                	if (verb == VERBOSE)
					printk("Received ping for us\n");
				/* Send an echo reply */
				send_icmp_echo_rep(ip_pkt,icmp_pkt,
				                   meta_data,
				                   arg_hBuffer,eth_pkt);
	                	return IX_SUCCESS;
			}
		}
	}
	if ( /* Packet not from the gateway */
	    meta_data->m_InputPort != NAT_IFC &&
	    /* An entry is present in ARP table for the gateway */
	    (gw_eth = find_arp_entry(GW_IP)) != NULL ) {
		/* The packet is an exception because the NAT lookup */
		/* failed, so add a new entry to the NAT table       */
		ne.valid=0; /* Will be set to 1 later */
		ne.prot=ip_pkt->ip_p;
		ne.ip_addr_loc=ip_pkt->ip_src;
		ne.ip_addr_rem=ip_pkt->ip_dst;
		switch (ip_pkt->ip_p) {
			case IPT_ICMP:
				/* Packet is ICMP */
				icmp_pkt=(icmp*)(ip_pkt->data);
				if (process_icmp(icmp_pkt,&ne) < 0)
					drop(arg_hBuffer);
				break;
			case IPT_TCP:
				/* Received TCP */
				tcp_pkt=(tcp*)(ip_pkt->data);
				if (process_tcp(tcp_pkt,&ne) < 0)
					drop(arg_hBuffer);
				break;
			case IPT_UDP:
				/* Received UDP */
				udp_pkt=(udp*)(ip_pkt->data);
				if (process_udp(udp_pkt,&ne) < 0)
					drop(arg_hBuffer);
				break;
			default:
				drop(arg_hBuffer);
		}
		/* Create an ARP entry for this packet in case a reply */
		/* comes later                                         */
		ae.ip_addr=ip_pkt->ip_src;
		ae.eth_w0=*(int*)eth_pkt->e_src;
		ae.eth_w1=(*(short*)&eth_pkt->e_src[4]);
		ae.ifnum = meta_data->m_InputPort;
		ae.valid = 1;
		/* Update the IP checksum */
		cksum = ip_pkt->ip_sum+(ip_pkt->ip_src>>16)
		      + (ip_pkt->ip_src&0xFFFF)
		      + ((~iface_table[NAT_IFC].ip_addr)>>16)
		      + ((~iface_table[NAT_IFC].ip_addr)&0xFFFF);
		cksum=(cksum&0xFFFF)+(cksum>>16);
		cksum=(cksum&0xFFFF)+(cksum>>16);
		/* Update the IP packet */
		ip_pkt->ip_src = iface_table[NAT_IFC].ip_addr;
		ip_pkt->ip_sum=cksum&0xFFFF;
		/* Transmit the packet */
		send_pkt((void*)arg_hBuffer,NAT_IFC,eth_pkt,
		         gw_eth,ETH_IP);
		/* Add the ARP entry that was created above */
		add_arp_entry(&ae);
		return IX_SUCCESS;
	}
	/* Drop the packet */
	drop(arg_hBuffer);
}

/* Function to pass packet to TX microblock */
static void send_pkt(void* buf, unsigned int ifnum, eth* eth_pkt,
	unsigned char * eth_addr, unsigned short eth_type)
{
	ix_tx_req txreq;
	ix_uint32 txreq_size;
	/* Set ethernet addresses */
	*(int*)eth_pkt->e_dst=*(int*)eth_addr;
	*(short*)((int*)eth_pkt->e_dst+1)=*(short*)((int*)eth_addr+1);
	*(int*)eth_pkt->e_src=iface_table[ifnum].eth_w0;
	*(short*)((int*)eth_pkt->e_src+1)=(iface_table[ifnum].eth_w1>>16);
	eth_pkt->e_type = eth_type;
	/* Prepare Tx request */
	txreq.valid = 1;     /* valid request */
	txreq.reserved=0;    /* reserved -- set to zero */
	txreq.port = ifnum;  /* outgoing interface */
	txreq.buff_handle = (unsigned int)buf;   /* buffer handle */
	txreq_size=1;
	/* Put Tx request on appropriate Tx Scratch ring */
	ix_rm_hw_ring_put(txScrRing[txreq.port], &txreq_size,
	                  (ix_uint32 *)&txreq);
}

/* ARP lookup function */
char * find_arp_entry(unsigned int ipaddr)
{
	ix_hash_48 hash48v;
	int i,j;
	hash48v.m_LW0 = ipaddr;
	hash48v.m_LW1 = 0;
	ix_rm_hash_48_hash(&hash48v);
	j = hash48v.m_LW0&ARP_TABLE_BIT_MASK;
	for (i=0;i<ARP_TABLE_SIZE;i++) {
		if (ipaddr == arp_table[j].ip_addr && arp_table[j].valid)
			return((char*)&(arp_table[j].eth_w0));
		j=(j+1)&ARP_TABLE_BIT_MASK;
	}
	return NULL;
}

/* Function to resolve an ARP entry for given IP address (used */
/* to obtain an ARP entry for the gateway)                     */
ix_error resolve_arp(unsigned int ipaddr)
{
	char eth_bcast[]={0xff,0xff,0xff,0xff,0xff,0xff};
	void * buf;
	eth *eth_pkt;
	arp *arp_pkt;
	ix_buffer_handle hBuffer;
	ix_hw_buffer_meta *meta_data;
	int i;
	for (i=0;i<GW_MAC_RES_ATTEMPTS;i++) {
		ix_rm_buffer_alloc(hwFreeList,&hBuffer);
		ix_rm_buffer_get_data(hBuffer,(void**)&buf);
		ix_rm_buffer_get_meta(hBuffer, (void **)&meta_data);
		meta_data->m_Offset=0;
		meta_data->m_BufferSize=60;
		meta_data->m_PacketSize=60;
		eth_pkt=(eth*)((int)buf+(int)meta_data->m_Offset);
		arp_pkt=(arp*)(eth_pkt->data);
		arp_pkt->ar_hrd = 1; /* Ethernet */
		arp_pkt->ar_hln = 6;
		arp_pkt->ar_pro = ETH_IP; /* IPv4 */
		arp_pkt->ar_pln = 4;
		arp_pkt->ar_op = ARP_REQ;
		*(int*)arp_pkt->ar_tha=0;
		*(short*)((int*)arp_pkt->ar_tha+1)=0;
		arp_pkt->ar_tpa=GW_IP;
		*(int*)arp_pkt->ar_sha=iface_table[NAT_IFC].eth_w0;
		*(short*)((int*)arp_pkt->ar_sha+1)=
		        (iface_table[NAT_IFC].eth_w1>>16);
		arp_pkt->ar_spa1=
		        (short)(iface_table[NAT_IFC].ip_addr>>16);
		arp_pkt->ar_spa2=
		        (short)(iface_table[NAT_IFC].ip_addr&0xFFFF);
		send_pkt((void*)hBuffer, NAT_IFC, eth_pkt,
		         eth_bcast, ETH_ARP);
		printk("%s: Resolving gateway MAC address...\n",
		        NAT_DRIVER_NAME);
		ix_ossl_sleep(500);
		if (find_arp_entry(GW_IP) != NULL)
			return IX_SUCCESS;
	}
	return(-1);
}

/* Function to process an ARP request */
void process_arp_req(arp* arp_pkt,ix_hw_buffer_meta* meta_data,
	ix_buffer_handle arg_hBuffer,eth *eth_pkt)
{
	arp_entry ae;
	ae.ip_addr = (arp_pkt->ar_spa1<<16)|arp_pkt->ar_spa2;
	ae.eth_w0 = *(int*)arp_pkt->ar_sha;
	ae.eth_w1 = (*(short*)((int*)arp_pkt->ar_sha+1));
	ae.ifnum = meta_data->m_InputPort;
	ae.valid = 1;
	arp_pkt->ar_op = ARP_REP;
	*(int*)arp_pkt->ar_tha=*(int*)arp_pkt->ar_sha;
	*(short*)(arp_pkt->ar_tha+4)=*(short*)(arp_pkt->ar_sha+4);
	arp_pkt->ar_tpa=(arp_pkt->ar_spa1<<16)|arp_pkt->ar_spa2;
	*(int*)arp_pkt->ar_sha=iface_table[meta_data->m_InputPort].eth_w0;
	*(short*)(arp_pkt->ar_sha+4)=
	                 iface_table[meta_data->m_InputPort].eth_w1>>16;
	arp_pkt->ar_spa1=iface_table[meta_data->m_InputPort].ip_addr>>16;
	arp_pkt->ar_spa2=
	            iface_table[meta_data->m_InputPort].ip_addr&0xFFFF;
	send_pkt((void*)arg_hBuffer, meta_data->m_InputPort,
	          eth_pkt, eth_pkt->e_src, ETH_ARP);
	if (verb == VERBOSE)
		printk("Sent ARP reply\n");
	/* Also add an entry into arp table */
	if ( !add_arp_entry(&ae) )
		printk("%s: ARP table full!", NAT_DRIVER_NAME);
}

/* Function to process an ARP reply */
void process_arp_rep(arp* arp_pkt,ix_hw_buffer_meta* meta_data)
{
	arp_entry ae;
	ae.ip_addr = (arp_pkt->ar_spa1<<16) | arp_pkt->ar_spa2;
	ae.eth_w0 = *(int*)arp_pkt->ar_sha;
	ae.eth_w1 = *(short*)(arp_pkt->ar_sha+4);
	ae.ifnum = meta_data->m_InputPort;
	ae.valid = 1;
	if ( !add_arp_entry(&ae) )
		printk("%s: ARP table full!", NAT_DRIVER_NAME);
}

/* Function to insert an entry into the ARP table.                     */
/* Note: because our code uses a simplified ARP table in which entries */
/* do not expire, there is no need to check for duplicate entries.     */
int add_arp_entry(arp_entry *ae)
{
	ix_hash_48 hash48v;
	int i,j;
	hash48v.m_LW0 = ae->ip_addr;
	hash48v.m_LW1 = 0;
	ix_rm_hash_48_hash(&hash48v);
	j = hash48v.m_LW0&ARP_TABLE_BIT_MASK;
	for (i=0;i<ARP_TABLE_SIZE;i++) {
		if (ae->ip_addr == arp_table[j].ip_addr &&
		    arp_table[j].valid )
			return(1);
		if ( !arp_table[j].valid ) {
			arp_table[j]=*ae;
			return(1);
		}
		j=(j+1)&ARP_TABLE_BIT_MASK;
	}
	return(0);
}

/* Function to insert an entry into the NAT table */
int add_nat_entry(nat_entry* ne)
{
	ix_hash_128 hash128v;
	unsigned char timer, del_timer;
	int i,j,del_cand;
	hash128v.m_LW0 = ne->ip_addr_rem;
	hash128v.m_LW1 = ne->ip_addr_loc;
	hash128v.m_LW2 = (ne->lport<<16)|ne->rport;
	hash128v.m_LW3 = ne->prot;
	ix_rm_hash_128_hash(&hash128v);
	j = (hash128v.m_LW0&NAT_TABLE_BIT_MASK)<<HASH_BUCKET_SHIFT;
	del_cand=j;
	for (i=0;i<HASH_BUCKET_SIZE;i++,j++) {
		if ( f_nat_table[j].valid &&
		     ne->ip_addr_loc == f_nat_table[j].ip_addr_loc &&
		     ne->ip_addr_rem == f_nat_table[j].ip_addr_rem &&
		     ne->lport == f_nat_table[j].lport &&
		     ne->rport == f_nat_table[j].rport &&
		     ne->prot ==  f_nat_table[j].prot ) {
			ne->nport=f_nat_table[j].nport;
			return(1);
		}
		if ( !f_nat_table[j].valid ) {
			if (set_new_nport(ne) < 0)
				return(-1);
			f_nat_table[j]=*ne;
			add_r_nat_entry(j);
			f_nat_table[j].valid=1;
			return(1);
		}
		/* No free slot was found; choose a candidate */
		/* for deletion                               */
		timer=f_timer[j]|r_timer[f_index[j]];
		del_timer = f_timer[del_cand]|r_timer[f_index[del_cand]];
		if ( timer < del_timer ||
		     ( timer == del_timer &&
		       f_nat_table[j].prot!=f_nat_table[del_cand].prot &&
		       ( f_nat_table[j].prot == IPT_ICMP ||
		         ( f_nat_table[j].prot == IPT_UDP &&
		           f_nat_table[del_cand].prot == IPT_TCP ))))
			del_cand=j;
	}
	del_nat_entry(del_cand);
	if (set_new_nport(ne) < 0)
		return(-1);
	f_nat_table[del_cand]=*ne;
	add_r_nat_entry(del_cand);
	f_nat_table[del_cand].valid=1;
	return(1);
}

/* Function to delete an entry from the NAT table */
void del_nat_entry(unsigned int entry_index)
{
	f_nat_table[entry_index].valid=0;
	f_timer[entry_index]=0;
	r_nat_table[f_index[entry_index]].valid=0;
	r_timer[f_index[entry_index]]=0;
}

/* Function to add an entry to the reverse NAT table */
void add_r_nat_entry(unsigned int entry_index)
{
	ix_hash_128 hash128v;
	int i, j, k, del_cand, r_del_cand;
	unsigned char timer, del_timer;
	nat_entry *ne=&f_nat_table[entry_index];
	hash128v.m_LW0 = ne->ip_addr_rem;
	hash128v.m_LW1 = (ne->nport<<16)|ne->rport;
	hash128v.m_LW2 = ne->prot;
	hash128v.m_LW3 = 0;
	ix_rm_hash_128_hash(&hash128v);
	j=(hash128v.m_LW0&NAT_TABLE_BIT_MASK)<<HASH_BUCKET_SHIFT;
	del_cand=r_index[j];
	r_del_cand=j;
	for (i=0;i<HASH_BUCKET_SIZE;i++,j++) {
		/* Check whether the slot is empty */
		if (!r_nat_table[j].valid) {
			/* we found an empty slot in reverse NAT table */
			r_nat_table[j]=f_nat_table[entry_index];
			f_index[entry_index]=j;
			r_index[j]=entry_index;
			r_nat_table[j].valid=1;
			return;
		}
		/* Find a canditate for deletion */
		k = r_index[j];
		timer = f_timer[k]|r_timer[j];
		del_timer=f_timer[del_cand]|r_timer[r_del_cand];
		if ( timer < del_timer ||
		     ( timer == del_timer &&
		       f_nat_table[k].prot!=f_nat_table[del_cand].prot &&
		        ( f_nat_table[k].prot == IPT_ICMP ||
		           ( f_nat_table[k].prot == IPT_UDP &&
		             f_nat_table[del_cand].prot == IPT_TCP )))) {
			del_cand=k;
			r_del_cand=j;
		}
	}
	/* This point is reached if no slot is empty */
	del_nat_entry(del_cand);
	r_nat_table[r_del_cand]=f_nat_table[entry_index];
	r_index[r_del_cand] = entry_index;
	f_index[entry_index] = r_del_cand;
	r_nat_table[r_del_cand].valid=1;
}

/* Function to calculate a value for a new NAT port */
int set_new_nport(nat_entry* ne)
{
	ix_hash_128 hash128v;
	int i,j,k;

	ne->nport=++global_nport;
	/* Try at most NEW_NPORT_ATTEMPS values, and then give up */
	for (i=0;i<NEW_NPORT_ATTEMPS;i++) {
		hash128v.m_LW0 = ne->ip_addr_rem;
		hash128v.m_LW1 = (ne->nport<<16)|ne->rport;
		hash128v.m_LW2 = ne->prot;
		hash128v.m_LW3 = 0;
		ix_rm_hash_128_hash(&hash128v);
		j=(hash128v.m_LW0&NAT_TABLE_BIT_MASK)<<HASH_BUCKET_SHIFT;
		for (k=0;k<HASH_BUCKET_SIZE;k++,j++) {
		    if ( r_nat_table[j].valid &&
		         r_nat_table[j].ip_addr_rem == ne->ip_addr_rem &&
		         r_nat_table[j].rport == ne->rport &&
		         r_nat_table[j].nport == ne->nport &&
		         r_nat_table[j].prot == ne->prot )
		      break;
		}
		if (k==HASH_BUCKET_SIZE)
			/* An unused NAT port value has been found */
			return(ne->nport);
		/* Try the next NAT port value */
		ne->nport=++global_nport;
	}
	return(-1);
}

/* Function to send echo response */
void send_icmp_echo_rep(ip* ip_pkt,icmp* icmp_pkt,
	ix_hw_buffer_meta* meta_data,ix_buffer_handle arg_hBuffer,
	eth *eth_pkt)
{
	unsigned int cksum;
	icmp_pkt->icmp_type = ICMP_ECHO_REP;
	cksum = icmp_pkt->icmp_cksum+(ICMP_ECHO_REQ<<8)
	      + ((~(ICMP_ECHO_REP<<8))&0xFFFF);
	cksum = (cksum&0xFFFF)+(cksum>>16);
	cksum = (cksum&0xFFFF)+(cksum>>16);
	icmp_pkt->icmp_cksum = cksum&0xFFFF;
	ip_pkt->ip_dst = ip_pkt->ip_src;
	ip_pkt->ip_src = iface_table[meta_data->m_InputPort].ip_addr;
	send_pkt((void*)arg_hBuffer,meta_data->m_InputPort, eth_pkt,
	         eth_pkt->e_src, ETH_IP);
}

/* Function to translate ICMP packet */
int process_icmp(icmp* icmp_pkt,nat_entry* ne)
{
	unsigned int cksum;
	/* If this is not an echo request -- drop the packet */
	if (icmp_pkt->icmp_type != ICMP_ECHO_REQ)
		return(-1);
	/* For ICMP echo request we do ID field translation */
	ne->lport=icmp_pkt->icmp_id;
	ne->rport=0;
	if (add_nat_entry(ne) < 0)
		return(-1);
	icmp_pkt->icmp_id=ne->nport;
	/* Update ICMP checksum */
	cksum= icmp_pkt->icmp_cksum+ne->lport
	     + ((~icmp_pkt->icmp_id)&0xFFFF);
	cksum=(cksum&0xFFFF)+(cksum>>16);
	cksum=(cksum&0xFFFF)+(cksum>>16);
	icmp_pkt->icmp_cksum = cksum&0xFFFF;
	return(1);
}

/* Function to translate TCP packet */
int process_tcp(tcp* tcp_pkt,nat_entry* ne)
{
	unsigned int cksum;
	if (verb == VERBOSE) {
		printk("\tTCP source port = %i\n", tcp_pkt->tcp_sport);
		printk("\tTCP dest.  port = %i\n", tcp_pkt->tcp_dport);
	}
	/* Perform TCP source port translation */
	ne->lport=tcp_pkt->tcp_sport;
	ne->rport=tcp_pkt->tcp_dport;
	if (add_nat_entry(ne) < 0)
		return(-1);
	tcp_pkt->tcp_sport=ne->nport;
	/* Update the TCP checksum */
	cksum = tcp_pkt->tcp_cksum+ne->lport+(ne->ip_addr_loc>>16)
	      + (ne->ip_addr_loc&0xFFFF)+((~tcp_pkt->tcp_sport)&0xFFFF)
	      + ((~iface_table[NAT_IFC].ip_addr)>>16)
	      + ((~iface_table[NAT_IFC].ip_addr)&0xFFFF);
	cksum=(cksum&0xFFFF)+(cksum>>16);
	cksum=(cksum&0xFFFF)+(cksum>>16);
	tcp_pkt->tcp_cksum = cksum&0xFFFF;
	return(1);
}

/* Function to translate UDP packet */
int process_udp(udp* udp_pkt,nat_entry* ne)
{
	unsigned int cksum;
	if (verb == VERBOSE) {
		printk("\tUDP source port = %i\n", udp_pkt->udp_sport);
		printk("\tUDP dest.  port = %i\n", udp_pkt->udp_dport);
	}
	/* Perform UDP source port translation */
	ne->lport=udp_pkt->udp_sport;
	ne->rport=udp_pkt->udp_dport;
	if (add_nat_entry(ne) < 0)
		return(-1);
	udp_pkt->udp_sport=ne->nport;
	/* Update the UDP checksum */
	if (udp_pkt->udp_cksum) {
		cksum = udp_pkt->udp_cksum+ne->lport+(ne->ip_addr_loc>>16)
		      + (ne->ip_addr_loc&0xFFFF)
		      + ((~udp_pkt->udp_sport)&0xFFFF)
		      + ((~iface_table[NAT_IFC].ip_addr)>>16)
		      + ((~iface_table[NAT_IFC].ip_addr)&0xFFFF);
		cksum=(cksum&0xFFFF)+(cksum>>16);
		cksum=(cksum&0xFFFF)+(cksum>>16);
		udp_pkt->udp_cksum = cksum&0xFFFF;
	}
	return(1);
}
