From 5deb3317cb51ac52de922bb55f8492624018906d Mon Sep 17 00:00:00 2001 From: Roman Yeryomin Date: Thu, 13 Sep 2012 00:40:35 +0300 Subject: Add realtek target files Signed-off-by: Roman Yeryomin --- .../realtek/files/net/rtl/features/rtl_features.c | 2199 ++++++++++++++++++++ 1 file changed, 2199 insertions(+) create mode 100644 target/linux/realtek/files/net/rtl/features/rtl_features.c (limited to 'target/linux/realtek/files/net/rtl/features/rtl_features.c') diff --git a/target/linux/realtek/files/net/rtl/features/rtl_features.c b/target/linux/realtek/files/net/rtl/features/rtl_features.c new file mode 100644 index 000000000..a07cecac4 --- /dev/null +++ b/target/linux/realtek/files/net/rtl/features/rtl_features.c @@ -0,0 +1,2199 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_PROC_FS) +#include +#endif + +#if defined(CONFIG_RTL_HARDWARE_NAT )&&defined(CONFIG_RTL_MULTIPLE_WAN) +#include +#endif +#include +#include +#include +#if defined(CONFIG_RTL_HARDWARE_NAT) +#include +#include +#include +#include +#endif +#include +#include +#if defined(CONFIG_RTL_HARDWARE_NAT) +#include +#endif + +#ifdef CONFIG_RTL_LAYERED_DRIVER_L3 +#include +#include +#include +#endif + +#include + +#if defined(CONFIG_RTL_IPTABLES_FAST_PATH) || defined(CONFIG_RTL_HARDWARE_NAT) +#include +#endif + +//#if defined(CONFIG_RTL_IPTABLES_FAST_PATH) +#include +//#endif + +#if defined(CONFIG_RTL_LOCAL_PUBLIC) || defined(CONFIG_RTL_MULTIPLE_WAN) || (defined(CONFIG_NET_SCHED)&&defined(CONFIG_RTL_IPTABLES_FAST_PATH)) || defined(CONFIG_RTL_HW_QOS_SUPPORT) +#include +#endif + +#if defined(CONFIG_RTL_HW_QOS_SUPPORT) +#include +#endif + +#if defined (CONFIG_RTL_LOCAL_PUBLIC) +#include +extern int rtl865x_curOpMode; +#endif + +#if defined(CONFIG_RTL_FAST_BRIDGE) +#include +#endif + +#if defined(CONFIG_NET_SCHED) +__DRAM_GEN int gQosEnabled; +#endif + +#ifdef CONFIG_RTL_HARDWARE_NAT +/*2007-12-19*/ +#ifdef CONFIG_RTL_LAYERED_DRIVER_L3 +#include +#endif +#endif + +#include +#include + +#if defined(CONFIG_FAST_PATH_MODULE) && defined(CONFIG_RTL_IPTABLES_FAST_PATH) +#include +enum LR_RESULT (*FastPath_hook4)( rtl_fp_napt_entry *fpNaptEntry)=NULL; +enum LR_RESULT (*FastPath_hook6)( rtl_fp_napt_entry *fpNaptEntry, +#if defined(IMPROVE_QOS) + struct sk_buff *pskb, struct nf_conn *ct, +#endif + enum NP_FLAGS flags)=NULL; +enum LR_RESULT (*FastPath_hook11)(rtl_fp_napt_entry *fpNaptEntry, uint32 interval)=NULL; +int (*fast_path_hook)(struct sk_buff **pskb) = NULL; +EXPORT_SYMBOL(FastPath_hook4); +EXPORT_SYMBOL(FastPath_hook6); +EXPORT_SYMBOL(FastPath_hook11); +EXPORT_SYMBOL(fast_path_hook); +#endif + +#ifdef FAST_PPTP + void (*sync_tx_pptp_gre_seqno_hook)(struct sk_buff *skb) = NULL; +#ifdef CONFIG_FAST_PATH_MODULE +EXPORT_SYMBOL(sync_tx_pptp_gre_seqno_hook); +#endif +#endif + +#if defined(CONFIG_RTL_HARDWARE_NAT) +__DRAM_GEN int gHwNatEnabled; + +int rtl865x_handle_nat(struct nf_conn *ct, int act, struct sk_buff *skb) +{ + struct nf_conn_nat *nat; + u_int32_t sip, dip, gip; + u_int16_t sp, dp, gp, proto=0; + int timeval; + int rc=0; + +#if defined(CONFIG_RTL_HW_QOS_SUPPORT) + uint32 ret; + struct net_device *lanDev, *wanDev; +#endif + +#if defined(CONFIG_RTL_LAYERED_DRIVER_L4) + rtl865x_napt_entry rtl865xNaptEntry; + rtl865x_priority rtl865xPrio; + rtl865x_qos_mark rtl865xQosMark; +#endif + + if (gHwNatEnabled!=1) + return -1; + + proto = (ct->tuplehash[0].tuple.dst.protonum==IPPROTO_TCP)? 1: 0; + + if (ct->status & IPS_SRC_NAT) + { /* outbound flow */ + sip = ct->tuplehash[0].tuple.src.u3.ip; + dip = ct->tuplehash[0].tuple.dst.u3.ip; + gip = ct->tuplehash[1].tuple.dst.u3.ip; + sp = (proto)? ct->tuplehash[0].tuple.src.u.tcp.port: ct->tuplehash[0].tuple.src.u.udp.port; + dp = (proto)? ct->tuplehash[0].tuple.dst.u.tcp.port: ct->tuplehash[0].tuple.dst.u.udp.port; + gp = (proto)? ct->tuplehash[1].tuple.dst.u.tcp.port: ct->tuplehash[1].tuple.dst.u.udp.port; + } + else if (ct->status & IPS_DST_NAT) + { /* inbound flow */ + sip = ct->tuplehash[1].tuple.src.u3.ip; + dip = ct->tuplehash[1].tuple.dst.u3.ip; + gip = ct->tuplehash[0].tuple.dst.u3.ip; + sp = (proto)? ct->tuplehash[1].tuple.src.u.tcp.port: ct->tuplehash[1].tuple.src.u.udp.port; + dp = (proto)? ct->tuplehash[1].tuple.dst.u.tcp.port: ct->tuplehash[1].tuple.dst.u.udp.port; + gp = (proto)? ct->tuplehash[0].tuple.dst.u.tcp.port: ct->tuplehash[0].tuple.dst.u.udp.port; + } + else + return -1; + + /* do not add hardware NAPT table if protocol is UDP and source IP address is equal to gateway IP address */ + if ((act == 1) && (proto == 0) && (sip == gip)) + return -1; + + /* for TZO DDNS */ + if ((act == 1) && (proto == 1) && (dp == 21347)) { + return -1; + } + + if (act == 2) { + /* query for idle */ + timeval = 0; +#ifdef CONFIG_RTL_LAYERED_DRIVER_L4 + rtl865xNaptEntry.protocol=proto; + rtl865xNaptEntry.intIp=sip; + rtl865xNaptEntry.intPort=sp; + rtl865xNaptEntry.extIp=gip; + rtl865xNaptEntry.extPort=gp; + rtl865xNaptEntry.remIp=dip; + rtl865xNaptEntry.remPort=dp; + + timeval = rtl865x_naptSync(&rtl865xNaptEntry, 0); +#endif + if (timeval > 0) + return 0; + else + return -1; + } + else if (act == 0) { + /* delete */ + rc = 0; +#ifdef CONFIG_RTL_LAYERED_DRIVER_L4 + rtl865xNaptEntry.protocol=proto; + rtl865xNaptEntry.intIp=sip; + rtl865xNaptEntry.intPort=sp; + rtl865xNaptEntry.extIp=gip; + rtl865xNaptEntry.extPort=gp; + rtl865xNaptEntry.remIp=dip; + rtl865xNaptEntry.remPort=dp; + + rc = rtl865x_delNaptConnection(&rtl865xNaptEntry); +#endif + } + else { + #if defined(CONFIG_RTL_HW_QOS_SUPPORT) + if (NULL!=skb) + { + rtl865xNaptEntry.protocol=proto; + rtl865xNaptEntry.intIp=sip; + rtl865xNaptEntry.intPort=sp; + rtl865xNaptEntry.extIp=gip; + rtl865xNaptEntry.extPort=gp; + rtl865xNaptEntry.remIp=dip; + rtl865xNaptEntry.remPort=dp; + + rtl865xQosMark.downlinkMark=0; //Initial + rtl865xQosMark.uplinkMark=0; //Initial + ret=rtl_qosGetSkbMarkByNaptEntry(&rtl865xNaptEntry, &rtl865xQosMark, skb); + + lanDev=rtl865x_getLanDev(); + wanDev=rtl865x_getWanDev(); + rtl865xPrio.downlinkPrio=rtl_qosGetPriorityByMark(lanDev->name, rtl865xQosMark.downlinkMark); + rtl865xPrio.uplinkPrio=rtl_qosGetPriorityByMark(wanDev->name, rtl865xQosMark.uplinkMark); + + if(lanDev) + dev_put(lanDev); + + if(wanDev) + dev_put(wanDev); + } else + #endif + { + rtl865xPrio.downlinkPrio=0; + rtl865xPrio.uplinkPrio=0; + } + +#if defined(CONFIG_RTL_LAYERED_DRIVER_L4) + rtl865xNaptEntry.protocol=proto; + rtl865xNaptEntry.intIp=sip; + rtl865xNaptEntry.intPort=sp; + rtl865xNaptEntry.extIp=gip; + rtl865xNaptEntry.extPort=gp; + rtl865xNaptEntry.remIp=dip; + rtl865xNaptEntry.remPort=dp; +#endif + + /* add */ +#if defined(CONFIG_PROC_FS) && defined(CONFIG_NET_SCHED) && !defined(CONFIG_RTL_HW_QOS_SUPPORT) + if (gQosEnabled == 0) + { +#ifdef CONFIG_RTL_LAYERED_DRIVER_L4 + rc = rtl865x_addNaptConnection(&rtl865xNaptEntry, &rtl865xPrio); +#endif + } + else + { + act = 0; + } +#else +#ifdef CONFIG_RTL_LAYERED_DRIVER_L4 + rc = rtl865x_addNaptConnection(&rtl865xNaptEntry, &rtl865xPrio); +#endif + +#endif + } + + nat = nfct_nat(ct); + if (!rc && nat && act == 1) /* mark it as an asic entry */ + nat->hw_acc = 1; + if (!rc && nat && act == 0) /* unmark it */ + nat->hw_acc = 0; + + #ifdef CONFIG_HARDWARE_NAT_DEBUG + /*2007-12-19*/ + DEBUGP("%s:%d:(%s): errno=%d\n %s (%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u) g:(%u.%u.%u.%u:%u)\n", + __FUNCTION__,__LINE__,((is_add)?"add_nat": "del_nat"), rc, ((proto)? "tcp": "udp"), + NIPQUAD(sip), sp, NIPQUAD(dip), dp, NIPQUAD(gip), gp); + #endif + + return 0; +} + +/* return value: + FAILED: ct should be delete + SUCCESS: ct should NOT be delete. +*/ +int rtl_hwnat_timer_update(struct nf_conn *ct) +{ + unsigned long expires, now; + struct nf_conn_nat *nat; + + if (gHwNatEnabled!=1) + return FAILED; + + nat = nfct_nat(ct); + if (nat==NULL || nat->hw_acc!=1) + return FAILED; + + now = jiffies; + //read_lock_bh(&nf_conntrack_lock); + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { + if(ct->status & IPS_SEEN_REPLY) + expires = nf_ct_udp_timeout_stream; + else + expires = nf_ct_udp_timeout; + } else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_TCP && + ct->proto.tcp.state < TCP_CONNTRACK_LAST_ACK) { + expires = tcp_get_timeouts_by_state(ct->proto.tcp.state); + } else { + //read_unlock_bh(&nf_conntrack_lock); + return FAILED; + } + //read_unlock_bh(&nf_conntrack_lock); + + if (!rtl865x_handle_nat(ct, 2, NULL)) { + /* update ct expires time */ + ct->timeout.expires = now+expires; + rtl_check_for_acc(ct, (now+expires)); + return SUCCESS; + } else + return FAILED; + +} +#endif + + +#if defined(CONFIG_RTL_IPTABLES_FAST_PATH) || defined(CONFIG_RTL_HARDWARE_NAT) +int smart_count=0; +unsigned long smart_count_start_timer; +unsigned int _br0_ip; +unsigned int _br0_mask; +static void get_br0_ip_mask(void) +{ + struct in_device *in_dev; + struct net_device *landev; + struct in_ifaddr *ifap = NULL; + + if ((landev = __dev_get_by_name(&init_net, RTL_PS_BR0_DEV_NAME)) != NULL){ + in_dev=(struct in_device *)(landev->ip_ptr); + if (in_dev != NULL) { + for (ifap=in_dev->ifa_list; ifap != NULL; ifap=ifap->ifa_next) { + if (strcmp(RTL_PS_BR0_DEV_NAME, ifap->ifa_label) == 0){ + _br0_ip = ifap->ifa_address; + _br0_mask = ifap->ifa_mask; + return; + } + } + + } + } +} + +/* return value: + FAILED: ct should be delete + SUCCESS: ct should NOT be delete. +*/ +void rtl_delConnCache(struct nf_conn *ct) +{ + #if defined(CONFIG_RTL_IPTABLES_FAST_PATH) + enum NP_PROTOCOL protocol; + rtl_fp_napt_entry rtlFpNaptEntry; + #endif + #ifdef CONFIG_RTL_HARDWARE_NAT + struct nf_conn_nat *nat; + #endif + + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_TCP) { + #if defined(CONFIG_RTL_IPTABLES_FAST_PATH) + protocol = NP_TCP; + #endif + } else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { + #if defined(CONFIG_RTL_IPTABLES_FAST_PATH) + protocol = NP_UDP; + #endif + } else { + return; + } + + spin_lock_bh(&nf_conntrack_lock); + #if defined(CONFIG_RTL_HARDWARE_NAT) + nat = nfct_nat(ct); + if ((nat!=NULL) && (nat->hw_acc==1)) { + rtl865x_handle_nat(ct, 0, NULL); + } + #endif + + #if defined(CONFIG_RTL_IPTABLES_FAST_PATH) + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip) { + /*case WAN->LAN(BC->AB) use C|A-B*/ + + rtlFpNaptEntry.protocol=protocol; + rtlFpNaptEntry.intIp=ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; + rtlFpNaptEntry.intPort=ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); + rtlFpNaptEntry.extIp=ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip; + rtlFpNaptEntry.extPort=ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all); + rtlFpNaptEntry.remIp=ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; + rtlFpNaptEntry.remPort=ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all); + + #ifdef CONFIG_FAST_PATH_MODULE + if(FastPath_hook4!=NULL) + { + FastPath_hook4(&rtlFpNaptEntry) ; + } + #else + rtk_delNaptConnection(&rtlFpNaptEntry) ; + #endif + } else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) { + /*case LAN->WAN(AB->BC) use A|C-B*/ + + rtlFpNaptEntry.protocol=protocol; + rtlFpNaptEntry.intIp=ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; + rtlFpNaptEntry.intPort=ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all); + rtlFpNaptEntry.extIp=ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; + rtlFpNaptEntry.extPort=ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all); + rtlFpNaptEntry.remIp=ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; + rtlFpNaptEntry.remPort=ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); + + #ifdef CONFIG_FAST_PATH_MODULE + if(FastPath_hook4!=NULL) + { + FastPath_hook4(&rtlFpNaptEntry); + } + #else + rtk_delNaptConnection(&rtlFpNaptEntry); + #endif + } + #endif + spin_unlock_bh(&nf_conntrack_lock); +} + +void rtl_check_for_acc(struct nf_conn *ct, unsigned long expires) +{ + #if defined(CONFIG_RTL_NF_CONNTRACK_GARBAGE_NEW) + int newstate; + struct list_head* state_hash; + + write_lock_bh(&nf_conntrack_lock); + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_TCP) { + newstate = ct->proto.tcp.state; + state_hash = Tcp_State_Hash_Head[newstate].state_hash; + } else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { + if(ct->status & IPS_SEEN_REPLY) + newstate = 1; + else + newstate = 0; + state_hash = Udp_State_Hash_Head[newstate].state_hash; + } else { + write_unlock_bh(&nf_conntrack_lock); + return; + } + + list_move_tail(&ct->state_tuple, state_hash); + write_unlock_bh(&nf_conntrack_lock); + #endif +} + +int32 rtl_connCache_timer_update(struct nf_conn *ct) +{ + spin_lock_bh(&nf_conntrack_lock); + if (time_after_eq(jiffies, ct->timeout.expires)) { + #if defined(CONFIG_RTL_IPTABLES_FAST_PATH) + if (SUCCESS==rtl_fpTimer_update(ct)) { + add_timer(&ct->timeout); + spin_unlock_bh(&nf_conntrack_lock); + return SUCCESS; + } + #endif + + #if defined(CONFIG_RTL_HARDWARE_NAT) + if (SUCCESS==rtl_hwnat_timer_update(ct)) { + add_timer(&ct->timeout); + spin_unlock_bh(&nf_conntrack_lock); + return SUCCESS; + } + #endif + } + spin_unlock_bh(&nf_conntrack_lock); + return FAILED; +} + +#if defined(IMPROVE_QOS) +/* + * ### for iperf application test ### + * the behavior of iperf UDP test is LAN PC (client) will burst UDP from LAN to WAN (by one way), + * WAN PC (server) will only send one UDP packet (statistics) at the end of test. + * so the fastpath or hardware NAT will create link at the end of test. + * + * the purpose for adding the following code is to create fastpath or hardware NAT link + * when we only get one packet from LAN to WAN in UDP case. + */ +static inline int32 rtl_addConnCheck(struct nf_conn *ct, struct iphdr *iph, struct sk_buff *skb) +{ + extern unsigned int _br0_ip; + extern unsigned int _br0_mask; + extern int smart_count; + extern unsigned long smart_count_start_timer; + struct tcphdr *tcph; + uint32 sip, dip; + int32 create_conn; + + sip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; + dip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; + create_conn = FALSE; + + if (((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) || + (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)) + #if defined(UNNUMBER_IP) + && (is_unnumber_ip(dip)==FALSE) + #endif + ) { + /* UDP and "LAN to WAN" */ + /* ignore some cases: + * 1. sip = br0's ip -----> (ex. sip 192.168.1.254 ==> dip 239.255.255.250) + * 2. (sip & br0's mask) != (br0's ip & br0's mask) -----> sip is not in br0's subnet + * 3. (dip & br0's mask) = (br0's ip & br0's mask) -----> dip is in br0's subnet + * 4. dip != multicast IP address + * 5. sip != gip + */ + if (iph->protocol == IPPROTO_UDP) { + if ((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)&& + (sip != _br0_ip) && + ((sip & _br0_mask) == (_br0_ip & _br0_mask)) && + ((dip & _br0_mask) != (_br0_ip & _br0_mask)) && + ((dip & 0xf0000000) != 0xe0000000) && + (sip != (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip))) { + create_conn = TRUE; + } else if ((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)&& + ((sip & _br0_mask) != (_br0_ip & _br0_mask))&& + ((dip & _br0_mask) == (_br0_ip & _br0_mask))&& + (iph->daddr ==dip)) { + create_conn = TRUE; + } + } else if (iph->protocol == IPPROTO_TCP) { + tcph=(void *) iph + iph->ihl*4; + if (!tcph->fin && !tcph->syn && !tcph->rst && tcph->psh==1 && + tcph->ack ==1 && + (((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip==ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) && + (iph->daddr !=_br0_ip) && ((sip & _br0_mask) == (_br0_ip & _br0_mask)) && + ((dip & _br0_mask) != (_br0_ip & _br0_mask)) && (sip != (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)))|| + ((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip==ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip) && + ((sip & _br0_mask) != (_br0_ip & _br0_mask)) && + ((dip & _br0_mask) == (_br0_ip & _br0_mask))&& (sip == iph->saddr)))) { + + if (smart_count==0) { + smart_count_start_timer = jiffies+HZ; + } + + if (time_after(jiffies, smart_count_start_timer)) { + smart_count_start_timer = jiffies+HZ; + smart_count=0; + } + + smart_count++; + if(smart_count >810){ + //panic_printk("the case hit for mart flow:tcp state=%d, assured=%d\n",ct->proto.tcp.state,test_bit(IPS_ASSURED_BIT, &ct->status)); + create_conn=TRUE; + } + } + } else { + return create_conn; + } + +#if defined(UNNUMBER_IP) + if ((!create_conn) + && (is_unnumber_ip(sip)==TRUE)) + ){ + create_conn = TRUE; + } +#endif + } + + return create_conn; +} + +void rtl_addConnCache(struct nf_conn *ct, struct sk_buff *skb) +{ + int assured; + int create_conn; + struct iphdr *iph; + #if defined(CONFIG_RTL_IPTABLES_FAST_PATH) + enum NP_PROTOCOL protocol; + rtl_fp_napt_entry rtlFpNaptEntry; + #endif + + if (nfct_help(ct)) + return; + + iph=ip_hdr(skb); + if (iph->protocol== IPPROTO_TCP) { + assured = ((ct->proto.tcp.state==TCP_CONNTRACK_ESTABLISHED)&& + (test_bit(IPS_DST_NAT_DONE_BIT, &ct->status) || + test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status))); + + #if defined(CONFIG_RTL_IPTABLES_FAST_PATH) + protocol = NP_TCP; + #endif + } else if (iph->protocol== IPPROTO_UDP) { + assured = (test_bit(IPS_DST_NAT_DONE_BIT, &ct->status) || + test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status)); + + #if defined(CONFIG_RTL_IPTABLES_FAST_PATH) + protocol = NP_UDP; + #endif + } else { + return; + } + + + if (!assured) { + create_conn = rtl_addConnCheck(ct, iph, skb); + } else + create_conn = 0; + + #if defined(CONFIG_RTL_IPTABLES_FAST_PATH) + /*1.add "!(ct->helper)" to fix ftp-cmd type packet + 2.add identify case LAN->WAN(AB->BC) or WAN->LAN(BC->AB) + 3.add !(ct->nat.info.helper) for best ALG avoid + */ + if (assured || create_conn) { + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip) { + /*case BC->AB*/ + /* wan->lan */ + + rtlFpNaptEntry.protocol=protocol; + rtlFpNaptEntry.intIp=ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; + rtlFpNaptEntry.intPort=ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); + rtlFpNaptEntry.extIp=ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip; + rtlFpNaptEntry.extPort=ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all); + rtlFpNaptEntry.remIp=ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; + rtlFpNaptEntry.remPort=ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all); + + #ifdef CONFIG_FAST_PATH_MODULE + if(FastPath_hook6!=NULL) + { + FastPath_hook6(&rtlFpNaptEntry, + skb, ct, + NP_NONE); + } + #else + rtk_addNaptConnection(&rtlFpNaptEntry, + skb, ct, + NP_NONE); + #endif + } else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) { + /*case AB->BC*/ + /* lan->wan */ + + rtlFpNaptEntry.protocol=protocol; + rtlFpNaptEntry.intIp=ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; + rtlFpNaptEntry.intPort=ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all); + rtlFpNaptEntry.extIp=ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; + rtlFpNaptEntry.extPort=ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all); + rtlFpNaptEntry.remIp=ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; + rtlFpNaptEntry.remPort=ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); + + #ifdef CONFIG_FAST_PATH_MODULE + if(FastPath_hook6!=NULL) + { + FastPath_hook6(&rtlFpNaptEntry, + skb, ct, + NP_NONE); + } + #else + rtk_addNaptConnection(&rtlFpNaptEntry, + skb, ct, + NP_NONE); + #endif + } + } + #endif + + #if defined(CONFIG_RTL_HARDWARE_NAT) + /*2007-12-19*/ + #if !defined(CONFIG_RTL865x_TCPFLOW_NONE_STATUS_CHECK) + if (assured || create_conn) + #endif + { + rtl865x_handle_nat(ct, 1, skb); + } + #endif +} +#else /* !defined(IMPROVE_QOS) */ +/* + * ### for iperf application test ### + * the behavior of iperf UDP test is LAN PC (client) will burst UDP from LAN to WAN (by one way), + * WAN PC (server) will only send one UDP packet (statistics) at the end of test. + * so the fastpath or hardware NAT will create link at the end of test. + * + * the purpose for adding the following code is to create fastpath or hardware NAT link + * when we only get one packet from LAN to WAN in UDP case. + */ +static int32 rtl_fpAddConnCheck(struct nf_conn *ct, struct iphdr *iph, struct sk_buff *skb) +{ + extern unsigned int _br0_ip; + extern unsigned int _br0_mask; + struct tcphdr *tcph; + uint32 sip, dip; + int32 create_conn; + + sip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; + dip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; + create_conn = FALSE; + + if ((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) + #if defined(UNNUMBER_IP) + && (is_unnumber_ip(dip)==FALSE) + #endif + ) { + /* lan -> wan */ + if (iph->protocol == IPPROTO_UDP && + (sip != _br0_ip) && + ((sip & _br0_mask) == (_br0_ip & _br0_mask)) && + ((dip & _br0_mask) != (_br0_ip & _br0_mask)) && + (!IS_CLASSD_ADDR(dip)) && + (sip != (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)) + ) { + create_conn = TRUE; + /* copied from last 2 line of this function **/ + set_bit(IPS_SEEN_REPLY_BIT, &ct->status); + /* next 3 lines are copied from udp_packet() in ip_conntrack_proto_udp.c */ + nf_ct_refresh(ct,skb, nf_ct_udp_timeout_stream); + /* Also, more likely to be important, and not a probe */ + set_bit(IPS_ASSURED_BIT, &ct->status); + } else if (iph->protocol == IPPROTO_TCP) { + tcph=(void *) iph + iph->ihl*4; + if (!tcph->fin && !tcph->syn && !tcph->rst && tcph->psh==1 && + tcph->ack ==TRUE && (iph->daddr !=_br0_ip) && ((sip & _br0_mask) == (_br0_ip & _br0_mask)) && + ((dip & _br0_mask) != (_br0_ip & _br0_mask)) && (sip != (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip))) { + + if (smart_count==0) { + smart_count_start_timer = jiffies+HZ; + } + + if (time_after(jiffies, smart_count_start_timer)) { + smart_count_start_timer = jiffies+HZ; + smart_count=0; + } + + smart_count++; + if(smart_count >810){ + //panic_printk("the case hit for mart flow:tcp state=%d, assured=%d\n",ct->proto.tcp.state,test_bit(IPS_ASSURED_BIT, &ct->status)); + create_conn=TRUE; + } + } + } else { + return FALSE; + } + +#if defined(UNNUMBER_IP) + if ((!create_conn) + && (is_unnumber_ip(sip)==TRUE)) + ){ + create_conn = TRUE; + } +#endif + } + + return create_conn; +} + +void rtl_fpAddConnCache(struct nf_conn *ct, struct sk_buff *skb) +{ + int assured; + int create_conn; + struct iphdr *iph; + enum NP_PROTOCOL protocol; + rtl_fp_napt_entry rtlFpNaptEntry; + + if (nfct_help(ct)) + return; + + iph=ip_hdr(skb); + create_conn = rtl_fpAddConnCheck(ct, iph, skb); + assured = test_bit(IPS_ASSURED_BIT, &ct->status); + + /*1.add "!(ct->helper)" to fix ftp-cmd type packet + 2.add identify case LAN->WAN(AB->BC) or WAN->LAN(BC->AB) + 3.add !(ct->nat.info.helper) for best ALG avoid + */ + + if ((assured) || (TRUE==create_conn)) + { + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_TCP) { + protocol = NP_TCP; + } else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { + protocol = NP_UDP; + } + + if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip) { + /*case BC->AB*/ + /* wan->lan */ + + rtlFpNaptEntry.protocol=protocol; + rtlFpNaptEntry.intIp=ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; + rtlFpNaptEntry.intPort=ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); + rtlFpNaptEntry.extIp=ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip; + rtlFpNaptEntry.extPort=ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all); + rtlFpNaptEntry.remIp=ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; + rtlFpNaptEntry.remPort=ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all); + + #ifdef CONFIG_FAST_PATH_MODULE + if(FastPath_hook6!=NULL) + { + FastPath_hook6(&rtlFpNaptEntry, + NP_NONE); + } + #else + rtk_addNaptConnection(&rtlFpNaptEntry, + NP_NONE); + #endif + } else if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip + == ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip) { + /*case AB->BC*/ + /* lan->wan */ + + rtlFpNaptEntry.protocol=protocol; + rtlFpNaptEntry.intIp=ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; + rtlFpNaptEntry.intPort=ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all); + rtlFpNaptEntry.extIp=ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; + rtlFpNaptEntry.extPort=ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all); + rtlFpNaptEntry.remIp=ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip; + rtlFpNaptEntry.remPort=ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); + + #ifdef CONFIG_FAST_PATH_MODULE + if(FastPath_hook6!=NULL) + { + FastPath_hook6(&rtlFpNaptEntry, + NP_NONE); + } + #else + rtk_addNaptConnection(&rtlFpNaptEntry, + NP_NONE); + #endif + } + } + +} +#endif /* defined(IMPROVE_QOS) */ + +#endif + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_RTL_HARDWARE_NAT ) +static struct proc_dir_entry *proc_hw_nat=NULL; +static char gHwNatSetting[16]; +//extern unsigned int ldst, lmask, wdst, wmask; + +static int hw_nat_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%s\n", gHwNatSetting); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int hw_nat_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + if (count < 2) + return -EFAULT; + + if (buffer && !copy_from_user(&gHwNatSetting, buffer, 8)) { + if (gHwNatSetting[0] == '0') { /* hardware NAT disabled, operation mode = gateway */ + gHwNatEnabled = 0; + rtl865x_nat_reinit(); + rtl865x_reChangeOpMode(); + //rtl8651_setAsicOperationLayer(4); + } + else if (gHwNatSetting[0] == '1') { /* hardware NAT enabled, operation mode = gateway */ + + rtl865x_changeOpMode(GATEWAY_MODE); + //rtl8651_setAsicOperationLayer(4); + gHwNatEnabled = 1; + } + else if (gHwNatSetting[0] == '2') { /* hardware NAT enabled, operation mode = bridge mode*/ + //rtl865x_delRoute(wdst, wmask); + //rtl865x_delRoute(ldst, lmask); + rtl865x_changeOpMode(BRIDGE_MODE); + //rtl8651_setAsicOperationLayer(3); + gHwNatEnabled = 2; + } + else if(gHwNatSetting[0] == '3'){ /* hardware NAT enabled, operation mode = wisp mode */ + rtl865x_changeOpMode(WISP_MODE); + //rtl8651_setAsicOperationLayer(3); + gHwNatEnabled = 3; + } + else if ((gHwNatSetting[0] == '8')&& + ((gHwNatSetting[1] == '5') /* L2TP */ + ||(gHwNatSetting[1] == '4') /* PPTP */)) + { + gHwNatEnabled = 0; + } + #if defined(CONFIG_RTL_HARDWARE_NAT) || defined(CONFIG_RTL_IPTABLES_FAST_PATH) + else if (gHwNatSetting[0] == '9') { + get_br0_ip_mask(); + } + #endif + return count; + } + return -EFAULT; +} +#endif + +#if defined(CONFIG_RTL_819X) && (defined(CONFIG_PROC_FS) && !defined(CONFIG_RTL_HARDWARE_NAT)) +static struct proc_dir_entry *proc_sw_nat=NULL; +static char gSwNatSetting[16]; + +static int sw_nat_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%s\n", gSwNatSetting); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int sw_nat_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + if (count < 2) + return -EFAULT; + + if (buffer && !copy_from_user(&gSwNatSetting, buffer, 8)) { + if (gSwNatSetting[0] == '0'){ /* operation mode = GATEWAY */ + //SoftNAT_OP_Mode(2); + rtl865x_changeOpMode(GATEWAY_MODE); + //rtl8651_setAsicOperationLayer(2); + } + else if (gSwNatSetting[0] == '1'){ /* operation mode = BRIDGE*/ + //SoftNAT_OP_Mode(1); + rtl865x_changeOpMode(BRIDGE_MODE); + //rtl8651_setAsicOperationLayer(2); + } + else if(gSwNatSetting[0] == '2'){ /* operation mode = WISP */ + rtl865x_changeOpMode(WISP_MODE); + //rtl8651_setAsicOperationLayer(2); + } +#if defined(CONFIG_RTL_HARDWARE_NAT) || defined(CONFIG_RTL_IPTABLES_FAST_PATH) + else if(gSwNatSetting[0] == '9'){ + get_br0_ip_mask(); + } +#endif + return count; + } + return -EFAULT; +} +#endif /* defined(CONFIG_RTL_819X) && (defined(CONFIG_PROC_FS) && !defined(CONFIG_RTL_HARDWARE_NAT)) */ + +#if defined(CONFIG_RTL_819X) +int32 rtl_nat_init(void) +{ + #if defined(CONFIG_PROC_FS) && defined(CONFIG_RTL_HARDWARE_NAT) + proc_hw_nat = create_proc_entry("hw_nat", 0, NULL); + if (proc_hw_nat) { + proc_hw_nat->read_proc = hw_nat_read_proc; + proc_hw_nat->write_proc = hw_nat_write_proc; + } + #endif + + #if defined(CONFIG_PROC_FS) && !defined(CONFIG_RTL_HARDWARE_NAT) + proc_sw_nat = create_proc_entry("sw_nat", 0, NULL); + if (proc_sw_nat) { + proc_sw_nat->read_proc = sw_nat_read_proc; + proc_sw_nat->write_proc = sw_nat_write_proc; + } + #endif + + #if defined(CONFIG_RTL_HARDWARE_NAT) + gHwNatEnabled=1; + #endif + + return SUCCESS; +} +#endif + +#if defined(CONFIG_RTL_LOCAL_PUBLIC) || defined(CONFIG_RTL_MULTIPLE_WAN) || (defined(CONFIG_NET_SCHED)&&defined(CONFIG_RTL_IPTABLES_FAST_PATH)) +extern int rtl865x_curOpMode; +struct net_device *rtl865x_getWanDev(void ) +{ + struct net_device * wanDev=NULL; + + if(rtl865x_curOpMode==GATEWAY_MODE) + { +#if defined(CONFIG_RTL_PUBLIC_SSID) + wanDev=dev_get_by_name(&init_net,RTL_GW_WAN_DEVICE_NAME); +#else + //Try ppp0 first + wanDev=dev_get_by_name(&init_net,RTL_PS_PPP0_DEV_NAME); + if(wanDev==NULL) + { + //Try eth1 then + wanDev=dev_get_by_name(&init_net,RTL_PS_WAN0_DEV_NAME); + } +#endif + } + else if(rtl865x_curOpMode==WISP_MODE) + { +#if defined(CONFIG_RTL_PUBLIC_SSID) + wanDev=dev_get_by_name(&init_net,RTL_WISP_WAN_DEVICE_NAME); +#else + wanDev=dev_get_by_name(&init_net,RTL_PS_WLAN0_DEV_NAME); +#endif + } + else if(rtl865x_curOpMode==BRIDGE_MODE) + { +#if defined(CONFIG_RTL_PUBLIC_SSID) + wanDev=dev_get_by_name(&init_net,RTL_BR_WAN_DEVICE_NAME); +#else + wanDev=dev_get_by_name(&init_net,RTL_PS_BR0_DEV_NAME); +#endif + } + + return wanDev; +} + +struct net_device *rtl865x_getLanDev(void ) +{ + struct net_device * lanDev=NULL; + lanDev=dev_get_by_name(&init_net,RTL_PS_BR0_DEV_NAME); + return lanDev; +} +#endif + +#if defined (CONFIG_RTL_LOCAL_PUBLIC) || defined(CONFIG_RTL_HW_QOS_SUPPORT) +int rtl865x_attainDevType(unsigned char *devName, unsigned int *isLanDev, unsigned int *isWanDev) +{ + *isLanDev=0; + *isWanDev=0; + if(rtl865x_curOpMode==GATEWAY_MODE) + { +#if defined(CONFIG_RTL_PUBLIC_SSID) + if(strncmp(devName, RTL_PS_WAN0_DEV_NAME, 4) ==0 || strncmp(devName, RTL_GW_WAN_DEVICE_NAME, 3) ==0 || + rtl865x_from_public_ssid_device(devName) + ) +#else + if(strncmp(devName, RTL_PS_WAN0_DEV_NAME, 4) ==0) +#endif + { + *isWanDev=1; + } + else if( (strncmp(devName, RTL_PS_BR0_DEV_NAME, 3) ==0)|| + (strncmp(devName, RTL_PS_ETH_NAME, 3) ==0) || + (strncmp(devName, RTL_PS_WLAN_NAME, 4) ==0)) + { + *isLanDev=1; + } + else + { + return -1; + } + + } + else if(rtl865x_curOpMode==WISP_MODE) + { + if(strncmp(devName, RTL_PS_WAN0_DEV_NAME, 4)==0) + { + *isWanDev=1; + } + else if( (strncmp(devName, RTL_PS_BR0_DEV_NAME, 3) ==0) || + (strncmp(devName, RTL_PS_ETH_NAME, 3) ==0)) + { + *isLanDev=1; + } + else + { + return -1; + } + } + else if(rtl865x_curOpMode==BRIDGE_MODE) + { + if( (strncmp(devName, RTL_PS_BR0_DEV_NAME, 3) ==0) || + (strncmp(devName, RTL_PS_ETH_NAME, 3) ==0) || + (strncmp(devName, RTL_PS_WLAN_NAME, 4) ==0)) + { + *isLanDev=0; + } + else + { + return -1; + } + } + else + { + return -1; + } + + return 0; +} +#endif + +#if defined (CONFIG_RTL_LOCAL_PUBLIC) +int rtl865x_localPublicRx(struct sk_buff *skb) +{ + struct rtl865x_pktInfo pktInfo; + unsigned int rxFromLan, rxFromWan; + + if(rtl865x_localPublicEnabled() ==0) + { + goto end_of_local_public_rx; + } + + if(rtl865x_attainDevType(skb->dev->name, &rxFromLan, &rxFromWan)) + { + return NET_RX_SUCCESS; + } + + if(skb->localPublicFlags == 0x1) + { + //local public has done + return NET_RX_SUCCESS; + } + #if 0 + printk("%s:%d,skb->dev->name is %s,rxFromLan is %d,rxFromWan is %d\n",__FUNCTION__,__LINE__,skb->dev->name,rxFromLan,rxFromWan); + printk("EtherType: 0x%x\n", *((uint16*)&skb->mac.raw[12])); + printk("%x:%x:%x:%x:%x:%x ==> %x:%x:%x:%x:%x:%x \n\n", + skb->mac.raw[6], skb->mac.raw[7], skb->mac.raw[8], + skb->mac.raw[9], skb->mac.raw[10], skb->mac.raw[11], + skb->mac.raw[0], skb->mac.raw[1], skb->mac.raw[2], + skb->mac.raw[3], skb->mac.raw[4], skb->mac.raw[5]); + #endif + if(rxFromWan) + { + /*rx from ethernet wan*/ + /*direction WAN--->LAN*/ + //pktInfo.data=skb->mac.raw; + pktInfo.data=skb_mac_header(skb); + pktInfo.action=RX_WAN_PACKET; + rtl865x_checkLocalPublic(&pktInfo); + + if(pktInfo.fromLocalPublic==1) + { + kfree_skb(skb); + return NET_RX_DROP; + } + else if(pktInfo.toLocalPublic==1) + { + + skb->pkt_type=PACKET_HOST; + //printk("%s:%d,pktInfo.fromLocalPublic is %d,pktInfo.toLocalPublic is %d\n",__FUNCTION__,__LINE__,pktInfo.fromLocalPublic,pktInfo.toLocalPublic ); + memcpy(eth_hdr(skb)->h_dest, skb->dev->dev_addr, 6); + } + + } + else if (rxFromLan) + { + /*rx from ethernet lan*/ + pktInfo.data=skb_mac_header(skb); + pktInfo.port=skb->srcPort; + pktInfo.action=RX_LAN_PACKET; + strcpy(pktInfo.dev, skb->dev->name); + rtl865x_checkLocalPublic(&pktInfo); + //printk("%s:%d,pktInfo.fromLocalPublic is %d,pktInfo.toLocalPublic is %d\n",__FUNCTION__,__LINE__,pktInfo.fromLocalPublic,pktInfo.toLocalPublic ); + if(pktInfo.fromLocalPublic==1) + { + skb->fromLocalPublic=1; + skb->srcLocalPublicIp=pktInfo.srcIp; + //if(pktInfo.toLocalPublic==1) + { + skb->pkt_type=PACKET_HOST; + memcpy(eth_hdr(skb)->h_dest, skb->dev->dev_addr, 6); + #if 0 + dest = eth_hdr(skb)->h_dest; + src = eth_hdr(skb)->h_source; + printk("=========%s(%d),dst(%x:%x:%x:%x:%x:%x),src(%x:%x:%x:%x:%x:%x)\n",__FUNCTION__,__LINE__, + dest[0],dest[1],dest[2],dest[3],dest[4],dest[5], + src[0],src[1],src[2],src[3],src[4],src[5]); + #endif + + } + } + + } + skb->localPublicFlags = 0x1; + +end_of_local_public_rx: + return NET_RX_SUCCESS; +} + +int rtl865x_localPublicTx(struct sk_buff *skb, struct net_device *dev) +{ + unsigned int txToLan, txToWan; + if(rtl865x_attainDevType(skb->dev->name, &txToLan, &txToWan)) + { + return NET_RX_SUCCESS; + } + + if(txToWan) + { + if((skb->fromLocalPublic==1) && (skb->srcLocalPublicIp!=0)) + { + rtl865x_getLocalPublicMac(skb->srcLocalPublicIp, eth_hdr(skb)->h_source); + } + + } + else if (txToLan) + { + /*needn't do anything*/ + + } + return NET_RX_SUCCESS; +} + +#endif + +int rtl865x_getDevIpAndNetmask(struct net_device * dev, unsigned int *ipAddr, unsigned int *netMask ) +{ + struct in_device *in_dev; + struct in_ifaddr *ifap = NULL; + + if((dev==NULL) || (ipAddr==NULL) || (netMask==NULL)) + { + return FAILED; + } + + *ipAddr=0; + *netMask=0; + + in_dev=(struct net_device *)(dev->ip_ptr); + if (in_dev != NULL) { + for (ifap=in_dev->ifa_list; ifap != NULL; ifap=ifap->ifa_next) { + if (strcmp(dev->name, ifap->ifa_label) == 0){ + *ipAddr = ifap->ifa_address; + *netMask = ifap->ifa_mask; + return SUCCESS; + } + } + + } + + return FAILED; + +} + + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_NET_SCHED) +#define QOS_CLASSIFY_INFO_LEN 16 +typedef struct { + /* classify */ + unsigned int protocol; + struct in_addr local_ip; + struct in_addr remote_ip; + unsigned short lo_port; + unsigned short re_port; + + /* tc */ + uint32 mark; + unsigned char prio; +} rtl865x_qos_cache_t; + +static struct proc_dir_entry *proc_qos=NULL; + +static char *gQosSetting = NULL; +#ifdef CONFIG_FAST_PATH_MODULE +EXPORT_SYMBOL(gQosEnabled); +#endif + +static int qos_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%s\n", gQosSetting); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int qos_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + if ( gQosSetting==NULL || count < 2) + return -EFAULT; + + if (buffer && !copy_from_user(gQosSetting, buffer, count)) { + gQosSetting[count-1] = 0; /* remove 0x0a */ + if (gQosSetting[0] == '0') + gQosEnabled = 0; + else + gQosEnabled = 1; + +#if defined (CONFIG_RTL_HW_QOS_SUPPORT) && defined(CONFIG_RTL_QOS_PATCH) + if(gQosEnabled == 1){ + rtl865x_reinitOutputQueuePatchForQoS(TRUE); + } + else{ + rtl865x_reinitOutputQueuePatchForQoS(FALSE); + } +#endif + + return count; + } + return -EFAULT; +} +#endif + +#if defined(CONFIG_NET_SCHED) +#define RTL_QOS_PROC_MAX_LEN 1024 +int32 rtl_qos_init(void) +{ + #if defined(CONFIG_PROC_FS) + proc_qos = create_proc_entry("qos", 0, NULL); + if (proc_qos) { + proc_qos->read_proc = qos_read_proc; + proc_qos->write_proc = qos_write_proc; + } + #endif + gQosSetting = kmalloc(RTL_QOS_PROC_MAX_LEN, GFP_KERNEL); + memset(gQosSetting, 0, RTL_QOS_PROC_MAX_LEN); + gQosEnabled = 0; + + return SUCCESS; +} + +int32 rtl_qos_cleanup(void) +{ + kfree(gQosSetting); + + return SUCCESS; +} +#endif + + +#if defined(CONFIG_RTL_FAST_BRIDGE) +int32 rtl_fb_add_br_entry(skb) +{ + struct net_bridge_fdb_entry *dst; + const unsigned char *dest = eth_hdr(skb)->h_dest; + if (!is_multicast_ether_addr(dest)) + { + dst = __br_fdb_get(skb->dev->br_port->br, dest); + if(dst != NULL && dst->dst->dev == skb->dev) + { + fast_br_cache_entry entry; + memset(&entry,0,sizeof(fast_br_cache_entry)); + memcpy(&entry.mac_addr,dest,6); + entry.ageing_timer = jiffies; + entry.to_dev = skb->dev; + entry.valid = 1; + + rtl_add_fast_br_entry(&entry); + } + } +} +#endif + +#if defined(FAST_PATH_SPI_ENABLED) +enum tcp_bit_set { + TCP_SYN_SET, + TCP_SYNACK_SET, + TCP_FIN_SET, + TCP_ACK_SET, + TCP_RST_SET, + TCP_NONE_SET, +}; + +static unsigned int rtl_spi_get_conntrack_index(const struct tcphdr *tcph) + { + if (tcph->rst) return TCP_RST_SET; + else if (tcph->syn) return (tcph->ack ? TCP_SYNACK_SET : TCP_SYN_SET); + else if (tcph->fin) return TCP_FIN_SET; + else if (tcph->ack) return TCP_ACK_SET; + else return TCP_NONE_SET; + } + +extern bool tcp_in_window(const struct nf_conn *ct, + struct ip_ct_tcp *state, + enum ip_conntrack_dir dir, + unsigned int index, + const struct sk_buff *skb, + unsigned int dataoff, + const struct tcphdr *tcph, + u_int8_t pf); + +static inline struct nf_conn * +rtl_resolve_normal_ct(struct net *net, + struct sk_buff *skb, + unsigned int dataoff, + u_int16_t l3num, + u_int8_t protonum, + struct nf_conntrack_l3proto *l3proto, + struct nf_conntrack_l4proto *l4proto, + int *set_reply, + enum ip_conntrack_info *ctinfo) +{ + struct nf_conntrack_tuple tuple; + struct nf_conntrack_tuple_hash *h; + struct nf_conn *ct; + + if (!nf_ct_get_tuple(skb, skb_network_offset(skb), + dataoff, l3num, protonum, &tuple, l3proto, + l4proto)) { + pr_debug("resolve_normal_ct: Can't get tuple\n"); + return NULL; + } + + /* look for tuple match */ + h = nf_conntrack_find_get(net, &tuple); + + if (!h) { + //h = init_conntrack(net, &tuple, l3proto, l4proto, skb, dataoff); + //if (!h) + return NULL; + //if (IS_ERR(h)) + // return (void *)h; + } + ct = nf_ct_tuplehash_to_ctrack(h); + + /* It exists; we have (non-exclusive) reference. */ + if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) { + *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY; + } else { + /* Once we've had two way comms, always ESTABLISHED. */ + if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { + pr_debug("nf_conntrack_in: normal packet for %p\n", ct); + *ctinfo = IP_CT_ESTABLISHED; + } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) { + pr_debug("nf_conntrack_in: related packet for %p\n", + ct); + *ctinfo = IP_CT_RELATED; + } else { + pr_debug("nf_conntrack_in: new packet for %p\n", ct); + *ctinfo = IP_CT_NEW; + } + } + skb->nfct = &ct->ct_general; + skb->nfctinfo = *ctinfo; + return ct; +} + + +unsigned int +rtl_nf_conntrack_in(struct net *net, unsigned int dataoff, unsigned int hooknum, + struct sk_buff *skb) +{ + struct nf_conn *ct; + enum ip_conntrack_info ctinfo; + struct nf_conntrack_l3proto *l3proto; + struct nf_conntrack_l4proto *l4proto; + int set_reply = 0; + enum ip_conntrack_dir dir; + const struct tcphdr *th; + struct tcphdr _tcph; + unsigned int index; + + + /* Previously seen (loopback or untracked)? Ignore. */ + if (skb->nfct) { + NF_CT_STAT_INC_ATOMIC(net, ignore); + return NF_ACCEPT; + } + + + /* rcu_read_lock()ed by nf_hook_slow */ + l3proto = rcu_dereference(nf_ct_l3protos[PF_INET]); + + l4proto = rcu_dereference(nf_ct_protos[PF_INET][IPPROTO_TCP]); + + ct = rtl_resolve_normal_ct(net, skb, dataoff, PF_INET, IPPROTO_TCP, + l3proto, l4proto, &set_reply, &ctinfo); + + if (!ct) { + /* Not valid part of a connection */ + return NF_ACCEPT; + } + + if (IS_ERR(ct)) { + /* Too stressed to deal. */ + return NF_DROP; + } + + NF_CT_ASSERT(skb->nfct); + + + th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); + BUG_ON(th == NULL); + + dir = CTINFO2DIR(ctinfo); + + index = rtl_spi_get_conntrack_index(th); + + NF_CT_ASSERT(skb->nfct); + + if (!tcp_in_window(ct, &ct->proto.tcp, dir, index, + skb, dataoff, th, PF_INET)) { + return NF_DROP; + } + return NF_ACCEPT; + +} +#endif + +#if defined(CONFIG_RTL_IPTABLES_RULE_2_ACL) || defined(CONFIG_RTL_HARDWARE_NAT) +/*get the chain number of the ipt_entry*/ +int get_hookNum(struct ipt_entry *e, unsigned char *base, const unsigned int valid_hooks,const unsigned int *hook_entries) +{ + int h; + unsigned int offset = 0; + int hook_num = -1; + + offset = (void *)e - (void *)base; + for(h = 0; h < NF_INET_NUMHOOKS; h++) + { + if(!(valid_hooks & (1 << h))) + continue; + + if(offset >= hook_entries[h]) + hook_num = h; + } + + return hook_num; +} +#endif + +#if defined(CONFIG_RTL_HARDWARE_NAT) +/*2007-12-19*/ + int syn_asic_arp(struct neighbour *n, int add) +{ +#ifdef CONFIG_RTL_LAYERED_DRIVER_L3 + u32 arp_ip = htonl(*((u32 *)n->primary_key)); + int rc; + + rc = add? rtl865x_addArp(arp_ip, (void *)n->ha): rtl865x_delArp(arp_ip); +#endif + return 0; +} + +#if defined(CONFIG_RTL_MULTIPLE_WAN) +int rtl_get_ps_arp_mapping(u32 ip, void *arp_entry_tmp) +{ + rtl865x_arpMapping_entry_t *arp_entry; + struct neighbour *dst_n; + struct net_device *wanDev; + wanDev=rtl865x_getWanDev(); + + if(wanDev == NULL) + return FAILED; + + arp_entry = (rtl865x_arpMapping_entry_t*)arp_entry_tmp; + + dst_n = neigh_lookup(&arp_tbl,&ip,wanDev); + dev_put(wanDev); + if(dst_n != NULL) + { + arp_entry->ip = ip; + memcpy(arp_entry->mac.octet,dst_n->ha,ETHER_ADDR_LEN); + return SUCCESS; + } + + return FAILED; +} +#endif + +rtl_masq_if rtl_masq_info[RTL_MULTIPLE_WAN_NUM]; + +rtl_masq_if *rtl_get_masq_info_by_devName(const char* name) +{ + int i; + if(name == NULL) + return NULL; + + for(i = 0; i < RTL_MULTIPLE_WAN_NUM;i++) + { + if(rtl_masq_info[i].valid == 1 &&strcmp(rtl_masq_info[i].ifName,name) == 0) + return &rtl_masq_info[i]; + } + + return NULL; +} + +int rtl_add_masq_info(const char *name,int ipAddr) +{ + int i; + if(strlen(name) >=IFNAMSIZ || ipAddr ==0) + return FAILED; + + for(i = 0; i < RTL_MULTIPLE_WAN_NUM;i++) + { + if(rtl_masq_info[i].valid == 0) + break; + } + + if(i == RTL_MULTIPLE_WAN_NUM) + return FAILED; + + rtl_masq_info[i].valid = 1; + rtl_masq_info[i].ipAddr = ipAddr; + memcpy(rtl_masq_info[i].ifName,name,strlen(name)); + rtl_masq_info[i].ifName[strlen(name)] ='\0'; + return SUCCESS; +} + +int rtl_init_masq_info(void) +{ + int i; + for(i = 0; i < RTL_MULTIPLE_WAN_NUM;i++) + { + memset(&rtl_masq_info[i],0,sizeof(rtl_masq_if)); + } + + return SUCCESS; +} + +/* Performance critical */ +static inline struct ipt_entry * +get_entry(void *base, unsigned int offset) +{ + return (struct ipt_entry *)(base + offset); +} + +#ifdef CONFIG_NETFILTER_DEBUG +#define IP_NF_ASSERT(x) \ +do { \ + if (!(x)) \ + printk("IP_NF_ASSERT: %s:%s:%u\n", \ + __func__, __FILE__, __LINE__); \ +} while(0) +#else +#define IP_NF_ASSERT(x) +#endif + +static int rtl_get_masquerade_netif(struct xt_table_info *private,struct ipt_entry *masq_entry) +{ + void *table_base; + struct ipt_entry *e, *back; + struct ipt_entry_target *t; + struct net_device *dev; + char masq_name[IFNAMSIZ]={'\0'}; + + if(masq_entry && masq_entry->ip.outiface[0] !='\0') + { + memcpy(masq_name, masq_entry->ip.outiface, IFNAMSIZ); + //return 0; + } + else + { + table_base = private->entries[smp_processor_id()]; + e = get_entry(table_base, private->hook_entry[NF_INET_POST_ROUTING]); + back = get_entry(table_base, private->underflow[NF_INET_POST_ROUTING]); + + //clear masq_name; + memset(masq_name,0,IFNAMSIZ); + while(e) + { + + if(e == masq_entry) + break; + + //record the entry's outif name + if(e->ip.outiface[0] !='\0') + memcpy(masq_name,e->ip.outiface,IFNAMSIZ); + + //target + t = ipt_get_target(e); + IP_NF_ASSERT(t->u.kernel.target); + + + //if error target + if(strcmp(t->u.kernel.target->name, "ERROR") == 0) + { + memset(masq_name,0,IFNAMSIZ); + break; + } + + /* Standard target? */ + if (!t->u.kernel.target->target) + { + int v; + v = ((struct ipt_standard_target *)t)->verdict; + + if (v < 0 ) + { + if(v == IPT_RETURN) + { + e = back; + back = get_entry(table_base, back->comefrom); + } + else + { + e = (void *)e + e->next_offset; + } + + continue; + } + + //jump ? + if (table_base + v != (void *)e + e->next_offset + && !(e->ip.flags & IPT_F_GOTO)) { + /* Save old back ptr in next entry */ + struct ipt_entry *next + = (void *)e + e->next_offset; + next->comefrom + = (void *)back - table_base; + /* set back pointer to next entry */ + back = next; + } + e = get_entry(table_base, v); + continue; + } + + /*user define target?*/ + e = (void *)e + e->next_offset; + } + + } + + if(masq_name[0] !='\0') + { + struct in_ifaddr *ina; + dev = __dev_get_by_name(&init_net,masq_name); + if ((dev)&&(dev->ip_ptr)) + { + + ina=(struct in_ifaddr *)(((struct in_device *)(dev->ip_ptr))->ifa_list); + if (ina!=NULL) + { + rtl_add_masq_info(masq_name,ina->ifa_local); + } + } + } + + + return 0; +} + +static int rtl_check_for_masquerade_entry(struct ipt_entry *e, + unsigned char *base, + const char *name, + unsigned int size, + const unsigned int valid_hooks, + const unsigned int *hook_entries, + struct xt_table_info *private) +{ + struct ipt_entry_target *t; + unsigned int hook; + int ret = 0; + + t = ipt_get_target(e); + if ( !t) + { + goto err; + } + + hook = get_hookNum(e,base,valid_hooks,hook_entries); + if ((hook == NF_INET_POST_ROUTING) && + ((strcmp(t->u.kernel.target->name, "MASQUERADE") == 0))) + { + rtl_get_masquerade_netif(private,e); + } + err: + return ret; +} + +int rtl_check_for_extern_ip(const char *name, + unsigned int valid_hooks, + struct xt_table_info *newinfo, + void *entry0, + unsigned int size, + unsigned int number, + const unsigned int *hook_entries, + const unsigned int *underflows) +{ + int i; + IPT_ENTRY_ITERATE(entry0, size,rtl_check_for_masquerade_entry, entry0,name,size,valid_hooks,hook_entries,newinfo); + + //found masq entry + for(i = 0; i < RTL_MULTIPLE_WAN_NUM;i++) + { + if(rtl_masq_info[i].valid == 1 && rtl_masq_info[i].ipAddr) + { + rtl865x_addIp(0,rtl_masq_info[i].ipAddr,IP_TYPE_NAPT); + } + } + + return 0; +} + + int rtl_flush_extern_ip(void) +{ + int i; + for(i = 0; i < RTL_MULTIPLE_WAN_NUM;i++) + { + if(rtl_masq_info[i].valid == 1) + { + //delete.... + rtl865x_delIp(rtl_masq_info[i].ipAddr); + } + } + + return SUCCESS; +} + +int32 rtl_update_ip_tables(char *name, unsigned long event, struct in_ifaddr *ina) +{ + rtl_masq_if *entry; + + /*2007-12-19*/ + #ifdef CONFIG_HARDWARE_NAT_DEBUG + /*2007-12-19*/ + printk("%s:%d\n",__FUNCTION__,__LINE__); + #endif + if (ina==NULL) + return SUCCESS; + + entry = rtl_get_masq_info_by_devName(name); + if (entry!=NULL) + { + if (event == NETDEV_UP ) + { + rtl865x_addIp(0,(u32)(ina->ifa_local),IP_TYPE_NAPT); + //update the ip address + entry->ipAddr = ina->ifa_local; + } + else if(event == NETDEV_DOWN) + { + if(rtl865x_delIp(ina->ifa_local)==SUCCESS) + { + rtl865x_nat_init(); + } + } + } + + return SUCCESS; +} + +int32 rtl_fn_insert(struct fib_table *tb, struct fib_config *cfg, struct fib_info *fi) +{ + int rc; + unsigned int ipDst, ipMask, ipGw; + unsigned int srcIp,srcMask; + struct net_device *netif; + char *dev_t; + + /*2007-12-19*/ + if ((tb->tb_id == RT_TABLE_MAIN) && (gHwNatEnabled !=0)) { + if(cfg->fc_oif) { + netif = __dev_get_by_index(&init_net,cfg->fc_oif); + } else { + netif=NULL; + } + + dev_t = (netif)? netif->name: NULL; + ipDst = cfg->fc_dst ; + ipMask = inet_make_mask(cfg->fc_dst_len); + ipGw = cfg->fc_gw; + rtl865x_getDevIpAndNetmask(netif,&srcIp,&srcMask); + if (!ipDst || (!MULTICAST(ipDst) && !LOOPBACK(ipDst) && (ipDst != 0xffffffff))) + { + #ifdef CONFIG_RTL_LAYERED_DRIVER_L3 + //printk("-------------------%s(%d)\n",__FUNCTION__,__LINE__); + rc = rtl865x_addRoute(ipDst,ipMask,ipGw,dev_t,srcIp); + //printk("-------------------%s(%d),rc(%d)\n",__FUNCTION__,__LINE__,rc); + #endif + #ifdef CONFIG_HARDWARE_NAT_DEBUG + /*2007-12-19*/ + printk("%s:%d:(%s): dst:%u.%u.%u.%u/%u, gw:%u.%u.%u.%u, dev: %s, errno=%d\n", + __FUNCTION__,__LINE__,"add_rt", NIPQUAD(ipDst), cfg->fc_dst_len, NIPQUAD(ipGw), dev_t? dev_t: "null", rc + ); + #endif + + } + } + + return SUCCESS; +} + +int32 rtl_fn_delete(struct fib_table *tb, struct fib_config *cfg) +{ + int rc; + unsigned int ipDst, ipMask; + + /*2007-12-19*/ + if (tb->tb_id == RT_TABLE_MAIN) { + ipDst = cfg->fc_dst; + ipMask = inet_make_mask(cfg->fc_dst_len); + + if (!ipDst || (!MULTICAST(ipDst) && !LOOPBACK(ipDst) && (ipDst != 0xffffffff))) { + rc = 0; + #ifdef CONFIG_RTL_LAYERED_DRIVER_L3 + rc = rtl865x_delRoute(ipDst, ipMask); + #endif + } + } + + return SUCCESS; +} + +int32 rtl_fn_flush(int fz_order, int idx, u32 tb_id, u32 fn_key) +{ + int rc; + unsigned int ipDst, ipMask; + /*2007-12-19*/ + if (tb_id==RT_TABLE_MAIN) { + ipDst =fn_key; + ipMask = inet_make_mask(fz_order); + + if (!ipDst || (!MULTICAST(ipDst) && !LOOPBACK(ipDst) && (ipDst != 0xffffffff))) { + rc = 0; + #ifdef CONFIG_RTL_LAYERED_DRIVER_L3 + rc = rtl865x_delRoute(ipDst, ipMask); + #endif + } + } + + return SUCCESS; +} + +int32 rtl_ip_vs_conn_expire_check(struct ip_vs_conn *cp) +{ + int timeval; + rtl865x_napt_entry rtl865xNaptEntry; + +/* chhuang: + printk("ip_vs_conn_expire: c:(%u.%u.%u.%u:%d), v:(%u.%u.%u.%u:%d), \n\td:(%u.%u.%u.%u:%d), p:(%x), f: %x, s: %x\n", + NIPQUAD(cp->caddr), cp->cport, NIPQUAD(cp->vaddr), cp->vport, NIPQUAD(cp->daddr), cp->dport, + cp->protocol, cp->flags, cp->state); +*/ + if (cp->hw_acc) { + rtl865xNaptEntry.protocol=((cp->protocol==IPPROTO_TCP)? 1: 0); + rtl865xNaptEntry.intIp=cp->daddr.ip; + rtl865xNaptEntry.intPort=cp->dport; + rtl865xNaptEntry.extIp=cp->vaddr.ip; + rtl865xNaptEntry.extPort=cp->vport; + rtl865xNaptEntry.remIp=cp->caddr.ip; + rtl865xNaptEntry.remPort=cp->cport; + + timeval = rtl865x_naptSync(&rtl865xNaptEntry, 0); + + if (timeval > 0 && (cp->protocol==IPPROTO_UDP)) + { + cp->timer.expires = jiffies + (timeval)*HZ; + add_timer(&cp->timer); + #ifdef CONFIG_HARDWARE_NAT_DEBUG + /*2007-12-19*/ + printk("%s:%d:(%s): expired time = %d\n %s (%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u) g:(%u.%u.%u.%u:%u)\n", + __FUNCTION__,__LINE__,"poll_nat", timeval, (cp->protocol==IPPROTO_TCP)? "tcp": "udp", + NIPQUAD(cp->daddr), cp->dport, NIPQUAD(cp->caddr), cp->cport, + NIPQUAD(cp->vaddr), cp->vport + ); + #endif + + return FAILED; + } + } + + return SUCCESS; +} + + +int32 rtl_ip_vs_conn_expire_check_delete(struct ip_vs_conn *cp) +{ + rtl865x_napt_entry rtl865xNaptEntry; + + if (cp->hw_acc) { + int rc; + + rtl865xNaptEntry.protocol=((cp->protocol==IPPROTO_TCP)? 1: 0); + rtl865xNaptEntry.intIp=cp->daddr.ip; + rtl865xNaptEntry.intPort=cp->dport; + rtl865xNaptEntry.extIp=cp->vaddr.ip; + rtl865xNaptEntry.extPort=cp->vport; + rtl865xNaptEntry.remIp=cp->caddr.ip; + rtl865xNaptEntry.remPort=cp->cport; + + rc = rtl865x_delNaptConnection(&rtl865xNaptEntry); + + #ifdef CONFIG_HARDWARE_NAT_DEBUG + /*2007-12-19*/ + printk("%s:%d:(%s): errno=%d\n %s (%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u) g:(%u.%u.%u.%u:%u)\n", + __FUNCTION__,__LINE__,"del_nat", rc, (cp->protocol==IPPROTO_TCP)? "tcp": "udp", + NIPQUAD(cp->daddr.ip), cp->dport, NIPQUAD(cp->caddr.ip), cp->cport, + NIPQUAD(cp->vaddr.ip), cp->vport + ); + #endif + } + + return SUCCESS; +} + +int32 rtl_tcp_state_transition_check(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb, struct ip_vs_protocol *pp) +{ + #if defined(CONFIG_RTL_HW_QOS_SUPPORT) + uint32 ret; + struct net_device *lanDev, *wanDev; + #endif + + #if defined(CONFIG_RTL_LAYERED_DRIVER_L4) + rtl865x_napt_entry rtl865xNaptEntry; + rtl865x_priority rtl865xPrio; + rtl865x_qos_mark rtl865xQosMark; + #endif + + /*2007-12-19*/ + /* + printk("ip_vs_set_state: c:(%u.%u.%u.%u:%d), v:(%u.%u.%u.%u:%d), \n\td:(%u.%u.%u.%u:%d), p:(%x), f: %x, s: %x, master: %s\n\tapp_data: %x, app: %x\n", + NIPQUAD(cp->caddr), cp->cport, NIPQUAD(cp->vaddr), cp->vport, NIPQUAD(cp->daddr), cp->dport, cp->protocol, cp->flags, cp->state, + cp->control? "yes": "no", cp->app_data, cp->app); + */ + #if 0 + if (!cp->hw_acc && !cp->app && + cp->state==IP_VS_S_ESTABLISHED) + #else + if (!cp->hw_acc && !cp->app && + cp->state==IP_VS_TCP_S_ESTABLISHED) + #endif + { + int rc; + rc = 0; + + #if defined(CONFIG_RTL_HW_QOS_SUPPORT) + if (NULL!=skb) + { + rtl865xNaptEntry.protocol=RTL865X_PROTOCOL_TCP; + rtl865xNaptEntry.intIp=cp->daddr.ip; + rtl865xNaptEntry.intPort=cp->dport; + rtl865xNaptEntry.extIp=cp->vaddr.ip; + rtl865xNaptEntry.extPort=cp->vport; + rtl865xNaptEntry.remIp=cp->caddr.ip; + rtl865xNaptEntry.remPort=cp->cport; + + rtl865xQosMark.downlinkMark=0; //Initial + rtl865xQosMark.uplinkMark=0; //Initial + ret=rtl_qosGetSkbMarkByNaptEntry(&rtl865xNaptEntry, &rtl865xQosMark, skb); + + lanDev=rtl865x_getLanDev(); + wanDev=rtl865x_getWanDev(); + rtl865xPrio.downlinkPrio=rtl_qosGetPriorityByMark(lanDev->name, rtl865xQosMark.downlinkMark); + rtl865xPrio.uplinkPrio=rtl_qosGetPriorityByMark(wanDev->name, rtl865xQosMark.uplinkMark); + + if(lanDev) + dev_put(lanDev); + + if(wanDev) + dev_put(wanDev); + }else + #endif + { + rtl865xPrio.downlinkPrio=0; + rtl865xPrio.uplinkPrio=0; + } + + #if defined(CONFIG_RTL_LAYERED_DRIVER_L4) + rtl865xNaptEntry.protocol=RTL865X_PROTOCOL_TCP; + rtl865xNaptEntry.intIp=cp->daddr.ip; + rtl865xNaptEntry.intPort=cp->dport; + rtl865xNaptEntry.extIp=cp->vaddr.ip; + rtl865xNaptEntry.extPort=cp->vport; + rtl865xNaptEntry.remIp=cp->caddr.ip; + rtl865xNaptEntry.remPort=cp->cport; + rc = rtl865x_addNaptConnection(&rtl865xNaptEntry, &rtl865xPrio); + #endif + if (!rc) + cp->hw_acc = 1; + #ifdef CONFIG_HARDWARE_NAT_DEBUG + /*2007-12-19*/ + printk("%s:%d:(%s): errno=%d\n %s (%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u) g:(%u.%u.%u.%u:%u)\n", + __FUNCTION__,__LINE__,"add_nat", rc, "tcp", NIPQUAD(cp->daddr), cp->dport, + NIPQUAD(cp->caddr), cp->cport, NIPQUAD(cp->vaddr), cp->vport + ); + #endif + } +} + +int32 rtl_udp_state_transition_check(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb, struct ip_vs_protocol *pp) +{ + #if defined(CONFIG_RTL_HW_QOS_SUPPORT) + uint32 ret; + struct net_device *lanDev, *wanDev; + #endif + #if defined(CONFIG_RTL_LAYERED_DRIVER_L4) + rtl865x_napt_entry rtl865xNaptEntry; + rtl865x_priority rtl865xPrio; + rtl865x_qos_mark rtl865xQosMark; + #endif + + /*2007-12-19*/ + if (!cp->hw_acc && !cp->app) + { + int rc; + rc = 0; + #if defined(CONFIG_RTL_HW_QOS_SUPPORT) + if (NULL!=skb) + { + rtl865xNaptEntry.protocol=RTL865X_PROTOCOL_UDP; + rtl865xNaptEntry.intIp=cp->daddr.ip; + rtl865xNaptEntry.intPort=cp->dport; + rtl865xNaptEntry.extIp=cp->vaddr.ip; + rtl865xNaptEntry.extPort=cp->vport; + rtl865xNaptEntry.remIp=cp->caddr.ip; + rtl865xNaptEntry.remPort=cp->cport; + + rtl865xQosMark.downlinkMark=0; //Initial + rtl865xQosMark.uplinkMark=0; //Initial + ret=rtl_qosGetSkbMarkByNaptEntry(&rtl865xNaptEntry, &rtl865xQosMark, skb); + + lanDev=rtl865x_getLanDev(); + wanDev=rtl865x_getWanDev(); + rtl865xPrio.downlinkPrio=rtl_qosGetPriorityByMark(lanDev->name, rtl865xQosMark.downlinkMark); + rtl865xPrio.uplinkPrio=rtl_qosGetPriorityByMark(wanDev->name, rtl865xQosMark.uplinkMark); + + if(lanDev) + dev_put(lanDev); + + if(wanDev) + dev_put(wanDev); + } else + #endif + { + rtl865xPrio.downlinkPrio=0; + rtl865xPrio.uplinkPrio=0; + } + + #if defined(CONFIG_RTL_LAYERED_DRIVER_L4) + rtl865xNaptEntry.protocol=RTL865X_PROTOCOL_UDP; + rtl865xNaptEntry.intIp=cp->daddr.ip; + rtl865xNaptEntry.intPort=cp->dport; + rtl865xNaptEntry.extIp=cp->vaddr.ip; + rtl865xNaptEntry.extPort=cp->vport; + rtl865xNaptEntry.remIp=cp->caddr.ip; + rtl865xNaptEntry.remPort=cp->cport; + + rc = rtl865x_addNaptConnection(&rtl865xNaptEntry, &rtl865xPrio); + #endif + if (!rc) + cp->hw_acc = 1; + #ifdef CONFIG_HARDWARE_NAT_DEBUG + /*2007-12-19*/ + printk("%s:%d:(%s): errno=%d\n %s (%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u) g:(%u.%u.%u.%u:%u)\n", + __FUNCTION__,__LINE__,"add_nat", rc, "udp", NIPQUAD(cp->daddr), cp->dport, + NIPQUAD(cp->caddr), cp->cport, NIPQUAD(cp->vaddr), cp->vport + ); + #endif + } +} + +#endif + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_RTL_NF_CONNTRACK_GARBAGE_NEW) +static struct proc_dir_entry *proc_gc_overflow_timout=NULL; +static int gc_overflow_timout_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "rtl_gc_overflow_timout(%d), HZ(%d)\n", rtl_gc_overflow_timout, HZ); + + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +static int gc_overflow_timout_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + uint32 tmpBuf[32]; + + if (count < 2) + return -EFAULT; + + if (buffer && !copy_from_user(tmpBuf, buffer, count)) { + tmpBuf[count-1]=0; + rtl_gc_overflow_timout=simple_strtol((const char *)tmpBuf, NULL, 0); + + return count; + } + return -EFAULT; +} + +void gc_overflow_timout_proc_init(void) +{ + proc_gc_overflow_timout = create_proc_entry("gc_overflow_timout", 0, NULL); + if (proc_gc_overflow_timout) { + proc_gc_overflow_timout->read_proc = gc_overflow_timout_read_proc; + proc_gc_overflow_timout->write_proc = gc_overflow_timout_write_proc; + } +} +#endif + + -- cgit v1.2.3