summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/files/drivers/net/rtl819x/l4Driver
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/realtek/files/drivers/net/rtl819x/l4Driver')
-rw-r--r--target/linux/realtek/files/drivers/net/rtl819x/l4Driver/Makefile39
-rw-r--r--target/linux/realtek/files/drivers/net/rtl819x/l4Driver/rtl865x_nat.c1880
-rw-r--r--target/linux/realtek/files/drivers/net/rtl819x/l4Driver/rtl865x_nat_local.h59
3 files changed, 1978 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/l4Driver/Makefile b/target/linux/realtek/files/drivers/net/rtl819x/l4Driver/Makefile
new file mode 100644
index 000000000..0478306df
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/rtl819x/l4Driver/Makefile
@@ -0,0 +1,39 @@
+#
+# Makefile for the Tulip ethernet driver
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+#Add mips16 Support
+
+DIR_RTLASIC = $(TOPDIR)/drivers/net/rtl819x/
+ifdef CONFIG_RTL865X_KERNEL_MIPS16_LAYERDRIVER
+ CFLAGS_rtl865x_nat.o = -mips16
+endif
+ ifdef CONFIG_RTL_LAYERED_DRIVER_L4
+ obj-y := rtl865x_nat.o
+ endif
+
+EXTRA_CFLAGS += -O1 -DRTL_TBLDRV -D__linux__ -mno-memcpy -DRTL865X_OVER_KERNEL -DRTL865X_OVER_LINUX -Werror
+#EXTRA_CFLAGS += -I$(DIR_RTLASIC)/common
+#EXTRA_CFLAGS += -I$(DIR_RTLASIC)/AsicDriver
+#EXTRA_CFLAGS += -I$(DIR_RTLASIC)/l2Driver
+#EXTRA_CFLAGS += -I$(DIR_RTLASIC)/l3Driver
+EXTRA_CFLAGS += -I$(DIR_RTLASIC)
+
+
+
+ifeq ($(CONFIG_RTL865X_MODULE_ROMEDRV),y)
+ EXTRA_CFLAGS += -D__KERNEL__
+ EXTRA_CFLAGS += -G 0
+ EXTRA_CFLAGS += -DMODULE
+ EXTRA_CFLAGS += -mlong-calls
+ EXTRA_CFLAGS += -DEXPORT_SYMTAB
+ EXTRA_CFLAGS += -DCONFIG_RTL865X_MODULE_INTERNAL
+# EXTRA_CFLAGS += -DMODVERSIONS
+# EXTRA_CFLAGS += -include $(DIR_LINUX)/include/linux/modversions.h
+endif
+
+EXTRA_AFLAGS += $(EXTRA_CFLAGS)
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/l4Driver/rtl865x_nat.c b/target/linux/realtek/files/drivers/net/rtl819x/l4Driver/rtl865x_nat.c
new file mode 100644
index 000000000..9ca1c2678
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/rtl819x/l4Driver/rtl865x_nat.c
@@ -0,0 +1,1880 @@
+/*
+* Copyright c Realtek Semiconductor Corporation, 2008
+* All rights reserved.
+*
+* Program : napt table driver
+* Abstract :
+* Author : hyking (hyking_liu@realsil.com.cn)
+*/
+
+/* @doc RTL_LAYEREDDRV_API
+
+ @module rtl865x_nat.c - RTL865x Home gateway controller Layered driver API documentation |
+ This document explains the API interface of the table driver module. Functions with rtl865x prefix
+ are external functions.
+ @normal Hyking Liu (Hyking_liu@realsil.com.cn) <date>
+
+ Copyright <cp>2008 Realtek<tm> Semiconductor Cooperation, All Rights Reserved.
+
+ @head3 List of Symbols |
+ Here is a list of all functions and variables in this module.
+
+ @index | RTL_LAYEREDDRV_API
+*/
+
+#include <net/rtl/rtl_types.h>
+#include <net/rtl/rtl_glue.h>
+#include <net/rtl/rtl865x_netif.h>
+#include "common/mbuf.h"
+//#include "assert.h"
+
+//#include "rtl865xc_swNic.h"
+//#include <common/types.h>
+#include "AsicDriver/rtl865x_hwPatch.h" /* define for chip related spec */
+#ifdef CONFIG_RTL_LAYERED_ASIC_DRIVER
+
+#include "AsicDriver/rtl865x_asicL4.h"
+#else
+#include "common/rtl8651_aclLocal.h"
+#include "rtl865xC_tblAsicDrv.h"
+#endif
+
+#include "common/rtl_errno.h"
+//#include <net/rtl/rtl_queue.h>
+#include "AsicDriver/rtl865xc_asicregs.h"
+#include "common/rtl865x_eventMgr.h"
+#include "l3Driver/rtl865x_ip.h"
+
+#include <net/rtl/rtl865x_nat.h>
+#include "rtl865x_nat_local.h"
+
+//#include "rtl865x_ppp.h"
+#include "common/rtl865x_netif_local.h"
+#include "l3Driver/rtl865x_ppp_local.h"
+//#include "l3Driver/rtl865x_route.h"
+#include <net/rtl/rtl865x_outputQueue.h>
+#if defined(CONFIG_RTL_HW_QOS_SUPPORT)
+#include <net/rtl/rtl865x_arp_api.h>
+#include "l3Driver/rtl865x_route.h"
+#endif
+
+#ifdef CONFIG_RTL_PROC_DEBUG
+#include <linux/seq_file.h>
+#endif
+
+#include <linux/jiffies.h>
+
+
+static struct nat_table nat_tbl;
+static int32 rtl865x_enableNaptFourWay=FALSE;
+//static int32 _rtl865x_naptIdleCheck(int32 index);
+#if 0
+static int32 rtl865x_nat_callbackFn_for_del_ip(void *param);
+
+static int32 rtl865x_nat_register_event(void);
+
+static int32 rtl865x_nat_callbackFn_for_del_ip(void *param)
+{
+ int i;
+ rtl865x_tblAsicDrv_extIntIpParam_t *natip;
+ struct nat_entry *nat_out, *nat_in;
+ struct nat_tuple nat_tuple;
+ natip=(rtl865x_tblAsicDrv_extIntIpParam_t *)param;
+
+ for(i=0; i<RTL8651_TCPUDPTBL_SIZE; i++)
+ {
+ if((nat_tbl.nat_bucket[i].flags & NAT_OUTBOUND) && (nat_tbl.nat_bucket[i].ext_ip_==natip->extIpAddr))
+ {
+ memcpy(&nat_tuple, &nat_tbl.nat_bucket[i].tuple_info, sizeof(struct nat_tuple));
+ nat_out = &nat_tbl.nat_bucket[i];
+ nat_in = &nat_tbl.nat_bucket[nat_out->in];
+ rtl8651_delAsicNaptTcpUdpTable(nat_out->in, nat_out->in);
+ rtl8651_delAsicNaptTcpUdpTable(nat_out->out, nat_out->out);
+ memset(nat_in, 0, sizeof(*nat_in));
+ memset(nat_out, 0, sizeof(*nat_out));
+
+ if(nat_tbl.connNum > 0)
+ {
+ nat_tbl.connNum--;
+ }
+ }
+
+ }
+ return EVENT_CONTINUE_EXECUTE;
+}
+
+static int32 _rtl865x_nat_unRegister_event(void)
+{
+ rtl865x_event_Param_t eventParam;
+
+ eventParam.eventLayerId=DEFAULT_LAYER3_EVENT_LIST_ID;
+ eventParam.eventId=EVENT_DEL_IP;
+ eventParam.eventPriority=0;
+ eventParam.event_action_fn=rtl865x_nat_callbackFn_for_del_ip;
+ rtl865x_unRegisterEvent(&eventParam);
+
+ return SUCCESS;
+}
+
+static int32 _rtl865x_nat_register_event(void)
+{
+ rtl865x_event_Param_t eventParam;
+
+ eventParam.eventLayerId=DEFAULT_LAYER3_EVENT_LIST_ID;
+ eventParam.eventId=EVENT_DEL_IP;
+ eventParam.eventPriority=0;
+ eventParam.event_action_fn=rtl865x_nat_callbackFn_for_del_ip;
+ rtl865x_registerEvent(&eventParam);
+
+ return SUCCESS;
+}
+#endif
+
+#define RTL_NAT_AVG_INTERVAL 3
+#define RTL_NAT_MIN_INTERVAL 1
+
+int32 rtl_nat_expire_interval_update(int proto, int32 interval)
+{
+ int32 asic_interval;
+
+ asic_interval = interval>RTL_NAT_AVG_INTERVAL?interval-RTL_NAT_AVG_INTERVAL:interval-RTL_NAT_MIN_INTERVAL;
+ asic_interval = asic_interval<RTL_NAT_MIN_INTERVAL?RTL_NAT_MIN_INTERVAL:asic_interval;
+
+ if (proto==RTL865X_PROTOCOL_UDP) {
+ nat_tbl.tcp_timeout = asic_interval;
+ }else if (proto==RTL865X_PROTOCOL_UDP) {
+ nat_tbl.udp_timeout = asic_interval;
+ } else {
+ return FAILED;
+ }
+
+ /* Set ASIC timeout value */
+ rtl8651_setAsicNaptTcpLongTimeout(nat_tbl.tcp_timeout);
+ rtl8651_setAsicNaptTcpMediumTimeout(nat_tbl.tcp_timeout);
+ rtl8651_setAsicNaptTcpFastTimeout(nat_tbl.tcp_timeout);
+ rtl8651_setAsicNaptUdpTimeout(nat_tbl.udp_timeout);
+
+ return SUCCESS;
+}
+
+static int32 _rtl865x_nat_init(void)
+{
+ rtl865x_tblAsicDrv_naptTcpUdpParam_t naptTcpUdp;
+ uint32 flowTblIdx;
+
+ memset(nat_tbl.nat_bucket, 0,
+ sizeof(struct nat_entry)*RTL8651_TCPUDPTBL_SIZE);
+
+ nat_tbl.connNum = 0;
+ nat_tbl.tcp_timeout = TCP_TIMEOUT; //24*60*60;
+ nat_tbl.udp_timeout = UDP_TIMEOUT; //60*15;
+ nat_tbl.freeEntryNum=RTL8651_TCPUDPTBL_SIZE;
+
+ /* Set ASIC timeout value */
+ rtl8651_setAsicNaptTcpLongTimeout(TCP_TIMEOUT);
+ rtl8651_setAsicNaptTcpMediumTimeout(TCP_TIMEOUT);
+ rtl8651_setAsicNaptTcpFastTimeout(TCP_TIMEOUT);
+ rtl8651_setAsicNaptUdpTimeout(UDP_TIMEOUT);
+
+ /*enable 865xC enhanced hash1*/
+ _rtl8651_enableEnhancedHash1();
+
+ /* Initial ASIC NAT Table */
+ memset( &naptTcpUdp, 0, sizeof(naptTcpUdp) );
+ naptTcpUdp.isCollision = 1;
+ naptTcpUdp.isCollision2 = 1;
+ for(flowTblIdx=0; flowTblIdx<RTL8651_TCPUDPTBL_SIZE; flowTblIdx++)
+ rtl8651_setAsicNaptTcpUdpTable(TRUE, flowTblIdx, &naptTcpUdp );
+
+ //rtl865x_nat_register_event();
+
+ return SUCCESS;
+}
+
+
+
+static struct nat_entry * _rtl865x_nat_outbound_lookup(struct nat_tuple *nat_tuple)
+{
+ struct nat_entry *nat_out;
+ uint32 i,hash;
+
+ hash = rtl8651_naptTcpUdpTableIndex((uint8)nat_tuple->proto, nat_tuple->int_host.ip, nat_tuple->int_host.port,
+ nat_tuple->rem_host.ip, nat_tuple->rem_host.port);
+ if(rtl865x_enableNaptFourWay==TRUE)
+ {
+ for(i=0; i<4; i++)
+ {
+ nat_out = &nat_tbl.nat_bucket[hash];
+ if (!memcmp(nat_out, nat_tuple, sizeof(*nat_tuple)) &&
+ (nat_out->flags&NAT_OUTBOUND))
+ {
+ return nat_out;
+ }
+ hash=(hash&0xFFFFFFFC)+(hash+1)%4;
+ assert(hash<=RTL8651_TCPUDPTBL_SIZE);
+ }
+ }
+ else
+ {
+ nat_out = &nat_tbl.nat_bucket[hash];
+ if (!memcmp(nat_out, nat_tuple, sizeof(*nat_tuple)) &&
+ (nat_out->flags&NAT_OUTBOUND))
+ return nat_out;
+ }
+ return (struct nat_entry *)0;
+}
+
+static struct nat_entry * _rtl865x_nat_inbound_lookup(struct nat_tuple *nat_tuple)
+{
+ struct nat_entry *nat_in;
+ uint32 hash;
+
+ hash = rtl8651_naptTcpUdpTableIndex((uint8)nat_tuple->proto, nat_tuple->rem_host.ip, nat_tuple->rem_host.port,
+ nat_tuple->ext_host.ip, nat_tuple->ext_host.port);
+
+
+ nat_in = &nat_tbl.nat_bucket[hash];
+ if (!memcmp(nat_in, nat_tuple, sizeof(*nat_tuple)) &&
+ (nat_in->flags&NAT_INBOUND))
+ {
+ return nat_in;
+ }
+
+ return (struct nat_entry *)0;
+}
+
+#if defined (CONFIG_RTL_INBOUND_COLLISION_AVOIDANCE)
+static int _rtl865x_isEntryPreReserved(uint32 index)
+{
+ struct nat_entry *natEntry;
+ if(index>=RTL8651_TCPUDPTBL_SIZE)
+ {
+ return FALSE;
+ }
+
+ natEntry= &nat_tbl.nat_bucket[index];
+
+ if((natEntry->flags & NAT_PRE_RESERVED))
+ {
+ if(jiffies>=natEntry->reserveTime)
+ {
+ if(jiffies>(natEntry->reserveTime+RESERVE_EXPIRE_TIME*HZ))
+ {
+ /*pre-reserve become invalid now*/
+ natEntry->flags &= (~(NAT_PRE_RESERVED));
+ natEntry->reserveTime=0;
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+ else
+ {
+ /*timer overflow*/
+ if(((0xFFFFFFFF-natEntry->reserveTime)+jiffies+1)>(RESERVE_EXPIRE_TIME*HZ))
+ {
+ natEntry->flags &= (~(NAT_PRE_RESERVED));
+ natEntry->reserveTime=0;
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int _rtl865x_PreReserveEntry(uint32 index)
+{
+ struct nat_entry *natEntry;
+ if(index>=RTL8651_TCPUDPTBL_SIZE)
+ {
+ return FAILED;
+ }
+ natEntry= &nat_tbl.nat_bucket[index];
+
+ if(NAT_INUSE(natEntry))
+ {
+ /*already used by other napt connection, can not reserve it*/
+ natEntry->flags &= (~(NAT_PRE_RESERVED));
+ natEntry->reserveTime=0;
+ }
+ else
+ {
+ natEntry->flags|=NAT_PRE_RESERVED;
+ natEntry->reserveTime=jiffies;
+ }
+ return SUCCESS;
+}
+
+static int _rtl865x_getNaptHashInfo( rtl865x_napt_entry *naptEntry,
+ rtl865x_naptHashInfo_t *naptHashInfo)
+{
+
+ uint32 in, out;
+ uint32 i,index;
+ struct nat_entry *nat_in, *nat_out;
+ struct nat_entry *natEntry;
+
+ if(naptHashInfo==NULL)
+ {
+ return FAILED;
+ }
+
+ memset(naptHashInfo, 0, sizeof(rtl865x_naptHashInfo_t));
+
+ in = rtl8651_naptTcpUdpTableIndex((uint8)(naptEntry->protocol), naptEntry->remIp, naptEntry->remPort, naptEntry->extIp, naptEntry->extPort);
+ out = rtl8651_naptTcpUdpTableIndex((uint8)(naptEntry->protocol), naptEntry->intIp, naptEntry->intPort, naptEntry->remIp, naptEntry->remPort);
+
+ if(rtl865x_enableNaptFourWay==TRUE)
+ {
+ uint32 outAvailIdx=0xFFFFFFFF;
+ index=out;
+ for(i=0;i<4;i++)
+ {
+ natEntry = &nat_tbl.nat_bucket[index];
+ if (NAT_INUSE(natEntry) || _rtl865x_isEntryPreReserved(index))
+ {
+
+ }
+ else
+ {
+ if(index==in)
+ {
+ /*collide with inbound*/
+ }
+ else
+ {
+ out=index;
+ break;
+ }
+ }
+ index=(index&0xFFFFFFFC)+(index+1)%4;
+ assert(index<=RTL8651_TCPUDPTBL_SIZE);
+
+ }
+
+ if(i>=4)
+ {
+ /*only one empty entry, but collide with its own inbound*/
+ if(outAvailIdx!=0xFFFFFFFF)
+ {
+ out=outAvailIdx;
+ }
+ }
+ else
+ {
+ /*proper empty entry has been found*/
+ }
+ }
+
+ naptHashInfo->outIndex=out;
+ naptHashInfo->inIndex=in;
+
+ if((in&0xFFFFFFFC)==(out&0xFFFFFFFC))
+ {
+ naptHashInfo->sameFourWay=1;
+ }
+
+ if(in==out)
+ {
+ naptHashInfo->sameLocation=1;
+
+ nat_out = &nat_tbl.nat_bucket[out];
+ if(NAT_INUSE(nat_out)|| _rtl865x_isEntryPreReserved(out))
+ {
+ naptHashInfo->outCollision=1;
+ }
+
+ naptHashInfo->inCollision=1;
+ }
+ else
+ {
+ nat_out = &nat_tbl.nat_bucket[out];
+ nat_in = &nat_tbl.nat_bucket[in];
+
+ if(NAT_INUSE(nat_out) || _rtl865x_isEntryPreReserved(out))
+ {
+ naptHashInfo->outCollision=1;
+ }
+
+ if (NAT_INUSE(nat_in) || _rtl865x_isEntryPreReserved(in))
+ {
+ naptHashInfo->inCollision=1;
+ }
+ }
+
+
+ index=in;
+ naptHashInfo->inFreeCnt=0;
+ for(i=0;i<4;i++)
+ {
+ natEntry = &nat_tbl.nat_bucket[index];
+ if (NAT_INUSE(natEntry) || _rtl865x_isEntryPreReserved(index))
+ {
+
+ }
+ else
+ {
+ naptHashInfo->inFreeCnt++;
+ }
+ index=(index&0xFFFFFFFC)+(index+1)%4;
+ assert(index<=RTL8651_TCPUDPTBL_SIZE);
+ }
+ #if 0
+ printk("%s:%d:%s (%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u) ,out is %d,in is %d\n",
+ __FUNCTION__,__LINE__,protocol?"tcp":"udp",
+ NIPQUAD(intIp), intPort, NIPQUAD(extIp), extPort, NIPQUAD(remIp), remPort, out, in);
+ #endif
+ return SUCCESS;
+}
+
+int rtl865x_optimizeExtPort(unsigned short origDelta, unsigned int rangeSize, unsigned short *newDelta)
+{
+ int i;
+ int msb;
+ unsigned int bitShift;
+
+ msb=0;
+ for(i=0;i<16;i++)
+ {
+ if((1<<i) & rangeSize)
+ {
+ msb=i;
+ }
+ }
+
+ if(((1<<msb)+1)>rangeSize)
+ {
+ if(msb>1)
+ {
+ msb--;
+ }
+ }
+
+ *newDelta=0;
+ if(msb<10)
+ {
+ bitShift=0x01;
+ for(i=0;i<=msb;i++)
+ {
+ if(i==0)/*bit0 keep the same*/
+ {
+ if(origDelta&bitShift)
+ {
+ *newDelta|=bitShift;
+ }
+ }
+ else /*original bit1~ bit_maxPower mapped to bit_maxPower~bit1*/
+ {
+ if(origDelta&bitShift)
+ {
+ *newDelta |=(0x1<<(msb+1-i));
+ }
+ }
+
+ bitShift=bitShift<<1;
+ }
+ }
+ else
+ {
+ bitShift=0x01;
+
+ for(i=0;i<=msb;i++)
+ {
+ if(i==0) /*bit0 keep the same*/
+ {
+ if(origDelta&bitShift)
+ {
+ *newDelta |=bitShift;
+ }
+ }
+ else if (i<10) /*bit1~ bit9 mapped to bit 9~bit1*/
+ {
+ if(origDelta&bitShift)
+ {
+ *newDelta |=(0x1<<(10-i));
+ }
+ }
+ else/*other bits keep the same*/
+ {
+ if(origDelta&bitShift)
+ {
+ *newDelta |=bitShift;
+ }
+ }
+
+ bitShift=bitShift<<1;
+ }
+
+
+ }
+ return SUCCESS;
+}
+
+int rtl865x_getAsicNaptHashScore(rtl865x_napt_entry *naptEntry,
+ uint32 *naptHashScore)
+{
+ rtl865x_naptHashInfo_t naptHashInfo;
+ _rtl865x_getNaptHashInfo(naptEntry, &naptHashInfo);
+
+ /*initialize napt hash score*/
+ *naptHashScore=100;
+
+ /*note:we can not change outbound index*/
+
+ if(naptHashInfo.inCollision==FALSE)
+ {
+ if(naptHashInfo.inFreeCnt==4)
+ {
+ if(!naptHashInfo.sameFourWay)
+ {
+ *naptHashScore=100;
+ }
+ else
+ {
+ if(!naptHashInfo.sameLocation)
+ {
+ *naptHashScore=80;
+ }
+ else
+ {
+ *naptHashScore=0;
+ }
+ }
+ }
+ else if (naptHashInfo.inFreeCnt==3)
+ {
+ if(!naptHashInfo.sameFourWay)
+ {
+ *naptHashScore=80;
+ }
+ else
+ {
+ if(!naptHashInfo.sameLocation)
+ {
+ *naptHashScore=70;
+ }
+ else
+ {
+ *naptHashScore=0;
+ }
+ }
+ }
+ else if (naptHashInfo.inFreeCnt==2)
+ {
+ if(!naptHashInfo.sameFourWay)
+ {
+ *naptHashScore=70;
+ }
+ else
+ {
+ if(!naptHashInfo.sameLocation==FALSE)
+ {
+ *naptHashScore=60;
+ }
+ else
+ {
+ *naptHashScore=0;
+ }
+ }
+ }
+ else if (naptHashInfo.inFreeCnt==1)
+ {
+ if(naptHashInfo.sameFourWay==FALSE)
+ {
+ *naptHashScore=60;
+ }
+ else
+ {
+ *naptHashScore=0;
+
+ }
+ }
+ else
+ {
+ *naptHashScore=0;
+ }
+
+
+ }
+ else
+ {
+ /*worst case:inbound is collision*/
+ *naptHashScore=0;
+ }
+
+ return SUCCESS;
+
+}
+
+int32 rtl865x_preReserveConn(rtl865x_napt_entry *naptEntry)
+{
+
+ rtl865x_naptHashInfo_t naptHashInfo;
+ _rtl865x_getNaptHashInfo(naptEntry, &naptHashInfo);
+
+ if(naptHashInfo.outCollision==FALSE)
+ {
+ _rtl865x_PreReserveEntry(naptHashInfo.outIndex);
+ }
+
+ if(naptHashInfo.inCollision==FALSE)
+ {
+ _rtl865x_PreReserveEntry(naptHashInfo.inIndex);
+ }
+
+ return SUCCESS;
+}
+
+#endif
+
+static int32 _rtl865x_addNaptConnection(rtl865x_napt_entry *naptEntry, rtl865x_priority *prio)
+{
+ int32 retval;
+ rtl865x_tblAsicDrv_naptTcpUdpParam_t asic_nat;
+ struct nat_entry *nat_in, *nat_out;
+ struct nat_tuple nat_tuple;
+ uint32 in, out, offset, ipidx, i;
+ uint16 very,selEidx_out;
+#if defined(CONFIG_RTL_HW_QOS_SUPPORT)
+ #if defined(CONFIG_RTL_IPTABLES_RULE_2_ACL)
+ rtl865x_route_t rt;
+ rtl865x_arpMapping_entry_t arpInfo;
+ ipaddr_t sip, dip;
+ uint16 sport, dport;
+ rtl865x_AclRule_t rule4[2], rule2[2];
+ int32 defPriority[2];
+ int32 upDown[2], defUpDown[2];//0: uplink; 1: downlink
+ #endif
+ int32 priority[2];
+#endif
+ //int32 elasped, del_conn_flags;
+
+ uint32 outCollision=FALSE;
+ uint32 inCollision=FALSE;
+
+ /* Make sure natip */
+ retval = rtl865x_getIpIdxByExtIp(naptEntry->extIp, &ipidx);
+ if(retval != SUCCESS)
+ return RTL_EINVALIDINPUT;
+
+ memset(&nat_tuple, 0, sizeof(struct nat_tuple));
+ nat_tuple.int_host.ip = naptEntry->intIp;
+ nat_tuple.int_host.port = naptEntry->intPort;
+ nat_tuple.ext_host.ip = naptEntry->extIp;
+ nat_tuple.ext_host.port = naptEntry->extPort;
+ nat_tuple.rem_host.ip = naptEntry->remIp;
+ nat_tuple.rem_host.port = naptEntry->remPort;
+ nat_tuple.proto = naptEntry->protocol;
+
+ nat_out = _rtl865x_nat_outbound_lookup(&nat_tuple);
+ if (nat_out)
+ {
+ return RTL_EENTRYALREADYEXIST;
+ }
+
+ nat_in = _rtl865x_nat_inbound_lookup(&nat_tuple);
+ if(nat_in)
+ {
+ return RTL_EENTRYALREADYEXIST;
+ }
+
+ offset = (naptEntry->extPort&0x0000ffff)>>10;
+ very = rtl8651_naptTcpUdpTableIndex(((uint8)naptEntry->protocol) |HASH_FOR_VERI , naptEntry->remIp, naptEntry->remPort, 0, 0);
+
+ selEidx_out = naptEntry->extPort&0x3ff;
+ in = rtl8651_naptTcpUdpTableIndex((uint8)naptEntry->protocol, naptEntry->remIp, naptEntry->remPort, naptEntry->extIp, naptEntry->extPort);
+ out = rtl8651_naptTcpUdpTableIndex((uint8)naptEntry->protocol, naptEntry->intIp, naptEntry->intPort, naptEntry->remIp, naptEntry->remPort);
+ /*support outbound 4-way*/
+ if(rtl865x_enableNaptFourWay==TRUE)
+ {
+
+ uint32 hash=out;
+ uint32 outAvailIdx=0xFFFFFFFF;
+
+ for(i=0;i<4;i++)
+ {
+ nat_out = &nat_tbl.nat_bucket[hash];
+ if (NAT_INUSE(nat_out))
+ {
+ /* collision with outbound */
+ }
+ else
+ {
+ outAvailIdx=hash;
+ if(hash==in)
+ {
+ /*collision with inbound*/
+ }
+ else
+ {
+ out=hash;
+ break;
+ }
+ }
+ hash=(hash&0xFFFFFFFC)+(hash+1)%4;
+ assert(hash<=RTL8651_TCPUDPTBL_SIZE);
+
+ }
+
+
+ if(i>=4)
+ {
+ /*only one empty entry,but collide with its own inbound*/
+ if(outAvailIdx!=0xFFFFFFFF)
+ {
+ out=outAvailIdx;
+ }
+ }
+ }
+
+
+ nat_out = &nat_tbl.nat_bucket[out];
+ nat_in = &nat_tbl.nat_bucket[in];
+ #if 0
+ del_conn_flags = 0;
+ if (NAT_INUSE(nat_out))
+ {
+ elasped = _rtl865x_naptIdleCheck(out);
+ if ( ((nat_out->tuple_info.proto==RTL865X_PROTOCOL_UDP)&&(elasped>UDP_OVERRIDE_ELASPED_THRESHOLD))
+ || ((nat_out->tuple_info.proto==RTL865X_PROTOCOL_TCP)&&(elasped>TCP_OVERRIDE_ELASPED_THRESHOLD)))
+ {
+ NAT_INVALID(nat_out); /* invalide */
+ nat_tbl.freeEntryNum++;
+ del_conn_flags++;
+ }
+ }
+
+ if (NAT_INUSE(nat_in))
+ {
+ elasped = _rtl865x_naptIdleCheck(in);
+ if ( ((nat_out->tuple_info.proto==RTL865X_PROTOCOL_UDP)&&(elasped>UDP_OVERRIDE_ELASPED_THRESHOLD))
+ || ((nat_out->tuple_info.proto==RTL865X_PROTOCOL_TCP)&&(elasped>TCP_OVERRIDE_ELASPED_THRESHOLD)))
+ {
+ NAT_INVALID(nat_in); /* invalide */
+ nat_tbl.freeEntryNum++;
+ del_conn_flags++;
+ }
+ }
+
+ if (del_conn_flags==2) {
+ nat_tbl.connNum--;
+ }
+ #endif
+ if ( NAT_INUSE(nat_out) && NAT_INUSE(nat_in))
+ {
+ /*both outbound and inbound has been occupied*/
+ return RTL_EINVALIDINPUT;
+ }
+
+ if(out==in)
+ {
+ outCollision=FALSE;
+ inCollision=TRUE;
+ /*we don't support this case at present, otherwise, when delete napt connection must be very very careful*/
+ //return RTL_EENTRYALREADYEXIST;
+ }
+ else
+ {
+ if (NAT_INUSE(nat_out))
+ {
+ outCollision=TRUE;
+ }
+
+ if(NAT_INUSE(nat_in))
+ {
+ inCollision=TRUE;
+ }
+ }
+#ifdef CONFIG_HARDWARE_NAT_DEBUG
+ rtlglue_printf("LR(%s): %s (%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u) g:(%u.%u.%u.%u:%u)\n",
+ ("add_nat"), ((naptEntry->protocol)? "tcp": "udp"),
+ NIPQUAD(naptEntry->intIp), naptEntry->intPort, NIPQUAD(naptEntry->remIp), naptEntry->remPort, NIPQUAD(naptEntry->extIp), naptEntry->extPort);
+#endif
+
+#if defined (CONFIG_RTL_HALF_NAPT_ACCELERATION)
+
+#else
+ if((outCollision==TRUE) || (inCollision==TRUE))
+ {
+ /*we must make sure both direction can be written into asic*/
+ return RTL_EINVALIDINPUT;
+ }
+#endif
+
+ if ( outCollision==FALSE)
+ {
+ memset(nat_out, 0, sizeof(struct nat_entry));
+ *((struct nat_tuple *)nat_out)=nat_tuple;
+ nat_out->out=out;
+ if( inCollision==FALSE)
+ {
+ nat_out->in=in;
+ }
+ else
+ {
+ nat_out->in=0xFFFFFFFF;
+ }
+
+ nat_out->natip_idx =ipidx;
+ SET_NAT_FLAGS(nat_out, NAT_OUTBOUND);
+ }
+ else
+ {
+ nat_out=NULL;
+ }
+
+ if( inCollision==FALSE)
+ {
+ memset(nat_in, 0, sizeof(struct nat_entry));
+ *((struct nat_tuple *)nat_in) = nat_tuple;
+ nat_in->in = in;
+ if ( outCollision==FALSE)
+ {
+ nat_in->out = out;
+ }
+ else
+ {
+ nat_in->out=0xFFFFFFFF;
+ }
+ nat_in->natip_idx = ipidx;
+ SET_NAT_FLAGS(nat_in, NAT_INBOUND);
+ }
+ else
+ {
+ nat_in=NULL;
+ }
+
+#if defined(CONFIG_RTL_HW_QOS_SUPPORT)
+#if defined(CONFIG_RTL_IPTABLES_RULE_2_ACL)
+ sip = naptEntry->intIp;
+ dip = naptEntry->remIp;
+ sport = naptEntry->intPort;
+ dport = naptEntry->remPort;
+
+ //Initial
+ for(i=0;i<2;i++)
+ {
+ priority[i] = 0;
+ defPriority[i]=-1;
+ upDown[i]=-1;
+ defUpDown[i]=-1;
+ }
+
+ for(i=0;i<2;i++)
+ {
+ if (rtl865x_getRouteEntry(sip, &rt)==SUCCESS)
+ {
+ /* check ip base rule firstly */
+
+ memset(&rule4[i], 0, sizeof(rtl865x_AclRule_t));
+ rule4[i].ruleType_ = (naptEntry->protocol==RTL865X_PROTOCOL_TCP?RTL865X_ACL_TCP:RTL865X_ACL_UDP);
+ rule4[i].srcIpAddr_ = sip;
+ rule4[i].dstIpAddr_ = dip;
+ rule4[i].tcpSrcPortLB_ = sport;
+ rule4[i].tcpDstPortLB_ = dport;
+ rule4[i].netifIdx_ = _rtl865x_getNetifIdxByNameExt(rt.dstNetif->name);
+
+ if (rtl865x_qosCheckNaptPriority(&rule4[i])==SUCCESS)
+ {
+ priority[i] = rule4[i].priority_; /* matched priority */
+ upDown[i]=rule4[i].upDown_;
+ //break;
+
+ if (i==0)
+ {
+ sip = naptEntry->remIp;
+ dip = naptEntry->intIp;
+ sport = naptEntry->remPort;
+ dport = naptEntry->intPort;
+ continue;
+ }
+
+ }
+ else if (i==0)
+ {
+ sip = naptEntry->remIp;
+ dip = naptEntry->intIp;
+ sport = naptEntry->remPort;
+ dport = naptEntry->intPort;
+ continue;
+ }
+ else
+ {
+ defPriority[i] = rule4[i].priority_;
+ defUpDown[i]=rule4[i].upDown_;
+ }
+ }
+ else
+ {
+ sip = naptEntry->remIp;
+ dip = naptEntry->intIp;
+ sport = naptEntry->remPort;
+ dport = naptEntry->intPort;
+ }
+ }
+
+ {
+ sip = naptEntry->intIp;
+ for(i=0;i<2;i++)
+ {
+ if (rtl865x_getArpMapping(sip, &arpInfo)==SUCCESS && rtl865x_getRouteEntry(sip, &rt)==SUCCESS)
+ {
+ /* check mac base rule secondly */
+ memset(&rule2[i], 0, sizeof(rtl865x_AclRule_t));
+ rule2[i].ruleType_ = RTL865X_ACL_MAC;
+ memcpy(rule2[i].srcMac_.octet, arpInfo.mac.octet, ETHER_ADDR_LEN);
+ memset(rule2[i].srcMacMask_.octet, 0xff, ETHER_ADDR_LEN);
+ rule2[i].netifIdx_ = _rtl865x_getNetifIdxByNameExt(rt.dstNetif->name);
+
+ if (rtl865x_qosCheckNaptPriority(&rule2[i])==SUCCESS)
+ {
+ priority[i] = rule2[i].priority_; /* matched priority */
+ upDown[i]=rule2[i].upDown_;
+ //break;
+
+ if(i==0)
+ {
+ sip = naptEntry->remIp;
+ continue;
+ }
+
+ }
+ else if(i==0)
+ {
+ sip = naptEntry->remIp;
+ continue;
+ }
+ else
+ {
+ dip = naptEntry->remIp;
+ for(i=0;i<2;i++)
+ {
+ if (rtl865x_getArpMapping(dip, &arpInfo)==SUCCESS)
+ {
+ /* check mac base rule secondly */
+ memset(&rule2[i], 0, sizeof(rtl865x_AclRule_t));
+ rule2[i].ruleType_ = RTL865X_ACL_MAC;
+ memcpy(rule2[i].dstMac_.octet, arpInfo.mac.octet, ETHER_ADDR_LEN);
+ memset(rule2[i].dstMacMask_.octet, 0xff, ETHER_ADDR_LEN);
+ rule2[i].netifIdx_ = _rtl865x_getNetifIdxByNameExt(rt.dstNetif->name);
+
+ if (rtl865x_qosCheckNaptPriority(&rule2[i])==SUCCESS)
+ {
+ priority[i] = rule2[i].priority_; /* matched priority */
+ upDown[i]=rule2[i].upDown_;
+ //break;
+
+ if(i==0)
+ {
+ dip = naptEntry->intIp;
+ continue;
+ }
+
+ }
+ else if(i==0)
+ {
+ dip = naptEntry->intIp;
+ continue;
+ }
+ else
+ {
+ defPriority[i] = rule2[i].priority_;
+ defUpDown[i]=rule2[i].upDown_;
+ }
+ }
+ else
+ {
+ dip = naptEntry->intIp;
+ }
+ }
+ }
+ }
+ else
+ {
+ sip = naptEntry->remIp;
+ }
+ }
+ }
+
+ for(i=0;i<2;i++)
+ {
+ if (rule4[i].aclIdx&&rule2[i].aclIdx)
+ {
+ priority[i] = (rule4[i].aclIdx<rule2[i].aclIdx)?rule4[i].priority_:rule2[i].priority_;
+ upDown[i]=(rule4[i].aclIdx<rule2[i].aclIdx)?rule4[i].upDown_:rule2[i].upDown_;
+ }
+ else if (rule4[i].aclIdx)
+ {
+ priority[i] = rule4[i].priority_;
+ upDown[i]=rule4[i].upDown_;
+ }
+ else if (rule2[i].aclIdx)
+ {
+ priority[i] = rule2[i].priority_;
+ upDown[i]=rule2[i].upDown_;
+ }
+ else if (defPriority[i]>-1)
+ {
+ priority[i] = defPriority[i];
+ upDown[i]=defUpDown[i];
+ }
+ }
+#else /* defined(CONFIG_RTL_IPTABLES_RULE_2_ACL) */
+ priority[0]=prio->uplinkPrio;
+ priority[1]=prio->downlinkPrio;
+#endif /* defined(CONFIG_RTL_IPTABLES_RULE_2_ACL) */
+#endif /* defined(CONFIG_RTL_HW_QOS_SUPPORT) */
+
+ for(i=0; i<2; i++) {
+
+ if(i==0)
+ {
+ /*check writing outbound connection into asic*/
+ if((outCollision==TRUE) || (nat_out==NULL))
+ {
+ /*shouldn't be written into asic*/
+ continue;
+ }
+ }
+ else if(i==1)
+ {
+ /*check writing inbound connection into asic*/
+ if((inCollision==TRUE)||(nat_in==NULL))
+ {
+ /*shouldn't be written into asic*/
+ continue;
+ }
+ }
+ else
+ {
+ break;
+ }
+ //If qos enabled, not add inbound napt
+ //That is all downlink pkt will be trapped to CPU for software QoS
+ #if 0
+ /* drop pkt in the queue will resolve the wan->lan issue */
+ if((flags==FLAG_QOS_ENABLE)&&(i==1))
+ break;
+ #endif
+
+ memset(&asic_nat, 0, sizeof(asic_nat));
+ asic_nat.insideLocalIpAddr = naptEntry->intIp;
+ asic_nat.insideLocalPort = naptEntry->intPort;
+ asic_nat.isCollision = 0;
+ asic_nat.isCollision2 = 0;
+ asic_nat.isDedicated = 0;
+ asic_nat.isStatic = 1;
+ asic_nat.isTcp = (naptEntry->protocol==RTL865X_PROTOCOL_TCP)? 1: 0;
+ asic_nat.isValid = 1;
+ asic_nat.offset = ((i==0)?offset : (naptEntry->extPort & 0x3f));
+ asic_nat.selEIdx = ((i==0)?selEidx_out: very &0x3ff);
+ asic_nat.selExtIPIdx = ((i==0)?ipidx:((naptEntry->extPort & 0x3ff) >> 6));
+ //asic_nat.tcpFlag = (((in!=out)? 0x2:0x0) | ((i==0)? 1: 0));
+ /*enhanced hash1 doesn't support outbound/inbound share one connection*/
+ asic_nat.tcpFlag = (0x2 | ((i==0)? 1: 0));
+ asic_nat.ageSec = (naptEntry->protocol==RTL865X_PROTOCOL_TCP)? nat_tbl.tcp_timeout:nat_tbl.udp_timeout;
+#if defined(CONFIG_RTL_HW_QOS_SUPPORT)
+ asic_nat.priValid = FALSE;
+ #if defined(CONFIG_RTL_IPTABLES_RULE_2_ACL)
+ if(i==0&&upDown[i]==0)//Because ((i==0)?out: in)
+ {
+ //out: uplink
+ asic_nat.priority = priority[i];
+ }
+ if (i==1&&upDown[i]==1)
+ {
+ //in: downlink
+ asic_nat.priority = priority[i];
+ }
+ #else /* defined(CONFIG_RTL_IPTABLES_RULE_2_ACL) */
+ asic_nat.priority = priority[i];
+ #endif /* defined(CONFIG_RTL_IPTABLES_RULE_2_ACL) */
+ asic_nat.priValid = TRUE;
+#else
+ asic_nat.priValid = FALSE;
+#endif
+
+ rtl8651_setAsicNaptTcpUdpTable(1, ((i==0)?out: in), &asic_nat);
+ }
+
+
+ nat_tbl.connNum++;
+
+ if((outCollision==FALSE) && (nat_out!=NULL))
+ {
+ if(nat_tbl.freeEntryNum>0)
+ {
+ nat_tbl.freeEntryNum--;
+ }
+ }
+
+ if((inCollision==FALSE) && (nat_in!=NULL))
+ {
+ if(nat_tbl.freeEntryNum>0)
+ {
+ nat_tbl.freeEntryNum--;
+ }
+ }
+
+ return SUCCESS;
+}
+
+
+static int32 _rtl865x_delNaptConnection(rtl865x_napt_entry *naptEntry)
+{
+ struct nat_entry *nat_out, *nat_in;
+ struct nat_tuple nat_tuple;
+
+ memset(&nat_tuple, 0, sizeof(struct nat_tuple));
+ nat_tuple.int_host.ip = naptEntry->intIp;
+ nat_tuple.int_host.port = naptEntry->intPort;
+ nat_tuple.ext_host.ip = naptEntry->extIp;
+ nat_tuple.ext_host.port = naptEntry->extPort;
+ nat_tuple.rem_host.ip = naptEntry->remIp;
+ nat_tuple.rem_host.port = naptEntry->remPort;
+ nat_tuple.proto = naptEntry->protocol;
+
+ nat_out = _rtl865x_nat_outbound_lookup(&nat_tuple);
+ nat_in = _rtl865x_nat_inbound_lookup(&nat_tuple);
+
+ if ((nat_out==NULL) && (nat_in==NULL))
+ {
+ return RTL_EENTRYNOTFOUND;
+ }
+
+ if(nat_out==nat_in)
+ {
+ rtl8651_delAsicNaptTcpUdpTable(nat_out->out, nat_out->out);
+ memset(nat_out, 0, sizeof(*nat_out));
+ nat_tbl.freeEntryNum++;
+
+ }
+ else
+ {
+ if(nat_out)
+ {
+ rtl8651_delAsicNaptTcpUdpTable(nat_out->out, nat_out->out);
+ memset(nat_out, 0, sizeof(*nat_out));
+ nat_tbl.freeEntryNum++;
+ }
+
+ if(nat_in)
+ {
+ rtl8651_delAsicNaptTcpUdpTable(nat_in->in, nat_in->in);
+ memset(nat_in, 0, sizeof(*nat_in));
+ nat_tbl.freeEntryNum++;
+ }
+ }
+ #ifdef CONFIG_HARDWARE_NAT_DEBUG
+ /*2007-12-19*/
+ rtlglue_printf("LR(%s): %s (%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u) g:(%u.%u.%u.%u:%u)\n",
+ ("del_nat"), ((naptEntry->protocol)? "tcp": "udp"),
+ NIPQUAD(naptEntry->intIp), naptEntry->intPort, NIPQUAD(naptEntry->remIp), naptEntry->remPort, NIPQUAD(naptEntry->extIp), naptEntry->extPort);
+ #endif
+
+ if(nat_tbl.connNum>0)
+ {
+ nat_tbl.connNum--;
+ }
+
+ return SUCCESS;
+}
+#if 0
+static int32 _rtl865x_naptIdleCheck(int32 index)
+{
+ rtl865x_tblAsicDrv_naptTcpUdpParam_t entry;
+ int32 hw_now;
+
+ rtl8651_getAsicNaptTcpUdpTable(index, &entry);
+
+ hw_now = entry.ageSec;
+
+ if (entry.isTcp) {
+ return (nat_tbl.tcp_timeout>hw_now?nat_tbl.tcp_timeout-hw_now:0);
+ } else {
+ return (nat_tbl.udp_timeout>hw_now?nat_tbl.udp_timeout-hw_now:0);
+ }
+}
+#endif
+static int32 _rtl865x_naptSync(rtl865x_napt_entry *naptEntry, uint32 refresh)
+{
+ rtl865x_tblAsicDrv_naptTcpUdpParam_t asic_nat_out;
+ rtl865x_tblAsicDrv_naptTcpUdpParam_t asic_nat_in;
+ struct nat_entry *nat_out,*nat_in;
+ struct nat_tuple nat_tuple;
+ int32 rc;
+
+ memset(&nat_tuple, 0, sizeof(struct nat_tuple));
+ nat_tuple.int_host.ip = naptEntry->intIp;
+ nat_tuple.int_host.port = naptEntry->intPort;
+ nat_tuple.ext_host.ip = naptEntry->extIp;
+ nat_tuple.ext_host.port = naptEntry->extPort;
+ nat_tuple.rem_host.ip = naptEntry->remIp;
+ nat_tuple.rem_host.port = naptEntry->remPort;
+ nat_tuple.proto = naptEntry->protocol;
+
+ nat_out = _rtl865x_nat_outbound_lookup(&nat_tuple);
+ nat_in = _rtl865x_nat_inbound_lookup(&nat_tuple);
+
+ if( (!nat_out) && (!nat_in))
+ {
+ return 0;
+
+ }
+
+ memset(&asic_nat_out ,0 ,sizeof(rtl865x_tblAsicDrv_naptTcpUdpParam_t));
+ memset(&asic_nat_in,0 ,sizeof(rtl865x_tblAsicDrv_naptTcpUdpParam_t));
+
+ if((nat_out!=NULL) && (nat_in!=NULL))
+ {
+ rc = rtl8651_getAsicNaptTcpUdpTable(nat_out->out, &asic_nat_out);
+ assert(rc==SUCCESS);
+
+ rc = rtl8651_getAsicNaptTcpUdpTable(nat_in->in, &asic_nat_in);
+ assert(rc==SUCCESS);
+ return (asic_nat_out.ageSec>asic_nat_in.ageSec)? asic_nat_out.ageSec: asic_nat_in.ageSec;
+ }
+ else if((nat_out!=NULL) && (nat_in==NULL))
+ {
+ rc = rtl8651_getAsicNaptTcpUdpTable(nat_out->out, &asic_nat_out);
+ assert(rc==SUCCESS);
+ return asic_nat_out.ageSec;
+ }
+ else if((nat_out==NULL) && (nat_in!=NULL))
+ {
+ rc = rtl8651_getAsicNaptTcpUdpTable(nat_in->in, &asic_nat_in);
+ assert(rc==SUCCESS);
+ return asic_nat_in.ageSec;
+
+ }
+ else
+ {
+ return 0;
+ }
+
+ return 0;
+
+
+}
+
+
+/*
+@func int32 | rtl865x_addNaptConnection |add a napt entry.
+@parm uint32 | protocol | protocol.
+@parm ipaddr_t | intIp | internal ip address.
+@parm uint32 | intPort | internal port.
+@parm ipaddr_t | extIp | external ip address.
+@parm uint32 | extPort | external port.
+@parm ipaddr_t | remIp | remote ip address.
+@parm uint32 | remPort | remote port.
+@parm int32 | flags | flags.
+@rvalue SUCCESS | success.
+@rvalue FAILED | failed.
+@rvalue RTL_EINVALIDINPUT | invalid input.
+@rvalue RTL_EENTRYALREADYEXIST | route entry is already exist.
+@rvalue RTL_ENOFREEBUFFER | not enough memory in system.
+@comm
+ value of protocol should be RTL865X_PROTOCOL_TCP/RTL865X_PROTOCOL_UDP
+*/
+int32 rtl865x_addNaptConnection(rtl865x_napt_entry *naptEntry, rtl865x_priority *prio)
+{
+ int32 retval = FAILED;
+
+ retval = _rtl865x_addNaptConnection(naptEntry, prio);
+
+ return retval;
+}
+
+/*
+@func int32 | rtl865x_delNaptConnection |delete a napt entry.
+@parm uint32 | protocol | protocol.
+@parm ipaddr_t | intIp | internal ip address.
+@parm uint32 | intPort | internal port.
+@parm ipaddr_t | extIp | external ip address.
+@parm uint32 | extPort | external port.
+@parm ipaddr_t | remIp | remote ip address.
+@parm uint32 | remPort | remote port.
+
+@rvalue SUCCESS | success.
+@rvalue FAILED | failed.
+@rvalue RTL_EENTRYNOTFOUND | not found this entry in system.
+@comm
+*/
+int32 rtl865x_delNaptConnection(rtl865x_napt_entry *naptEntry)
+{
+ int32 retval = FAILED;
+
+ retval = _rtl865x_delNaptConnection(naptEntry);
+
+ return retval;
+}
+
+int32 rtl865x_naptSync(rtl865x_napt_entry *naptEntry, uint32 refresh)
+{
+ return _rtl865x_naptSync(naptEntry,refresh);
+}
+
+#if defined(CONFIG_RTL_HW_QOS_SUPPORT) && defined(CONFIG_RTL_IPTABLES_RULE_2_ACL)
+inline static int32 rtl865x_naptSetAsicWithPriority(struct nat_entry *entry, int32 priority)
+{
+ rtl865x_tblAsicDrv_naptTcpUdpParam_t asic_nat;
+ int32 idx;
+
+ //If qos enabled, not add inbound napt
+ //That is all downlink pkt will be trapped to CPU for software QoS
+ if(entry->flags&NAT_INBOUND)
+ return SUCCESS;
+
+ //printk("--%s(%d),entry(%p)\n",__FUNCTION__,__LINE__,entry);
+ idx = (entry->flags&NAT_INBOUND)?entry->in:entry->out;
+
+ rtl8651_getAsicNaptTcpUdpTable(idx, &asic_nat);
+ asic_nat.priority = priority;
+ asic_nat.priValid = TRUE;
+ rtl8651_setAsicNaptTcpUdpTable(1, idx, &asic_nat);
+
+ return SUCCESS;
+}
+
+static int32 rtl865x_naptCallbackFn_for_qosChange(void *param)
+{
+ int num, i;
+ struct nat_entry *nat_this, *nat_that;
+ ipaddr_t sip, dip;
+ uint16 sport, dport;
+ rtl865x_route_t rt;
+ rtl865x_arpMapping_entry_t arpInfo;
+ rtl865x_AclRule_t rule4, rule2;
+ int32 priority=-1, defPriority=-1;
+
+ num = i = 0;
+
+ while(num < nat_tbl.connNum && i < RTL8651_TCPUDPTBL_SIZE)
+ {
+ if(NAT_INUSE(&nat_tbl.nat_bucket[i]))
+ {
+ nat_this = &nat_tbl.nat_bucket[i];
+ if (nat_this->flags&NAT_INBOUND)
+ {
+ if(nat_this->out!=0xFFFFFFFF)
+ {
+ nat_that = &nat_tbl.nat_bucket[nat_this->out];
+ }
+ else
+ {
+ /*no outbound*/
+ nat_that = NULL;
+ }
+
+ sip = nat_this->rem_ip_;
+ dip = nat_this->ext_ip_;
+ sport = nat_this->rem_port_;
+ dport = nat_this->ext_port_;
+ }
+ else
+ {
+ if(nat_this->in!=0xFFFFFFFF)
+ {
+ nat_that = &nat_tbl.nat_bucket[nat_this->in];
+ }
+ else
+ {
+ /*no inbound*/
+ nat_that=NULL;
+ }
+
+ sip = nat_this->int_ip_;
+ dip = nat_this->rem_ip_;
+ sport = nat_this->int_port_;
+ dport = nat_this->rem_port_;
+ }
+
+ if (nat_this->flags&NAT_PRI_PROCESSED)
+ {
+ CLR_NAT_FLAGS(nat_this, NAT_PRI_PROCESSED);
+ num++;
+ }
+ else
+ {
+ if (rtl865x_getRouteEntry(sip, &rt)==SUCCESS)
+ {
+ memset(&rule4, 0, sizeof(rtl865x_AclRule_t));
+ rule4.ruleType_ = (nat_this->proto_==RTL865X_PROTOCOL_TCP?RTL865X_ACL_TCP:RTL865X_ACL_UDP);
+ rule4.srcIpAddr_ = sip;
+ rule4.dstIpAddr_ = dip;
+ rule4.tcpSrcPortLB_ = sport;
+ rule4.tcpDstPortLB_ = dport;
+ rule4.netifIdx_ = _rtl865x_getNetifIdxByNameExt(rt.dstNetif->name);
+ if(rule4.netifIdx_ < 0 || rule4.netifIdx_ >= NETIF_NUMBER)
+ {
+ printk("===%s %s(%d) Can't get netif(%s)\n",__FILE__,__FUNCTION__,__LINE__,rt.dstNetif->name);
+ }
+
+ if(rule4.netifIdx_ >=0 && rule4.netifIdx_ < NETIF_NUMBER)
+ if (rtl865x_qosCheckNaptPriority(&rule4)!=SUCCESS)
+ {
+ if (nat_this->flags&NAT_INBOUND)
+ {
+ rule4.dstIpAddr_ = nat_this->int_ip_;
+ rule4.tcpDstPortLB_ = nat_this->int_port_;
+ if (rtl865x_qosCheckNaptPriority(&rule4)!=SUCCESS)
+ defPriority = rule4.priority_;
+ }
+ else
+ defPriority = rule4.priority_;
+ }
+
+ if (rtl865x_getArpMapping(sip, &arpInfo)==SUCCESS)
+ {
+ memset(&rule2, 0, sizeof(rtl865x_AclRule_t));
+ rule2.ruleType_ = RTL865X_ACL_MAC;
+ memcpy(rule2.srcMac_.octet, arpInfo.mac.octet, ETHER_ADDR_LEN);
+ memset(rule2.srcMacMask_.octet, 0xff, ETHER_ADDR_LEN);
+ rule2.netifIdx_ = _rtl865x_getNetifIdxByNameExt(rt.dstNetif->name);
+ if(rule4.netifIdx_ < 0 || rule4.netifIdx_ >= NETIF_NUMBER)
+ {
+ printk("===%s %s(%d) Can't get netif(%s)\n",__FILE__,__FUNCTION__,__LINE__,rt.dstNetif->name);
+ }
+
+ if(rule4.netifIdx_ >=0 && rule4.netifIdx_ < NETIF_NUMBER)
+ if (rtl865x_qosCheckNaptPriority(&rule2)!=SUCCESS)
+ {
+ if (nat_this->flags&NAT_INBOUND)
+ {
+ if(rtl865x_getArpMapping(nat_this->int_ip_, &arpInfo)==SUCCESS)
+ {
+ memset(&rule2, 0, sizeof(rtl865x_AclRule_t));
+ rule2.ruleType_ = RTL865X_ACL_MAC;
+ memcpy(rule2.dstMac_.octet, arpInfo.mac.octet, ETHER_ADDR_LEN);
+ memset(rule2.dstMacMask_.octet, 0xff, ETHER_ADDR_LEN);
+ rule2.netifIdx_ = _rtl865x_getNetifIdxByNameExt(rt.dstNetif->name);
+ if (rtl865x_qosCheckNaptPriority(&rule2)!=SUCCESS)
+ defPriority = rule2.priority_;
+ }
+ }
+ else
+ defPriority = rule2.priority_;
+ }
+ }
+
+ if (rule4.aclIdx&& rule2.aclIdx)
+ {
+ priority = (rule4.aclIdx<rule2.aclIdx)?rule4.priority_:rule2.priority_;
+ }
+ else if (rule4.aclIdx)
+ {
+ priority = rule4.priority_;
+ }
+ else if (rule2.aclIdx)
+ {
+ priority = rule2.priority_;
+ }
+
+ if (priority>-1)
+ {
+
+ rtl865x_naptSetAsicWithPriority(nat_this, priority);
+
+ if(nat_that!=NULL)
+ {
+ rtl865x_naptSetAsicWithPriority(nat_that, priority);
+ }
+
+ if (nat_this->flags&NAT_PRI_HALF_PROCESSED)
+ {
+ CLR_NAT_FLAGS(nat_this, NAT_PRI_HALF_PROCESSED);
+ num++;
+ }
+ else
+ {
+ if(nat_that!=NULL)
+ {
+ SET_NAT_FLAGS(nat_that, NAT_PRI_PROCESSED);
+ }
+ else
+ {
+ /*only half accelerated*/
+ num++;
+ }
+ }
+ }
+ else
+ {
+ if (nat_this->flags&NAT_PRI_HALF_PROCESSED)
+ {
+ rtl865x_naptSetAsicWithPriority(nat_this, defPriority>-1?defPriority:0);
+ assert(nat_that!=NULL);
+ if(nat_that!=NULL)
+ {
+ rtl865x_naptSetAsicWithPriority(nat_that, defPriority>-1?defPriority:0);
+ }
+ CLR_NAT_FLAGS(nat_this, NAT_PRI_HALF_PROCESSED);
+ num++;
+ }
+ else
+ {
+ if(nat_that!=NULL)
+ {
+ SET_NAT_FLAGS(nat_that, NAT_PRI_HALF_PROCESSED);
+ }
+ else
+ {
+ /*only half accelerated*/
+ num++;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (nat_this->flags&NAT_PRI_HALF_PROCESSED)
+ {
+ CLR_NAT_FLAGS(nat_this, NAT_PRI_HALF_PROCESSED);
+ num++;
+ }
+ else
+ {
+ if(nat_that!=NULL)
+ {
+ SET_NAT_FLAGS(nat_that, NAT_PRI_HALF_PROCESSED);
+ }
+ else
+ {
+ /*only half accelerated*/
+ num++;
+ }
+ }
+ }
+ }
+ }
+
+ i++;
+ }
+ return EVENT_CONTINUE_EXECUTE;
+}
+
+
+static int32 rtl865x_napt_register_qosEvent(void)
+{
+ rtl865x_event_Param_t eventParam;
+
+ eventParam.eventLayerId=DEFAULT_LAYER2_EVENT_LIST_ID;
+ eventParam.eventId=EVENT_CHANGE_QOSRULE;
+ eventParam.eventPriority=0;
+ eventParam.event_action_fn=rtl865x_naptCallbackFn_for_qosChange;
+ rtl865x_registerEvent(&eventParam);
+
+ eventParam.eventId=EVENT_FLUSH_QOSRULE;
+ rtl865x_registerEvent(&eventParam);
+
+ eventParam.eventLayerId=DEFAULT_LAYER3_EVENT_LIST_ID;
+ eventParam.eventId=EVENT_ADD_ARP;
+ rtl865x_registerEvent(&eventParam);
+
+ return SUCCESS;
+}
+
+static int32 rtl865x_napt_unRegister_qosEvent(void)
+{
+ rtl865x_event_Param_t eventParam;
+
+ eventParam.eventLayerId=DEFAULT_LAYER2_EVENT_LIST_ID;
+ eventParam.eventId=EVENT_CHANGE_QOSRULE;
+ eventParam.eventPriority=0;
+ eventParam.event_action_fn=rtl865x_naptCallbackFn_for_qosChange;
+ rtl865x_unRegisterEvent(&eventParam);
+
+ eventParam.eventId=EVENT_FLUSH_QOSRULE;
+ rtl865x_unRegisterEvent(&eventParam);
+
+ eventParam.eventLayerId=DEFAULT_LAYER3_EVENT_LIST_ID;
+ eventParam.eventId=EVENT_ADD_ARP;
+ rtl865x_unRegisterEvent(&eventParam);
+
+ return SUCCESS;
+}
+#endif
+
+/*
+@func int32 | rtl865x_setNatFourWay |enable 4way hash algorithm.
+@parm int32 | enable | enable or disable.
+@rvalue SUCCESS | success.
+@comm
+ default is enable in system.
+*/
+int32 rtl865x_setNatFourWay(int32 enable)
+{
+ _set4WayHash(enable);
+ rtl865x_enableNaptFourWay=enable;
+ return SUCCESS;
+}
+
+/*
+@func int32 | rtl865x_nat_init |initialize napt table.
+@rvalue SUCCESS | success.
+@comm
+*/
+int32 rtl865x_nat_init(void)
+{
+ int32 retval = FAILED;
+#if defined(CONFIG_RTL_HW_QOS_SUPPORT) && defined(CONFIG_RTL_IPTABLES_RULE_2_ACL)
+ rtl865x_napt_unRegister_qosEvent();
+#endif
+
+ retval = _rtl865x_nat_init();
+ rtl865x_setNatFourWay(TRUE);
+
+#if defined(CONFIG_RTL_HW_QOS_SUPPORT) && defined(CONFIG_RTL_IPTABLES_RULE_2_ACL)
+ rtl865x_napt_register_qosEvent();
+#endif
+ return retval;
+}
+
+int32 rtl865x_nat_reinit(void)
+{
+ return rtl865x_nat_init();
+
+}
+
+#ifdef CONFIG_RTL_PROC_DEBUG
+int32 rtl865x_flushAllNaptConnection(void)
+{
+ uint32 i,outIndex,inIndex;
+ struct nat_entry *nat_out=NULL, *nat_in=NULL, *tmp=NULL;
+ for(i=0;i<RTL8651_TCPUDPTBL_SIZE;i++)
+ {
+ tmp = &nat_tbl.nat_bucket[i];
+
+ if(NAT_INUSE(tmp))
+ {
+ outIndex=tmp->out;
+ inIndex=tmp->in;
+ if(outIndex!=0xFFFFFFFF)
+ {
+ nat_out=&nat_tbl.nat_bucket[outIndex];
+ }
+ else
+ {
+ nat_out=NULL;
+ }
+
+ if(inIndex!=0xFFFFFFFF)
+ {
+ nat_in=&nat_tbl.nat_bucket[inIndex];
+ }
+ else
+ {
+ nat_in=NULL;
+ }
+
+ if((nat_out==NULL) &&(nat_in==NULL))
+ {
+ rtl8651_delAsicNaptTcpUdpTable(i, i);
+ continue;
+ }
+
+ if(nat_out==nat_in)
+ {
+ if(nat_out->flags&NAT_OUTBOUND)
+ {
+ rtl8651_delAsicNaptTcpUdpTable(outIndex, outIndex);
+ memset(nat_out, 0, sizeof(*nat_out));
+ nat_tbl.freeEntryNum++;
+ }
+ else if(nat_in->flags&NAT_INBOUND)
+ {
+ rtl8651_delAsicNaptTcpUdpTable(inIndex, inIndex);
+ memset(nat_in, 0, sizeof(*nat_in));
+ nat_tbl.freeEntryNum++;
+ }
+ else
+ {
+ /*fatal error*/
+ return RTL_EENTRYNOTFOUND;
+ }
+ }
+ else
+ {
+ if((nat_out!=NULL) && (nat_out->flags&NAT_OUTBOUND))
+ {
+ rtl8651_delAsicNaptTcpUdpTable(outIndex, outIndex);
+ memset(nat_out, 0, sizeof(*nat_out));
+ nat_tbl.freeEntryNum++;
+ }
+
+ if((nat_in!=NULL) && (nat_in->flags&NAT_INBOUND))
+ {
+ rtl8651_delAsicNaptTcpUdpTable(inIndex,inIndex);
+ memset(nat_in, 0, sizeof(*nat_in));
+ nat_tbl.freeEntryNum++;
+ }
+ }
+
+ if(nat_tbl.connNum>0)
+ {
+ nat_tbl.connNum--;
+ }
+
+ }
+ }
+
+ return SUCCESS;
+}
+
+int32 rtl865x_sw_napt_seq_read(struct seq_file *s, void *v)
+{
+
+ int i;
+ struct nat_entry *natEntryPtr;
+ int len=0;
+
+ len = seq_printf(s, "%s\n", "sw napt table:");
+
+ for(i=0; i<RTL8651_TCPUDPTBL_SIZE; i++)
+ {
+ natEntryPtr= &nat_tbl.nat_bucket[i];
+ if(NAT_INUSE(natEntryPtr))
+ {
+ if(natEntryPtr->flags&NAT_OUTBOUND)
+ {
+ len += seq_printf(s, "[%4d]%s:%d.%d.%d.%d:%d---->%d.%d.%d.%d:%d---->%d.%d.%d.%d:%d\n flags:0x%x,outbound:(%d),inbound:(%d)\n",
+ i,natEntryPtr->proto_==1?"tcp":"udp" ,NIPQUAD(natEntryPtr->int_ip_),natEntryPtr->int_port_,
+ NIPQUAD(natEntryPtr->ext_ip_),natEntryPtr->ext_port_,NIPQUAD(natEntryPtr->rem_ip_),natEntryPtr->rem_port_,natEntryPtr->flags,natEntryPtr->out, natEntryPtr->in);
+ }
+
+ if(natEntryPtr->flags&NAT_INBOUND)
+ {
+ len += seq_printf(s, "[%4d]%s:%d.%d.%d.%d:%d<----%d.%d.%d.%d:%d<----%d.%d.%d.%d:%d\n flags:0x%x, outbound:(%d), inbound:(%d)\n",
+ i,natEntryPtr->proto_==1?"tcp":"udp" ,NIPQUAD(natEntryPtr->int_ip_),natEntryPtr->int_port_,
+ NIPQUAD(natEntryPtr->ext_ip_),natEntryPtr->ext_port_,NIPQUAD(natEntryPtr->rem_ip_),natEntryPtr->rem_port_,natEntryPtr->flags,natEntryPtr->out,natEntryPtr->in);
+ }
+ }
+
+ }
+
+ len += seq_printf(s, "total napt connection number is %d\n",nat_tbl.connNum);
+ len += seq_printf(s, "total free entry number is %d\n",nat_tbl.freeEntryNum);
+ return 0;
+}
+
+int32 rtl865x_sw_napt_seq_write( struct file *filp, const char *buff,unsigned long len, loff_t *off )
+{
+ char tmpbuf[64];
+ uint32 delIndex,inIndex=0,outIndex=0;
+ char *strptr, *cmd_addr;
+ char *tokptr;
+ struct nat_entry *nat_out=NULL, *nat_in=NULL, *tmp=NULL;
+
+ if (buff && !copy_from_user(tmpbuf, buff, len)) {
+ tmpbuf[len] = '\0';
+ strptr=tmpbuf;
+ cmd_addr = strsep(&strptr," ");
+ if (cmd_addr==NULL)
+ {
+ goto errout;
+ }
+
+ if (!memcmp(cmd_addr, "flush", 5))
+ {
+ rtl865x_flushAllNaptConnection();
+ }
+ else if (!memcmp(cmd_addr, "del", 3))
+ {
+ tokptr = strsep(&strptr," ");
+ if (tokptr==NULL)
+ {
+ goto errout;
+ }
+
+ delIndex=simple_strtol(tokptr, NULL, 0);
+ if(delIndex>RTL8651_TCPUDPTBL_SIZE)
+ {
+ printk("error input!\n");
+ return len;
+ }
+ tmp = &nat_tbl.nat_bucket[delIndex];
+
+ if(NAT_INUSE(tmp))
+ {
+ outIndex=tmp->out;
+ inIndex=tmp->in;
+ if(outIndex!=0xFFFFFFFF)
+ {
+ nat_out=&nat_tbl.nat_bucket[outIndex];
+ }
+ else
+ {
+ nat_out=NULL;
+ }
+
+ if(inIndex!=0xFFFFFFFF)
+ {
+ nat_in=&nat_tbl.nat_bucket[inIndex];
+ }
+ else
+ {
+ nat_in=NULL;
+ }
+
+ if ((nat_out==NULL) && (nat_in==NULL))
+ {
+ rtl8651_delAsicNaptTcpUdpTable(delIndex, delIndex);
+ goto errout;
+ }
+
+ if(nat_out==nat_in)
+ {
+ rtl8651_delAsicNaptTcpUdpTable(outIndex, outIndex);
+ memset(nat_out, 0, sizeof(*nat_out));
+ nat_tbl.freeEntryNum++;
+ }
+ else
+ {
+ if((nat_out!=NULL) && (nat_out->flags&NAT_OUTBOUND))
+ {
+ rtl8651_delAsicNaptTcpUdpTable(outIndex, outIndex);
+ memset(nat_out, 0, sizeof(*nat_out));
+ nat_tbl.freeEntryNum++;
+ }
+
+ if((nat_in!=NULL) && ( nat_in->flags&NAT_INBOUND))
+ {
+ rtl8651_delAsicNaptTcpUdpTable(inIndex,inIndex);
+ memset(nat_in, 0, sizeof(*nat_in));
+ nat_tbl.freeEntryNum++;
+ }
+ }
+
+ if(nat_tbl.connNum>0)
+ {
+ nat_tbl.connNum--;
+ }
+ printk("del napt flow,outbound:%d,inbound:%d\n", outIndex, inIndex);
+
+ }
+
+ }
+ else
+ {
+ goto errout;
+ }
+ }
+ else
+ {
+errout:
+ return len;
+ }
+
+ return len;
+}
+
+#endif
+
diff --git a/target/linux/realtek/files/drivers/net/rtl819x/l4Driver/rtl865x_nat_local.h b/target/linux/realtek/files/drivers/net/rtl819x/l4Driver/rtl865x_nat_local.h
new file mode 100644
index 000000000..1949978c3
--- /dev/null
+++ b/target/linux/realtek/files/drivers/net/rtl819x/l4Driver/rtl865x_nat_local.h
@@ -0,0 +1,59 @@
+#ifndef RTL865X_NAT_LOCAL_H
+#define RTL865X_NAT_LOCAL_H
+
+struct nat_host_info {
+ ipaddr_t ip;
+ uint16 port;
+};
+
+struct nat_tuple {
+ struct nat_host_info int_host;
+ struct nat_host_info ext_host;
+ struct nat_host_info rem_host;
+ uint32 proto;
+};
+
+
+struct nat_entry {
+ struct nat_tuple tuple_info;
+
+ uint32 natip_idx;
+ uint32 in;
+ uint32 out;
+ uint32 flags;
+
+#if defined (CONFIG_RTL_INBOUND_COLLISION_AVOIDANCE)
+ uint32 reserveTime;
+#endif
+
+#define int_ip_ tuple_info.int_host.ip
+#define int_port_ tuple_info.int_host.port
+#define ext_ip_ tuple_info.ext_host.ip
+#define ext_port_ tuple_info.ext_host.port
+#define rem_ip_ tuple_info.rem_host.ip
+#define rem_port_ tuple_info.rem_host.port
+#define proto_ tuple_info.proto
+
+};
+
+struct nat_table {
+
+ int32 connNum; /* MUST equal or more than actually conntrack number */
+ int32 freeEntryNum;
+ int32 tcp_timeout;
+ int32 udp_timeout;
+ struct nat_entry nat_bucket[RTL8651_TCPUDPTBL_SIZE];
+};
+
+typedef struct rtl865x_naptHashInfo_s{
+ uint32 outIndex;
+ uint32 inIndex;
+ uint8 outCollision;
+ uint8 inCollision;
+ uint8 sameFourWay;
+ uint8 sameLocation;
+ uint8 inFreeCnt;
+}rtl865x_naptHashInfo_t;
+
+#endif
+