diff options
Diffstat (limited to 'target/linux/realtek/files/drivers/net/rtl819x/l4Driver')
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
+
|