#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