/* Linux Kernel Hacking: net/core/neighbour.c // ARP net/ipv4/fib_hash.c // ROUTE net/ipv4/netfilter/ip_conntrack_core.c // NAPT (PATH*2) net/ipv4/netfilter/ip_nat_core.c // NAPT (PATH*2) net/ipv4/ip_input.c // FastPath_Enter() net/ipv4/ip_output.c // FastPath_Track() */ #include <linux/kernel.h> #include <linux/notifier.h> #include <linux/netfilter.h> #include <linux/if_arp.h> #include <net/netfilter/nf_conntrack_ecache.h> #include <net/xfrm.h> #include <linux/fs.h> #include <linux/seq_file.h> #include "fastpath_core.h" #ifdef CONFIG_RTL8672_MIPS16_IPV4 #include "../../mips16_lib.h" #endif #include <net/rtl/rtl_types.h> #include <net/rtl/rtl_glue.h> #include "../drivers/net/rtl819x/AsicDriver/rtl865x_asicL4.h" #include <net/rtl/rtl865x_nat.h> #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #include <linux/if_vlan.h> #include "../net/8021q/vlan.h" struct vlan_vid_info { struct list_head list; __be16 proto; u16 vid; int refcount; }; #endif struct timer_list fp_monitor_timer; #if defined(CONFIG_RTL8685SB) static int heavy_traffic=10; #else static int heavy_traffic=5000; #endif #define BIT(nr) (1UL << (nr)) #define SUPPORT_UDP_UNI_DIRECTION 1 enum { FP_HEAVY = BIT(0) }; int MAX_FASTPATH_NUMBER=0; //#define ip_ct_tcp_timeout_established tcp_timeouts[TCP_CONNTRACK_ESTABLISHED] //#define ip_ct_udp_timeout_stream nf_ct_udp_timeout_stream #if defined(CONFIG_RTL_HW_NAPT_4KENTRY) struct Path_List_Entry *RTL_HWNAT_FP_MAPPING[RTL8676_TCPUDPTBL_SIZE_HW]; #endif #define MODULE_NAME "Realtek SD2-FastPath" #define MODULE_VERSION_FP "v1.00beta_2.4.26-uc0" //tylo, temp. remove code swap function #define __SWAP enum { ST_INIT = 0, ST_OPERATIONAL, ST_ADMIN_DOWN }; enum { EVT_SAR_UP = 1, EVT_SAR_DOWN, EVT_ADMIN_DOWN, EVT_ADMIN_UP }; //#if defined(CONFIG_RTL867X_IPTABLES_FAST_PATH) || defined(CONFIG_RTL867X_PACKET_PROCESSOR) #ifdef CONFIG_DSL_CODESWAP int fp_on=0; static int fp_state = 0; static int fp_admin = 1; // administrative status. #else int fp_on=2; #endif //#else //int fp_on=0; //#endif #define DEBUG_PROCFILE /* Create ProcFile for debug */ extern int DumpTrapCPUpkt_debug; extern int DumpTrapCPUpkt_debug_LIMIT; /* ==================================================================================================== */ static __u8 fastpath_forward_flag = 1; /* default: On */ static rwlock_t fp_arp_lock; static rwlock_t fp_route_lock; static rwlock_t fp_napt_lock; static rwlock_t fp_path_lock; /* --- ARP Table Structures --- */ struct Arp_Table { CTAILQ_HEAD(Arp_list_entry_head, Arp_List_Entry) list[ARP_TABLE_LIST_MAX]; }; static CTAILQ_HEAD(Arp_list_inuse_head, Arp_List_Entry) arp_list_inuse; static CTAILQ_HEAD(Arp_list_free_head, Arp_List_Entry) arp_list_free; static struct Arp_Table *table_arp; /* --- Route Table Structures --- */ struct Route_Table { CTAILQ_HEAD(Route_list_entry_head, Route_List_Entry) list[ROUTE_TABLE_LIST_MAX]; }; static CTAILQ_HEAD(Route_list_inuse_head, Route_List_Entry) route_list_inuse; static CTAILQ_HEAD(Route_list_free_head, Route_List_Entry) route_list_free; static struct Route_Table *table_route; /* --- NAPT Table Structures --- */ struct Napt_List_Entry { __u8 valid; //cathy //enum NP_PROTOCOL protocol; __u16 protocol; ip_t intIp; __u32 intPort; ip_t extIp; __u32 extPort; ip_t remIp; __u32 remPort; ip_t int_remIp; __u32 int_remPort; enum NP_FLAGS flags; __u16 state; //0-unreplied 1-established. 2-path exist __u16 refcnt; struct nf_conn * ct; CTAILQ_ENTRY(Napt_List_Entry) napt_link; CTAILQ_ENTRY(Napt_List_Entry) tqe_link; }; struct Napt_Table { CTAILQ_HEAD(Napt_list_entry_head, Napt_List_Entry) list[NAPT_TABLE_LIST_MAX]; }; static CTAILQ_HEAD(Napt_list_inuse_head, Napt_List_Entry) napt_list_inuse; static CTAILQ_HEAD(Napt_list_free_head, Napt_List_Entry) napt_list_free; #ifdef CONFIG_RTL8672 __DRAM #endif static struct Napt_Table *table_napt; struct Path_Table { CTAILQ_HEAD(Path_list_entry_head, Path_List_Entry) list[PATH_TABLE_LIST_MAX]; }; CTAILQ_HEAD(Path_list_inuse_head, Path_List_Entry) path_list_inuse; static CTAILQ_HEAD(Path_list_free_head, Path_List_Entry) path_list_free; #ifdef CONFIG_RTL8672 __DRAM #endif static struct Path_Table *table_path; #ifdef CONFIG_XFRM char ipsecdev[IFNAMSIZ] = "IPsecProcess"; #endif #if 0 /* --- InterFace Table Structures --- */ struct If_List_Entry { __u8 valid; __u8 ifname[IFNAME_LEN_MAX]; ip_t ipAddr; ether_t mac; __u32 mtu; enum IF_FLAGS flags; CTAILQ_ENTRY(If_List_Entry) if_link; CTAILQ_ENTRY(If_List_Entry) tqe_link; }; CTAILQ_HEAD(If_list_inuse_head, If_List_Entry) if_list_inuse; CTAILQ_HEAD(If_list_free_head, If_List_Entry) if_list_free; #endif /* ==================================================================================================== */ static __u32 __SWAP FastPath_Hash_ARP_Entry(ip_t ip) { //ql: maybe ip&0xF is better; //return (ip % 16); return (ip & 0xF); } static __u32 __SWAP FastPath_Hash_ROUTE_Entry(ip_t ip, ip_t mask) { int i; ip_t tmp = (ip & mask); for(i=0; i<32; i++) { if (tmp & 0x00000001) { return (tmp + (__u32)i) % ROUTE_TABLE_LIST_MAX; } tmp = tmp >> 1; } return 0; } static __u32 __SWAP FastPath_Hash_NAPT_Entry(ip_t intIp,__u32 intPort, ip_t extIp, __u32 extPort, ip_t remIp, __u32 remPort) { __u32 hash; hash = (0xff000000 & intIp) >> 24; hash ^= (0x00ff0000 & intIp) >> 16; hash ^= (0x0000ff00 & intIp) >> 8; hash ^= (0x000000ff & intIp); hash ^= (0x0000ff00 & intPort) >> 8; hash ^= (0x000000ff & intPort); hash ^= (0xff000000 & extIp) >> 24; hash ^= (0x00ff0000 & extIp) >> 16; hash ^= (0x0000ff00 & extIp) >> 8; hash ^= (0x000000ff & extIp); hash ^= (0x0000ff00 & extPort) >> 8; hash ^= (0x000000ff & extPort); hash ^= (0xff000000 & remIp) >> 24; hash ^= (0x00ff0000 & remIp) >> 16; hash ^= (0x0000ff00 & remIp) >> 8; hash ^= (0x000000ff & remIp); hash ^= (0x0000ff00 & remPort) >> 8; hash ^= (0x000000ff & remPort); // Kaohj //return 0x000003ff & (hash ^ (hash >> 12)); return (NAPT_TABLE_LIST_MAX-1) & (hash ^ (hash >> NAPT_TABLE_HASHING_BIT_NUM)); } __IRAM inline static __u32 FastPath_Hash_PATH_Entry(ip_t sip, __u32 sport, ip_t dip, __u32 dport, __u16 proto) { register __u32 hash; hash = ((sip>>16)^sip); hash ^= ((dip>>16)^dip); hash ^= sport; hash ^= dport; //cathy hash ^= proto; // Kaohj //return 0x000003ff & (hash ^ (hash >> 12)); return (PATH_TABLE_LIST_MAX-1) & (hash ^ (hash >> NAPT_TABLE_HASHING_BIT_NUM)); } /* ==================================================================================================== */ #if 0 enum LR_RESULT rtl865x_addFdbEntry(__u32 vid, __u32 fid, ether_t* mac, __u32 portmask, enum FDB_FLAGS flags) { DEBUGP_API("addFdbEntry: vid=%u fid=%u mac=%p portmask=0x%08X flasg=0x%08X \n", vid, fid, mac, portmask, flags); return LR_SUCCESS; } enum LR_RESULT rtl865x_delFdbEntry(__u32 vid, __u32 fid, ether_t* mac) { DEBUGP_API("delFdbEntry: vid=%u fid=%u mac=%p \n", vid, fid, mac); return LR_SUCCESS; } #endif enum LR_RESULT __SWAP fastpath_addArp(ip_t ip, ether_t* mac, enum ARP_FLAGS flags) { __u32 hash = FastPath_Hash_ARP_Entry(ip); struct Arp_List_Entry *ep; DEBUGP_API("addArp: ip=0x%08X mac=%02X:%02X:%02X:%02X:%02X:%02X flags=0x%08X Hash=%u \n", ip, MAC2STR(*mac), flags, hash); /* Lookup */ CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == ip) { DEBUGP_SYS("addArp: ERROR - arp(ip=0x%08X) already exist! \n", ip); return LR_EXIST; } } /* Create */ write_lock_bh(&fp_arp_lock); if(!CTAILQ_EMPTY(&arp_list_free)) { struct Arp_List_Entry *entry_arp; entry_arp = CTAILQ_FIRST(&arp_list_free); entry_arp->ip = ip; entry_arp->mac = *mac; entry_arp->flags = flags; entry_arp->valid = 0xff; CTAILQ_REMOVE(&arp_list_free, entry_arp, tqe_link); CTAILQ_INSERT_TAIL(&arp_list_inuse, entry_arp, tqe_link); CTAILQ_INSERT_TAIL(&table_arp->list[hash], entry_arp, arp_link); } else { DEBUGP_SYS("addArp: ERROR - arp_list_free is empty! \n"); write_unlock_bh(&fp_arp_lock); return LR_FAILED; } write_unlock_bh(&fp_arp_lock); return LR_SUCCESS; } enum LR_RESULT __SWAP fastpath_modifyArp(ip_t ip, ether_t* mac, enum ARP_FLAGS flags) { __u32 hash = FastPath_Hash_ARP_Entry(ip); struct Arp_List_Entry *ep; DEBUGP_API("modifyArp: ip=0x%08X mac=%02X:%02X:%02X:%02X:%02X:%02X flags=0x%08X \n", ip, MAC2STR(*mac), flags); /* Lookup */ write_lock_bh(&fp_arp_lock); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == ip) { ep->mac = *mac; ep->flags = flags; write_unlock_bh(&fp_arp_lock); return LR_SUCCESS; } } write_unlock_bh(&fp_arp_lock); return LR_SUCCESS; } /* delArp() - Delete an entry of Arp Table. */ enum LR_RESULT __SWAP fastpath_delArp(ip_t ip) { __u32 hash = FastPath_Hash_ARP_Entry(ip); struct Arp_List_Entry *ep; DEBUGP_API("delArp: ip=0x%08X \n", ip); /* Lookup */ write_lock_bh(&fp_arp_lock); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == ip) { ep->valid = 0x00; CTAILQ_REMOVE(&table_arp->list[hash], ep, arp_link); CTAILQ_REMOVE(&arp_list_inuse, ep, tqe_link); CTAILQ_INSERT_TAIL(&arp_list_free, ep, tqe_link); write_unlock_bh(&fp_arp_lock); return LR_SUCCESS; } } write_unlock_bh(&fp_arp_lock); return LR_NONEXIST; } //cathy u32 LANsub[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; u32 LANmask[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; u32 routeIndex = 0; __u32 ExistInLAN(ip_t ip, ip_t mask){ __u32 i; if(ip){ for( i=0; i<routeIndex&& routeIndex<=8; i++ ) if( LANsub[i] == ip && LANmask[i] == mask ) return 1; //found it, return 1 } return 0; //doesnt exist, return 0 } //#if defined(CONFIG_PPTP) || defined(CONFIG_PPPOL2TP) || defined(CONFIG_NET_IPIP) #define WAN_SIZE 8 u32 WANsub[WAN_SIZE];// = {[0 ... 7]=0}; u32 wanIndex=0; __u32 ExistInWAN(ip_t ip) { __u32 i; if (ip) { for (i=0; i<wanIndex && i<WAN_SIZE; i++) if (WANsub[i] == ip) return 1; } return 0; } //#endif//end of CONFIG_PPTP || CONFIG_PPPOL2TP || CONFIG_NET_IPIP enum LR_RESULT __SWAP fastpath_addRoute(ip_t ip, ip_t mask, ip_t gateway, __u8* ifname, enum RT_FLAGS flags, int type) { #ifdef CONFIG_PPP int ppplan=-1; #endif __u32 hash = FastPath_Hash_ROUTE_Entry(ip, mask); /* For fixing the bug that system will be hang if keep changing secondary IP&netmask . */ // Just skip the addition if node already existed in array struct Route_List_Entry *ep; /* Looking for the matched ip & netmask node in list */ CTAILQ_FOREACH(ep, &route_list_inuse, tqe_link) { if(ep->ip==ip && ep->mask == mask) return LR_SUCCESS; } DEBUGP_API("addRoute: ip=0x%08X mask=0x%08X gateway=0x%08X ifname=%s flags=0x%08X Hash=%u type=%d\n", ip, mask, gateway, ifname, flags, hash, type); write_lock_bh(&fp_route_lock); if(!CTAILQ_EMPTY(&route_list_free)) { struct Route_List_Entry *entry_route; entry_route = CTAILQ_FIRST(&route_list_free); entry_route->ip = ip; entry_route->mask = mask; entry_route->gateway = gateway; memcpy(&entry_route->ifname, ifname, IFNAME_LEN_MAX - 1); entry_route->flags = flags; entry_route->valid = 0xff; CTAILQ_REMOVE(&route_list_free, entry_route, tqe_link); CTAILQ_INSERT_TAIL(&route_list_inuse, entry_route, tqe_link); CTAILQ_INSERT_TAIL(&table_route->list[hash], entry_route, route_link); write_unlock_bh(&fp_route_lock); #ifdef CONFIG_PPP //cathy, for multi-subnet if (!strncmp(ifname, "ppp", 3)) { sscanf(ifname, "ppp%d", &ppplan); } #endif if( type == RTN_UNICAST && (strstr(ifname, "br") #ifdef CONFIG_PPP || ((ppplan!=-1) && (ppplan>=8) //#if defined(CONFIG_PPTP) || defined(CONFIG_PPPOL2TP) || defined(CONFIG_NET_IPIP) && isPPPoEDev(ifname))/*pppoe proxy lan itf*/ //#endif//end of CONFIG_PPTP || CONFIG_PPPOL2TP || CONFIG_NET_IPIP #endif ) ) { /* For fixing the bug that system will be hang if keep changing secondary IP&netmask . */ //Add it if ip&mask we dont know #if 0 if(ExistInLAN(ip, mask)==0){ #else if(ExistInLAN(ip, mask)==0 && routeIndex < 8){ //xl_yue:20100226 add restriction for routeIndex to avoid memory overlay #endif LANsub[routeIndex] = ip & mask; LANmask[routeIndex] = mask; routeIndex++; } } //#if defined(CONFIG_PPTP) || defined(CONFIG_PPPOL2TP) || defined(CONFIG_NET_IPIP) /*we must remember wan IP for every wan port */ else if (type == RTN_UNICAST) {//wan interface ip_t addr; addr = getNetAddrbyName(ifname, ip); if (addr) { if (!ExistInWAN(addr) && wanIndex<WAN_SIZE) { WANsub[wanIndex++] = addr; } } } //#endif//end of CONFIG_PPTP || CONFIG_PPPOL2TP || CONFIG_NET_IPIP } else { DEBUGP_SYS("addRoute: ERROR - Route_list_free is empty! \n"); write_unlock_bh(&fp_route_lock); return LR_FAILED; } return LR_SUCCESS; } enum LR_RESULT __SWAP fastpath_modifyRoute(ip_t ip, ip_t mask, ip_t gateway, __u8* ifname, enum RT_FLAGS flags, int type) { __u32 hash = FastPath_Hash_ROUTE_Entry(ip, mask); struct Route_List_Entry *ep; DEBUGP_API("modifyRoute: ip=0x%08X mask=0x%08X gateway=0x%08X ifname=%s flags=0x%08X \n", ip, mask, gateway, ifname, flags); /* Lookup */ write_lock_bh(&fp_route_lock); CTAILQ_FOREACH(ep, &table_route->list[hash], route_link) { if (ep->ip == ip && ep->mask == mask) { ep->gateway = gateway; memcpy(&ep->ifname, ifname, IFNAME_LEN_MAX - 1); ep->flags = flags; CTAILQ_REMOVE(&table_route->list[hash], ep, route_link); CTAILQ_REMOVE(&route_list_inuse, ep, tqe_link); CTAILQ_INSERT_TAIL(&route_list_free, ep, tqe_link); write_unlock_bh(&fp_route_lock); return LR_SUCCESS; } } write_unlock_bh(&fp_route_lock); return LR_SUCCESS; } enum LR_RESULT __SWAP fastpath_delRoute(ip_t ip, ip_t mask) { __u32 hash = FastPath_Hash_ROUTE_Entry(ip, mask); struct Route_List_Entry *ep; int i; DEBUGP_API("delRoute: ip=0x%08X mask=0x%08X \n", ip, mask); /* Lookup */ write_lock_bh(&fp_route_lock); CTAILQ_FOREACH(ep, &table_route->list[hash], route_link) { if (ep->ip == ip && ep->mask == mask) { ep->valid = 0x00; CTAILQ_REMOVE(&table_route->list[hash], ep, route_link); CTAILQ_REMOVE(&route_list_inuse, ep, tqe_link); CTAILQ_INSERT_TAIL(&route_list_free, ep, tqe_link); //cathy, for multi-subnet for( i=0; i<routeIndex&& routeIndex<=8; i++ ) { if( (LANsub[i] == (ip&mask)) && (LANmask[i] == mask) ) { LANsub[i] = 0; LANmask[i] = 0; routeIndex--; break; } } for( ; i<routeIndex&&routeIndex<=8; i++ ) { LANsub[i] = LANsub[i+1]; LANmask[i] = LANmask[i+1]; } //#if defined(CONFIG_PPTP) || defined(CONFIG_PPPOL2TP) || defined(CONFIG_NET_IPIP) { ip_t addr; addr = getNetAddrbyName(ep->ifname, ip); for (i=0; i<wanIndex && i<WAN_SIZE; i++) { if (WANsub[i] == addr) { WANsub[i] = 0; wanIndex--; break; } } for (; i<wanIndex && i<(WAN_SIZE-1); i++) WANsub[i] = WANsub[i+1]; for (; i<WAN_SIZE; i++) WANsub[i] = 0; } //#endif//end of CONFIG_PPTP || CONFIG_PPPOL2TP || CONFIG_NET_IPIP write_unlock_bh(&fp_route_lock); return LR_SUCCESS; } } write_unlock_bh(&fp_route_lock); return LR_NONEXIST; } enum LR_RESULT __SWAP fastpath_addRoutedSession(__u8* ifname, enum SE_TYPE seType, __u32 sessionId, enum SE_FLAGS flags ) { return LR_SUCCESS; } enum LR_RESULT __SWAP fastpath_delSession(__u8* ifname) { return LR_SUCCESS; } //#ifdef CONFIG_RTL867X_PACKET_PROCESSOR struct Arp_List_Entry *FastPath_Find_ARP_Entry(ip_t ipaddr) { struct Arp_List_Entry *ep; __u32 hash = FastPath_Hash_ARP_Entry(ipaddr); read_lock_bh(&fp_arp_lock); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == ipaddr) { read_unlock_bh(&fp_arp_lock); return ep; } } read_unlock_bh(&fp_arp_lock); return NULL; } struct Route_List_Entry * fastpath_lookupRoute(ip_t ip) { struct Route_List_Entry *ep,*default_route=NULL; /* Lookup */ read_lock_bh(&fp_route_lock); CTAILQ_FOREACH(ep, &route_list_inuse, tqe_link) { if ((ep->valid==0xff)&&((ip & ep->mask) == (ep->ip & ep->mask))) { if(ep->mask!=0) { read_unlock_bh(&fp_route_lock); return ep; } else { default_route=ep; } } } read_unlock_bh(&fp_route_lock); return default_route; } //#endif enum LR_RESULT __SWAP fastpath_addNaptConnection(void *pskb, struct FP_NAPT_entry *napt, int state) { struct Napt_List_Entry *ep; struct Napt_List_Entry *entry_napt; //unsigned long flags; __u8 *proto; __u32 hash; #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) struct vlan_info *vlan_info; struct vlan_vid_info *vid_info; #endif int lan_vlan_id; if( napt->protocol == IPPROTO_TCP ) { proto = "TCP"; } else if( napt->protocol == IPPROTO_UDP ) { proto = "UDP"; } //#ifdef CONFIG_PPTP else if ( napt->protocol == IPPROTO_GRE ) { proto = "GRE"; } //#endif else { proto = "unknow"; } hash = FastPath_Hash_NAPT_Entry(napt->intIp, napt->intPort, napt->extIp, napt->extPort, napt->remIp, napt->remPort); #if 1 if(unlikely(DumpTrapCPUpkt_debug && DumpTrapCPUpkt_debug_LIMIT>0)) { printk("addNaptConnection1: P=%s int=%u.%u.%u.%u:%u ext=%u.%u.%u.%u:%u rem=%u.%u.%u.%u:%u F=%d (H=%u, Ha=%u, Hb=%u),state=%x\n", proto, NIPQUAD(napt->intIp), napt->intPort, NIPQUAD(napt->extIp), napt->extPort, NIPQUAD(napt->remIp), napt->remPort, napt->flags, hash, FastPath_Hash_PATH_Entry(napt->intIp, napt->intPort, napt->remIp, napt->remPort, napt->protocol), FastPath_Hash_PATH_Entry(napt->remIp, napt->remPort, napt->extIp, napt->extPort, napt->protocol), state); } #endif /* Lookup */ write_lock_bh(&fp_napt_lock); CTAILQ_FOREACH(ep, &table_napt->list[hash], napt_link) { if ((ep->protocol == napt->protocol) && (ep->intIp == napt->intIp) && (ep->intPort == napt->intPort) && (ep->extIp == napt->extIp) && (ep->extPort == napt->extPort) && (ep->remIp == napt->remIp) && (ep->remPort == napt->remPort) && (ep->int_remIp == napt->int_remIp) && (ep->int_remPort == napt->int_remPort)) { DEBUGP_SYS("addNaptConnection: ERROR - the entry already exist! \n"); #if 1 if(unlikely(DumpTrapCPUpkt_debug && DumpTrapCPUpkt_debug_LIMIT>0)) { printk("addNaptConnection1: P=%s int=%u.%u.%u.%u:%u ext=%u.%u.%u.%u:%u rem=%u.%u.%u.%u:%u F=%d (H=%u, Ha=%u, Hb=%u),ref=%d, state=%d\n", proto, NIPQUAD(napt->intIp), napt->intPort, NIPQUAD(napt->extIp), napt->extPort, NIPQUAD(napt->remIp), napt->remPort, napt->flags, hash, FastPath_Hash_PATH_Entry(napt->intIp, napt->intPort, napt->remIp, napt->remPort, napt->protocol), FastPath_Hash_PATH_Entry(napt->remIp, napt->remPort, napt->extIp, napt->extPort, napt->protocol), ep->refcnt, ep->state); } #endif if (ep->state != 1) { if (state==1) {//current is the establish conntrack. if (ep->state == 2) {//PATH already exist. ep->state = 1; write_unlock_bh(&fp_napt_lock); return LR_SUCCESS; } else { ep->state = 1; entry_napt = ep; write_unlock_bh(&fp_napt_lock); goto ADD_PATH; } } else { if (ep->state == 2){ write_unlock_bh(&fp_napt_lock); return LR_SUCCESS; } if ((++(ep->refcnt)) >= 10) { ep->state = 2; entry_napt = ep; #if 1 if(unlikely(DumpTrapCPUpkt_debug && DumpTrapCPUpkt_debug_LIMIT>0)) { printk("addNaptConnection2: P=%s int=%u.%u.%u.%u:%u ext=%u.%u.%u.%u:%u rem=%u.%u.%u.%u:%u F=%d (H=%u, Ha=%u, Hb=%u)\n", proto, NIPQUAD(napt->intIp), napt->intPort, NIPQUAD(napt->extIp), napt->extPort, NIPQUAD(napt->remIp), napt->remPort, napt->flags, hash, FastPath_Hash_PATH_Entry(napt->intIp, napt->intPort, napt->remIp, napt->remPort, napt->protocol), FastPath_Hash_PATH_Entry(napt->remIp, napt->remPort, napt->extIp, napt->extPort, napt->protocol)); } #endif write_unlock_bh(&fp_napt_lock); goto ADD_PATH; } } } write_unlock_bh(&fp_napt_lock); return LR_SUCCESS; } } if (state==0) { // printk("only add napt entry.\n"); if(!CTAILQ_EMPTY(&napt_list_free) && !CTAILQ_EMPTY(&path_list_free)) { entry_napt = CTAILQ_FIRST(&napt_list_free); entry_napt->protocol = napt->protocol; entry_napt->intIp = napt->intIp; entry_napt->intPort = napt->intPort; entry_napt->extIp = napt->extIp; entry_napt->extPort = napt->extPort; entry_napt->remIp = napt->remIp; entry_napt->remPort = napt->remPort; entry_napt->int_remIp = napt->int_remIp; entry_napt->int_remPort = napt->int_remPort; entry_napt->flags = napt->flags; entry_napt->state = 0; entry_napt->refcnt = 0; entry_napt->valid = 0xff; entry_napt->ct = napt->ct; CTAILQ_REMOVE(&napt_list_free, entry_napt, tqe_link); CTAILQ_INSERT_TAIL(&napt_list_inuse, entry_napt, tqe_link); CTAILQ_INSERT_TAIL(&table_napt->list[hash], entry_napt, napt_link); } write_unlock_bh(&fp_napt_lock); return LR_SUCCESS; } if(!CTAILQ_EMPTY(&napt_list_free) && !CTAILQ_EMPTY(&path_list_free)) { entry_napt = CTAILQ_FIRST(&napt_list_free); entry_napt->protocol = napt->protocol; entry_napt->intIp = napt->intIp; entry_napt->intPort = napt->intPort; entry_napt->extIp = napt->extIp; entry_napt->extPort = napt->extPort; entry_napt->remIp = napt->remIp; entry_napt->remPort = napt->remPort; entry_napt->int_remIp = napt->int_remIp; entry_napt->int_remPort = napt->int_remPort; entry_napt->flags = napt->flags; entry_napt->state = 1; entry_napt->valid = 0xff; entry_napt->ct = napt->ct; CTAILQ_REMOVE(&napt_list_free, entry_napt, tqe_link); CTAILQ_INSERT_TAIL(&napt_list_inuse, entry_napt, tqe_link); CTAILQ_INSERT_TAIL(&table_napt->list[hash], entry_napt, napt_link); write_unlock_bh(&fp_napt_lock); goto ADD_PATH; } else { DEBUGP_SYS("addNaptConnection: ERROR - Napt_list_free is empty! \n"); write_unlock_bh(&fp_napt_lock); return LR_FAILED; } write_unlock_bh(&fp_napt_lock); ADD_PATH: /* add Path Table Entry */ if (1) { //__u32 hash; struct Path_List_Entry *entry_path, *orig = NULL; if (CTAILQ_EMPTY(&path_list_free)) { entry_napt->state = 0; return LR_SUCCESS; } write_lock_bh(&fp_path_lock); /* course = 1 (Outbound) */ hash = FastPath_Hash_PATH_Entry(napt->intIp, napt->intPort, napt->remIp, napt->remPort, napt->protocol); //cathy entry_path = CTAILQ_FIRST(&path_list_free); entry_path->protocol = &entry_napt->protocol; entry_path->in_sIp = &entry_napt->intIp; entry_path->in_sPort = &entry_napt->intPort; entry_path->in_dIp = &entry_napt->int_remIp; entry_path->in_dPort = &entry_napt->int_remPort; entry_path->out_sIp = &entry_napt->extIp; entry_path->out_sPort = &entry_napt->extPort; entry_path->out_dIp = &entry_napt->remIp; entry_path->out_dPort = &entry_napt->remPort; entry_path->arp_entry = NULL; //#ifdef CONFIG_NET_IPIP entry_path->arp_ignore = 0; //#endif//end of CONFIG_NET_IPIP entry_path->course = 1; entry_path->valid = 0xff; /* If connection is established by inbound packet, for now the destination device is unknown until FastPath forward the outbound packet. */ #if 1 entry_path->dst = NULL; entry_path->out_ifname = NULL; #else SetFPDst(pskb, &entry_path->dst); FastPathHoldDst(pskb); entry_path->out_ifname = fastpath_getdstifName(entry_path->dst); #endif entry_path->mark = getSkbMark(pskb); entry_path->mdscp = getSkbDscp(pskb); #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) entry_path->imq_flags = getSkbImqFlags(pskb); #endif entry_path->type = 0; /* Init: Normal (Only Routing) */ entry_path->ct = entry_napt->ct; // copy tuple from ct memcpy(&entry_path->orig_tuple, &entry_napt->ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(entry_path->orig_tuple)); entry_path->last_refresh_time = jiffies; entry_path->pps = 0; if (*entry_path->in_sIp != *entry_path->out_sIp) { entry_path->type |= 1; /* SNAT */ } if (*entry_path->in_sPort != *entry_path->out_sPort) { entry_path->type |= 2; /* SNPT */ } if (*entry_path->in_dIp != *entry_path->out_dIp) { entry_path->type |= 4; /* DNAT */ } if (*entry_path->in_dPort != *entry_path->out_dPort) { entry_path->type |= 8; /* DNPT */ } if( (entry_path->type & 4) || (entry_path->type & 8)) entry_path->add_into_asic_checked = 1; /* hwnat does not support DNAT when upstream */ else entry_path->add_into_asic_checked = 0; lan_vlan_id = -1; #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) if(((struct sk_buff *)pskb)->vlan_proto == ETH_P_8021Q) { vlan_info = ((struct sk_buff *)pskb)->from_dev->vlan_info; list_for_each_entry(vid_info, &vlan_info->vid_list, list) { if(vid_info->proto == ETH_P_8021Q) { lan_vlan_id = vid_info->vid; break; } } } #endif entry_path->internal_vlan_id = lan_vlan_id; CTAILQ_REMOVE(&path_list_free, entry_path, tqe_link); CTAILQ_INSERT_TAIL(&path_list_inuse, entry_path, tqe_link); CTAILQ_INSERT_TAIL(&table_path->list[hash], entry_path, path_link); MAX_FASTPATH_NUMBER++; orig = entry_path; //downstream if (CTAILQ_EMPTY(&path_list_free)) { entry_path->valid = 0x00; CTAILQ_REMOVE(&table_path->list[hash], entry_path, path_link); CTAILQ_REMOVE(&path_list_inuse, entry_path, tqe_link); CTAILQ_INSERT_TAIL(&path_list_free, entry_path, tqe_link); entry_napt->state = 0; MAX_FASTPATH_NUMBER--; write_unlock_bh(&fp_path_lock); return LR_SUCCESS; } /* course = 2 (Inbound) */ hash = FastPath_Hash_PATH_Entry(napt->remIp, napt->remPort, napt->extIp, napt->extPort, napt->protocol); //cathy entry_path = CTAILQ_FIRST(&path_list_free); entry_path->protocol = &entry_napt->protocol; entry_path->in_sIp = &entry_napt->remIp; entry_path->in_sPort = &entry_napt->remPort; entry_path->in_dIp = &entry_napt->extIp; entry_path->in_dPort = &entry_napt->extPort; entry_path->out_sIp = &entry_napt->int_remIp; entry_path->out_sPort = &entry_napt->int_remPort; entry_path->out_dIp = &entry_napt->intIp; entry_path->out_dPort = &entry_napt->intPort; entry_path->out_ifname = NULL; entry_path->arp_entry = NULL; //#ifdef CONFIG_NET_IPIP entry_path->arp_ignore = 0; //#endif //end of CONFIG_NET_IPIP entry_path->course = 2; entry_path->valid = 0xff; entry_path->dst = NULL; entry_path->type = 0; /* Init: Normal (Only Routing) */ entry_path->mark = 0; entry_path->mdscp = 0; #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) entry_path->imq_flags = 0; #endif entry_path->ct = entry_napt->ct; // copy tuple from ct memcpy(&entry_path->orig_tuple, &entry_napt->ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(entry_path->orig_tuple)); entry_path->last_refresh_time = jiffies; entry_path->pps = 0; if (*entry_path->in_sIp != *entry_path->out_sIp) { entry_path->type |= 1; /* SNAT */ } if (*entry_path->in_sPort != *entry_path->out_sPort) { entry_path->type |= 2; /* SNPT */ } if (*entry_path->in_dIp != *entry_path->out_dIp) { entry_path->type |= 4; /* DNAT */ } if (*entry_path->in_dPort != *entry_path->out_dPort) { entry_path->type |= 8; /* DNPT */ } if( (entry_path->type & 1) || (entry_path->type & 2)) entry_path->add_into_asic_checked = 1; /* hwnat does not support SNAT when downstream */ else entry_path->add_into_asic_checked = 0; #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) entry_path->internal_vlan_id = lan_vlan_id; #endif entry_path->pair = orig; orig->pair = entry_path; CTAILQ_REMOVE(&path_list_free, entry_path, tqe_link); CTAILQ_INSERT_TAIL(&path_list_inuse, entry_path, tqe_link); CTAILQ_INSERT_TAIL(&table_path->list[hash], entry_path, path_link); MAX_FASTPATH_NUMBER++; write_unlock_bh(&fp_path_lock); } return LR_SUCCESS; } enum LR_RESULT __SWAP fastpath_delNaptConnection(struct FP_NAPT_entry *napt) { struct Napt_List_Entry *ep; __u8 *proto; __u32 hash; if( napt->protocol == IPPROTO_TCP ) { proto = "TCP"; } else if( napt->protocol == IPPROTO_UDP ) { proto = "UDP"; } else { proto = "unknow"; } hash = FastPath_Hash_NAPT_Entry(napt->intIp, napt->intPort, napt->extIp, napt->extPort, napt->remIp, napt->remPort); //DEBUGP_API("delNaptConnection: P=%s int=%u.%u.%u.%u:%u ext=%u.%u.%u.%u:%u rem=%u.%u.%u.%u:%u \n", // proto, NIPQUAD(napt->intIp), napt->intPort, NIPQUAD(napt->extIp), napt->extPort, NIPQUAD(napt->remIp), napt->remPort); /* Lookup */ write_lock_bh(&fp_napt_lock); CTAILQ_FOREACH(ep, &table_napt->list[hash], napt_link) { if ((ep->protocol == napt->protocol) && (ep->intIp == napt->intIp) && (ep->intPort == napt->intPort) && (ep->extIp == napt->extIp) && (ep->extPort == napt->extPort) && (ep->remIp == napt->remIp) && (ep->remPort == napt->remPort) && (ep->int_remIp == napt->int_remIp) && (ep->int_remPort == napt->int_remPort)) { ep->valid = 0x00; CTAILQ_REMOVE(&table_napt->list[hash], ep, napt_link); CTAILQ_REMOVE(&napt_list_inuse, ep, tqe_link); CTAILQ_INSERT_TAIL(&napt_list_free, ep, tqe_link); /* del Path Table Entry */ if (1) { __u32 hash; struct Path_List_Entry *entry_path; /* course = 1 (Outbound) */ write_lock_bh(&fp_path_lock); hash = FastPath_Hash_PATH_Entry(napt->intIp, napt->intPort, napt->remIp, napt->remPort, napt->protocol); //cathy CTAILQ_FOREACH(entry_path, &table_path->list[hash], path_link) { if ((entry_path->protocol == &ep->protocol) && (entry_path->course == 1)) { entry_path->valid = 0x00; if( entry_path->dst ) { dst_release(entry_path->dst); } CTAILQ_REMOVE(&table_path->list[hash], entry_path, path_link); CTAILQ_REMOVE(&path_list_inuse, entry_path, tqe_link); CTAILQ_INSERT_TAIL(&path_list_free, entry_path, tqe_link); MAX_FASTPATH_NUMBER--; #if defined(CONFIG_RTL_HW_NAPT_4KENTRY) { int asicIdx; asicIdx = rtl865x_getNaptConnectionPosition(*entry_path->in_sIp, *entry_path->in_sPort, *entry_path->out_sIp, *entry_path->out_sPort, *entry_path->in_dIp, *entry_path->in_dPort, *entry_path->protocol==IPPROTO_TCP?1:0,1); if(asicIdx >= 0) { RTL_HWNAT_FP_MAPPING[asicIdx] = NULL; rtl865x_delNaptByIdx(asicIdx); } } #endif break; } } /* course = 2 (Inbound) */ hash = FastPath_Hash_PATH_Entry(napt->remIp, napt->remPort, napt->extIp, napt->extPort, napt->protocol); //cathy CTAILQ_FOREACH(entry_path, &table_path->list[hash], path_link) { if ((entry_path->protocol == &ep->protocol) && (entry_path->course == 2)) { entry_path->valid = 0x00; //cathy, fix dst destroyed before fastpath entry releases it if( entry_path->dst ) { dst_release(entry_path->dst); } CTAILQ_REMOVE(&table_path->list[hash], entry_path, path_link); CTAILQ_REMOVE(&path_list_inuse, entry_path, tqe_link); CTAILQ_INSERT_TAIL(&path_list_free, entry_path, tqe_link); MAX_FASTPATH_NUMBER--; #if defined(CONFIG_RTL_HW_NAPT_4KENTRY) { int asicIdx; asicIdx = rtl865x_getNaptConnectionPosition(*entry_path->out_dIp, *entry_path->out_dPort, *entry_path->in_dIp, *entry_path->in_dPort, *entry_path->in_sIp, *entry_path->in_sPort, *entry_path->protocol==IPPROTO_TCP?1:0,0); if(asicIdx >= 0) { RTL_HWNAT_FP_MAPPING[asicIdx] = NULL; rtl865x_delNaptByIdx(asicIdx); } } #endif break; } } write_unlock_bh(&fp_path_lock); } write_unlock_bh(&fp_napt_lock); return LR_SUCCESS; } } write_unlock_bh(&fp_napt_lock); return LR_NONEXIST; } enum LR_RESULT __SWAP fastpath_updateNaptConnection(struct FP_NAPT_entry *napt, unsigned int mark, unsigned int mdscp) { struct Napt_List_Entry *ep; __u8 *proto; __u32 hash; if( napt->protocol == IPPROTO_TCP ) { proto = "TCP"; } else if( napt->protocol == IPPROTO_UDP ) { proto = "UDP"; } else { proto = "unknow"; } hash = FastPath_Hash_NAPT_Entry(napt->intIp, napt->intPort, napt->extIp, napt->extPort, napt->remIp, napt->remPort); /* Lookup */ read_lock_bh(&fp_napt_lock); CTAILQ_FOREACH(ep, &table_napt->list[hash], napt_link) { if ((ep->protocol == napt->protocol) && (ep->intIp == napt->intIp) && (ep->intPort == napt->intPort) && (ep->extIp == napt->extIp) && (ep->extPort == napt->extPort) && (ep->remIp == napt->remIp) && (ep->remPort == napt->remPort) && (ep->int_remIp == napt->int_remIp) && (ep->int_remPort == napt->int_remPort)) { DEBUGP_API("updateNaptConnection: P=%s int=%u.%u.%u.%u:%u ext=%u.%u.%u.%u:%u rem=%u.%u.%u.%u:%u mark=%x\n", proto, NIPQUAD(napt->intIp), napt->intPort, NIPQUAD(napt->extIp), napt->extPort, NIPQUAD(napt->remIp), napt->remPort, mark); /* update Path Table Entry */ if (1) { __u32 hash; struct Path_List_Entry *entry_path; /* course = 1 (Outbound) */ hash = FastPath_Hash_PATH_Entry(napt->intIp, napt->intPort, napt->remIp, napt->remPort, napt->protocol); //cathy write_lock_bh(&fp_path_lock); CTAILQ_FOREACH(entry_path, &table_path->list[hash], path_link) { if ((entry_path->protocol == &ep->protocol) && (entry_path->course == 1)) { entry_path->mark = mark; break; } } write_unlock_bh(&fp_path_lock); #if 0 /* course = 2 (Inbound) */ hash = FastPath_Hash_PATH_Entry(napt->remIp, napt->remPort, napt->extIp, napt->extPort, napt->protocol); //cathy CTAILQ_FOREACH(entry_path, &table_path->list[hash], path_link) { if ((entry_path->protocol == &ep->protocol) && (entry_path->course == 2)) { entry_path->mark = mark; break; } } #endif } read_unlock_bh(&fp_napt_lock); return LR_SUCCESS; } } read_unlock_bh(&fp_napt_lock); return LR_NONEXIST; } /*delete concerning rules to filter chain*/ int clearFastPathEntry(void) { struct Path_List_Entry *path_ep; struct Napt_List_Entry *napt_ep; __u32 hash; REMOVE_PATH: CTAILQ_FOREACH(path_ep, &path_list_inuse, tqe_link) { path_ep->valid = 0; if (path_ep->dst) dst_release(path_ep->dst); hash = FastPath_Hash_PATH_Entry(*path_ep->in_sIp, *path_ep->in_sPort, *path_ep->in_dIp, *path_ep->in_dPort, *path_ep->protocol); CTAILQ_REMOVE(&table_path->list[hash], path_ep, path_link); CTAILQ_REMOVE(&path_list_inuse, path_ep, tqe_link); CTAILQ_INSERT_TAIL(&path_list_free, path_ep, tqe_link); MAX_FASTPATH_NUMBER--; goto REMOVE_PATH; } REMOVE_NAPT: CTAILQ_FOREACH(napt_ep, &napt_list_inuse, tqe_link) { napt_ep->valid = 0; hash = FastPath_Hash_NAPT_Entry(napt_ep->intIp, napt_ep->intPort, napt_ep->extIp, napt_ep->extPort, napt_ep->remIp, napt_ep->remPort); CTAILQ_REMOVE(&table_napt->list[hash], napt_ep, napt_link); CTAILQ_REMOVE(&napt_list_inuse, napt_ep, tqe_link); CTAILQ_INSERT_TAIL(&napt_list_free, napt_ep, tqe_link); goto REMOVE_NAPT; } return 1; } /* ==================================================================================================== */ __u8 * FastPath_Route(ip_t dIp) { __u8 *ifname = NULL; __u32 mask_max = 0x0; struct Route_List_Entry *ep; /* Lookup */ CTAILQ_FOREACH(ep, &route_list_inuse, tqe_link) { if ((ep->mask >= mask_max) && ((dIp & ep->mask) == ep->ip)) { ifname = &ep->ifname[0]; mask_max = ep->mask; } } return ifname; } /* ==================================================================================================== */ /* cached hardware header; allow for machine alignment needs. */ #define HH_DATA_MOD 16 #define HH_DATA_ALIGN(__len) \ (((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1)) __IRAM_SYS_MIDDLE int FastPath_Process(void *pskb, struct iphdr *iph,struct net_bridge_port *br_port) { __u32 sIp, dIp; __u16 sPort=0, dPort=0; #ifdef CONFIG_PPP int pppdev=0;//pppoe proxy or upstream pppoe #endif void *dev=NULL; __u8 imq_flags = 0; __u8 course; if (!fastpath_forward_flag) return 0; if (!iph) return 0; sIp = iph->saddr; dIp = iph->daddr; if(iph->frag_off & htons(0x3fff)){ return 0; } write_lock_bh(&fp_path_lock); switch (iph->protocol) { case IPPROTO_TCP: { struct tcphdr *tcph; __u32 hash; struct Path_List_Entry *entry_path; tcph = (struct tcphdr*)((__u32 *)iph + iph->ihl); sPort = tcph->source; dPort = tcph->dest; DEBUGP_PKT("==>> [%08X] SIP: %u.%u.%u.%u:%u -> DIP: %u.%u.%u.%u:%u flag:0x%x<TCP>\n", tcph->check, NIPQUAD(iph->saddr), tcph->source, NIPQUAD(iph->daddr), tcph->dest, *(unsigned short *)((__u8 *)tcph + 12)); if (tcph->rst || tcph->syn){ write_unlock_bh(&fp_path_lock); return 0; } hash = FastPath_Hash_PATH_Entry(sIp, sPort, dIp, dPort, iph->protocol); //cathy CTAILQ_FOREACH(entry_path, &table_path->list[hash], path_link) { if ((*entry_path->in_sPort == sPort) && (*entry_path->in_dPort == dPort) && (*entry_path->in_sIp == sIp) && (*entry_path->in_dIp == dIp) && (*entry_path->protocol == IPPROTO_TCP)) { //cathy if (unlikely(tcph->fin)) { entry_path->valid = 0; if (entry_path->pair) entry_path->pair->valid = 0; } if (unlikely(!entry_path->valid)){ write_unlock_bh(&fp_path_lock); return 0; } if(unlikely(NULL == entry_path->dst)){ if(!fp_iproute_input(pskb, iph, entry_path->out_dIp)){ write_unlock_bh(&fp_path_lock); return 0; } SetFPDst(pskb, &entry_path->dst); entry_path->out_ifname = fastpath_getdstifName(entry_path->dst); setSkbDst(pskb, NULL); } #ifdef CONFIG_PPP if (entry_path->out_ifname && (!strncmp(entry_path->out_ifname, "ppp", 3))) { DEBUGP_PKT("pppoe proxy or upstream pppoe, interface = %s\n", entry_path->out_ifname); dev = getDevFromDestentry(entry_path->dst); pppdev = 1; } #endif /* ARP Cache check */ if ((entry_path->arp_entry && entry_path->arp_entry->valid) || entry_path->arp_ignore) { //if (!pppdev) { setSkbDst(pskb, entry_path->dst); FastPathHoldDst(pskb); if (isDestLo(pskb)) { goto FINISH; } //} DEBUGP_PKT("FORWARD to [%s] \n", entry_path->out_ifname); switch(entry_path->type) { case 0: { /* Only Routing */ break; } case 1: { /* SNAT */ FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_sIp, iph->saddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_sIp, iph->saddr, tcph->check); iph->saddr = *entry_path->out_sIp; break; } case 2: /* SNPT */ case 3: { /* SNAPT */ FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_sIp, iph->saddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAPT(*entry_path->out_sIp, iph->saddr, *entry_path->out_sPort, tcph->source, tcph->check); iph->saddr = *entry_path->out_sIp; tcph->source = *entry_path->out_sPort; break; } case 4: { /* DNAT */ int org_tcp=0; org_tcp=tcph->check; FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_dIp, iph->daddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_dIp, iph->daddr, tcph->check); iph->daddr = *entry_path->out_dIp; break; } case 8: /* DNPT */ case 12: { /* DNAPT */ FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_dIp, iph->daddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAPT(*entry_path->out_dIp, iph->daddr, *entry_path->out_dPort, tcph->dest, tcph->check); iph->daddr = *entry_path->out_dIp; tcph->dest = *entry_path->out_dPort; break; } default: { FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_sIp, iph->saddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_dIp, iph->daddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAPT(*entry_path->out_sIp, iph->saddr, *entry_path->out_sPort, tcph->source, tcph->check); FASTPATH_ADJUST_CHKSUM_NAPT(*entry_path->out_dIp, iph->daddr, *entry_path->out_dPort, tcph->dest, tcph->check); iph->saddr = *entry_path->out_sIp; tcph->source = *entry_path->out_sPort; iph->daddr = *entry_path->out_dIp; tcph->dest = *entry_path->out_dPort; break; } } if(br_port) { // Kevin, if the original source interface is under bridge (ex.br0) // update its aging time before the source MAC being modifeid in ip_finish_output3() #if 0//krammer move this to fp_common.c for making lib clean br_fdb_update(br_port->br, br_port , eth_hdr(((struct sk_buff *)pskb))->h_source); #else fp_br_fdb_update(br_port, pskb); #endif } if (entry_path->course == 1) { setQoSMark(pskb, entry_path->mark); setQosDscp(pskb, entry_path->mdscp, entry_path->mark); #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) setQoSIMQ(pskb, entry_path->imq_flags); #endif } entry_path->pps ++; if ((entry_path->pps > heavy_traffic) && !entry_path->add_into_asic_checked) { add_fastpath_to_asic(pskb, entry_path); } // Kevin, refresh nf_conntrack timeout if( jiffies - entry_path->last_refresh_time > 20*HZ) { entry_path->last_refresh_time = jiffies; fp_updateConxTimer(entry_path); } course = entry_path->course; #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) imq_flags = entry_path->imq_flags; #endif write_unlock_bh(&fp_path_lock); #ifdef CONFIG_PPP if (pppdev) #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) pppoe_proxy_output(pskb, dev, course, imq_flags); #else pppoe_proxy_output(pskb, dev, course); #endif else { #endif initSkbHdr(pskb); ip_finish_output3(pskb, course, imq_flags); #ifdef CONFIG_PPP } #endif if(unlikely(DumpTrapCPUpkt_debug && DumpTrapCPUpkt_debug_LIMIT>0)) printk("Drop... @ %s %d\n",__func__,__LINE__); return NET_RX_DROP; } else { /* Arp Cache update */ struct Arp_List_Entry *ep; __u32 hash = FastPath_Hash_ARP_Entry(*entry_path->out_dIp); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == *entry_path->out_dIp) { entry_path->arp_entry = ep; goto FINISH; } } do { struct Route_List_Entry *rep; CTAILQ_FOREACH(rep, &route_list_inuse, tqe_link) { //printk("ROUTE_TABLE: ip:%x mask:%x gateway:%x\n", rep->ip, rep->mask, rep->gateway); //printk("entry_path out_dip:%x\n", *entry_path->out_dIp); if((rep->ip & rep->mask & 0xFFFFFFFF) == (*entry_path->out_dIp & rep->mask & 0xFFFFFFFF)) { //printk("this is the right route entry."); if (rep->gateway) { hash = FastPath_Hash_ARP_Entry(rep->gateway); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { //printk("ARP_TABLE: ip:%x gateway:%x\n", ep->ip, rep->gateway); if (ep->ip == rep->gateway) { entry_path->arp_entry = ep; //printk("arp entry found.\n"); goto FINISH; } } break; } } } //printk("arp entry still not found.\n\n"); } while(0); if (entry_path->out_ifname) { dev = (void *)__dev_get_by_name(&init_net,entry_path->out_ifname); if (dev && is_NoARP_Dev(dev)) { entry_path->arp_ignore = 1; //printk("arp_ignore.\n"); } } } break; } } break; } case IPPROTO_UDP: { struct udphdr *udph; __u32 hash; struct Path_List_Entry *entry_path; udph = (struct udphdr*)((__u32 *)iph + iph->ihl); sPort = udph->source; dPort = udph->dest; DEBUGP_PKT("==>> [%08X] SIP: %u.%u.%u.%u:%u -> DIP: %u.%u.%u.%u:%u <UDP> #0x%x\n", udph->check, NIPQUAD(iph->saddr), udph->source, NIPQUAD(iph->daddr), udph->dest, iph->frag_off); hash = FastPath_Hash_PATH_Entry(sIp, sPort, dIp, dPort, iph->protocol); //cathy //printk("hash=%d\n", hash); CTAILQ_FOREACH(entry_path, &table_path->list[hash], path_link) { if ((*entry_path->in_sPort == sPort) && (*entry_path->in_dPort == dPort) && (*entry_path->in_sIp == sIp) && (*entry_path->in_dIp == dIp) && (*entry_path->protocol == IPPROTO_UDP)) { //cathy if(unlikely(DumpTrapCPUpkt_debug && DumpTrapCPUpkt_debug_LIMIT>0)) printk("%s %d fp enter, case UDP. \n", __func__, __LINE__); if(unlikely(NULL == entry_path->dst)){ if(!isSkbDstAssigned(pskb)){ if(!fp_iproute_input(pskb, iph, entry_path->out_dIp)){ write_unlock_bh(&fp_path_lock); if(unlikely(DumpTrapCPUpkt_debug && DumpTrapCPUpkt_debug_LIMIT>0)) printk("Leave @ %s %d\n",__func__,__LINE__); return 0; } } SetFPDst(pskb, &entry_path->dst); FastPathHoldDst(pskb); entry_path->out_ifname = fastpath_getdstifName(entry_path->dst); } #ifdef CONFIG_PPP if (entry_path->out_ifname && (!strncmp(entry_path->out_ifname, "ppp", 3))) { DEBUGP_PKT("%s %d pppoe proxy or upstream pppoe\n", __func__, __LINE__); dev = getDevFromDestentry(entry_path->dst); pppdev = 1; } #endif /* ARP Cache check */ if ((entry_path->arp_entry && entry_path->arp_entry->valid) || entry_path->arp_ignore) { //if ((!pppdev)&& !isSkbDstAssigned(pskb)) { if (!isSkbDstAssigned(pskb)) { setSkbDst(pskb, entry_path->dst); FastPathHoldDst(pskb); if (isDestLo(pskb)) goto FINISH; } DEBUGP_PKT("FORWARD to [%s] \n", entry_path->out_ifname); switch(entry_path->type) { case 0: { /* Only Routing */ break; } case 1: { /* SNAT */ FASTPATH_ADJUST_CHKSUM_NAT_UDP(*entry_path->out_sIp, iph->saddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAT_UDP(*entry_path->out_sIp, iph->saddr, udph->check); iph->saddr = *entry_path->out_sIp; break; } case 2: /* SNPT */ case 3: { /* SNAPT */ FASTPATH_ADJUST_CHKSUM_NAT_UDP(*entry_path->out_sIp, iph->saddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAPT_UDP(*entry_path->out_sIp, iph->saddr, *entry_path->out_sPort, udph->source, udph->check); iph->saddr = *entry_path->out_sIp; udph->source = *entry_path->out_sPort; break; } case 4: { /* DNAT */ FASTPATH_ADJUST_CHKSUM_NAT_UDP(*entry_path->out_dIp, iph->daddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAT_UDP(*entry_path->out_dIp, iph->daddr, udph->check); iph->daddr = *entry_path->out_dIp; break; } case 8: /* DNPT */ case 12: { /* DNAPT */ FASTPATH_ADJUST_CHKSUM_NAT_UDP(*entry_path->out_dIp, iph->daddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAPT_UDP(*entry_path->out_dIp, iph->daddr, *entry_path->out_dPort, udph->dest, udph->check); iph->daddr = *entry_path->out_dIp; udph->dest = *entry_path->out_dPort; break; } default: { FASTPATH_ADJUST_CHKSUM_NAT_UDP(*entry_path->out_sIp, iph->saddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAT_UDP(*entry_path->out_dIp, iph->daddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAPT_UDP(*entry_path->out_sIp, iph->saddr, *entry_path->out_sPort, udph->source, udph->check); FASTPATH_ADJUST_CHKSUM_NAPT_UDP(*entry_path->out_dIp, iph->daddr, *entry_path->out_dPort, udph->dest, udph->check); iph->saddr = *entry_path->out_sIp; udph->source = *entry_path->out_sPort; iph->daddr = *entry_path->out_dIp; udph->dest = *entry_path->out_dPort; break; } } if(br_port) { // Kevin, if the original source interface is under bridge (ex.br0) // update its aging time before the source MAC being modifeid in ip_finish_output3() #if 0//krammer move this to fp_common.c for making lib clean br_fdb_update(br_port->br, br_port , eth_hdr(((struct sk_buff *)pskb))->h_source); #else fp_br_fdb_update(br_port, pskb); #endif } if (entry_path->course == 1) { setQoSMark(pskb, entry_path->mark); setQosDscp(pskb, entry_path->mdscp, entry_path->mark); #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) setQoSIMQ(pskb, entry_path->imq_flags); #endif } entry_path->pps ++; if ((entry_path->pps > heavy_traffic) && !entry_path->add_into_asic_checked) { add_fastpath_to_asic(pskb, entry_path); } // Kevin, refresh nf_conntrack timeout if( jiffies - entry_path->last_refresh_time > 20*HZ) { entry_path->last_refresh_time = jiffies; fp_updateConxTimer(entry_path); } course = entry_path->course; #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) imq_flags = entry_path->imq_flags; #endif write_unlock_bh(&fp_path_lock); #ifdef CONFIG_PPP if (pppdev) #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) pppoe_proxy_output(pskb, dev, course, imq_flags); #else pppoe_proxy_output(pskb, dev, course); #endif else { #endif initSkbHdr(pskb); ip_finish_output3(pskb,course,imq_flags); #ifdef CONFIG_PPP } #endif return NET_RX_DROP; } else { /* Arp Cache update */ struct Arp_List_Entry *ep; //printk("%s %d out_dIP:%x\n", __func__, __LINE__, *entry_path->out_dIp); __u32 hash = FastPath_Hash_ARP_Entry(*entry_path->out_dIp); //printk("%s %d hash=%x\n", __func__, __LINE__, hash); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { //printk("%s %d ep->ip=%x out_dIP=%x\n", __func__, __LINE__, ep->ip, *entry_path->out_dIp); if (ep->ip == *entry_path->out_dIp) { entry_path->arp_entry = ep; goto FINISH; } } do { struct Route_List_Entry *rep; CTAILQ_FOREACH(rep, &route_list_inuse, tqe_link) { if((rep->ip & rep->mask) == (*entry_path->out_dIp & rep->mask)) { if (rep->gateway) { hash = FastPath_Hash_ARP_Entry(rep->gateway); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == rep->gateway) { entry_path->arp_entry = ep; goto FINISH; } } break; } } } //printk("arp entry still not found.\n\n"); } while (0); if (entry_path->out_ifname) { dev = (void *)__dev_get_by_name(&init_net,entry_path->out_ifname); if (dev && is_NoARP_Dev(dev)) { entry_path->arp_ignore = 1; //printk("arp_ignore.\n"); } } } break; } } if(unlikely(DumpTrapCPUpkt_debug && DumpTrapCPUpkt_debug_LIMIT>0)) printk("no rule found.\n"); break; } //#ifdef CONFIG_PPTP case IPPROTO_GRE: { struct pptp_gre_header { __u8 flags; __u8 ver; __u16 protocol; __u16 payload_len; __u16 call_id; __u32 seq; __u32 ack; } *grehdr; __u16 callid; __u32 hash; struct Path_List_Entry *entry_path; grehdr = (struct pptp_gre_header*)((__u32 *)iph + iph->ihl); callid = grehdr->call_id; DEBUGP_PKT("==>> SIP: %u.%u.%u.%u -> DIP: %u.%u.%u.%u callid:%d <GRE> #0x%x\n", NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), callid, iph->frag_off); hash = FastPath_Hash_PATH_Entry(sIp, callid, dIp, callid, iph->protocol); //cathy //printk("hash=%d\n", hash); CTAILQ_FOREACH(entry_path, &table_path->list[hash], path_link) { //printk("entry:src %x/%d -> dst %x/%d proto:%d\n", *entry_path->in_sIp, *entry_path->in_sPort, *entry_path->in_dIp, // *entry_path->in_dPort, *entry_path->protocol); if ((*entry_path->in_sPort == callid) && (*entry_path->in_dPort == callid) && (*entry_path->in_sIp == sIp) && (*entry_path->in_dIp == dIp) && (*entry_path->protocol == IPPROTO_GRE)) { //printk("%s %d fp enter. \n", __func__, __LINE__); if(unlikely(NULL == entry_path->dst)){ if(!fp_iproute_output(pskb, iph)){ write_unlock_bh(&fp_path_lock); return 0; } SetFPDst(pskb, &entry_path->dst); entry_path->out_ifname = fastpath_getdstifName(entry_path->dst); setSkbDst(pskb, NULL); } #ifdef CONFIG_PPP if (entry_path->out_ifname && (!strncmp(entry_path->out_ifname, "ppp", 3))) { DEBUGP_PKT("%s %d pppoe proxy or upstream pppoe\n", __func__, __LINE__); dev = getDevFromDestentry(entry_path->dst); pppdev = 1; } #endif /* ARP Cache check */ if ((entry_path->arp_entry && entry_path->arp_entry->valid ) #ifdef CONFIG_PPP || pppdev #endif ) { //if (!pppdev) { setSkbDst(pskb, entry_path->dst); FastPathHoldDst(pskb); if (isDestLo(pskb)) goto FINISH; //} DEBUGP_PKT("FORWARD to [%s] \n", entry_path->out_ifname); if(br_port) { // Kevin, if the original source interface is under bridge (ex.br0) // update its aging time before the source MAC being modifeid in ip_finish_output3() #if 0//krammer move this to fp_common.c for making lib clean br_fdb_update(br_port->br, br_port , eth_hdr(((struct sk_buff *)pskb))->h_source); #else fp_br_fdb_update(br_port, pskb); #endif } if (entry_path->course == 1) { setQoSMark(pskb, entry_path->mark); setQosDscp(pskb, entry_path->mdscp, entry_path->mark); #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) setQoSIMQ(pskb, entry_path->imq_flags); #endif } entry_path->pps ++; if ((entry_path->pps > heavy_traffic) && !entry_path->add_into_asic_checked) { add_fastpath_to_asic(pskb, entry_path); } // Kevin, refresh nf_conntrack timeout if( jiffies - entry_path->last_refresh_time > 20*HZ) { entry_path->last_refresh_time = jiffies; fp_updateConxTimer(entry_path); } course = entry_path->course; #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) imq_flags = entry_path->imq_flags; #endif write_unlock_bh(&fp_path_lock); #ifdef CONFIG_PPP if (pppdev) #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) pppoe_proxy_output(pskb, dev, course, imq_flags); #else pppoe_proxy_output(pskb, dev, course); #endif else { #endif initSkbHdr(pskb); ip_finish_output3(pskb, course, imq_flags); #ifdef CONFIG_PPP } #endif return NET_RX_DROP; } else { /* Arp Cache update */ struct Arp_List_Entry *ep; __u32 hash = FastPath_Hash_ARP_Entry(*entry_path->out_dIp); //printk("%s %d out_dIP:%x\n", __func__, __LINE__, *entry_path->out_dIp); //printk("%s %d hash=%x\n", __func__, __LINE__, hash); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { //printk("%s %d ep->ip=%x out_dIP=%x\n", __func__, __LINE__, ep->ip, *entry_path->out_dIp); if (ep->ip == *entry_path->out_dIp) { entry_path->arp_entry = ep; goto FINISH; } } do { struct Route_List_Entry *rep; CTAILQ_FOREACH(rep, &route_list_inuse, tqe_link) { if((rep->ip & rep->mask) == (*entry_path->out_dIp & rep->mask)) { if (rep->gateway) { hash = FastPath_Hash_ARP_Entry(rep->gateway); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == rep->gateway) { entry_path->arp_entry = ep; goto FINISH; } } break; } } } //printk("arp entry still not found.\n\n"); } while (0); } break; } } //printk("no rule found.\n"); break; } //#endif//end of CONFIG_PPTP //#ifdef CONFIG_NET_IPIP case IPPROTO_IPIP: { __u32 hash; struct Path_List_Entry *entry_path; DEBUGP_PKT("==>> SIP: %u.%u.%u.%u -> DIP: %u.%u.%u.%u <IPIP> #0x%x\n", NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), iph->frag_off); hash = FastPath_Hash_PATH_Entry(sIp, sPort, dIp, dPort, iph->protocol); //cathy //printk("hash=%d\n", hash); CTAILQ_FOREACH(entry_path, &table_path->list[hash], path_link) { if ((*entry_path->in_sIp == sIp) && (*entry_path->in_dIp == dIp) && (*entry_path->protocol == IPPROTO_IPIP)) { //cathy //printk("%s %d fp enter. \n", __func__, __LINE__); void *dst = getSkbDst(pskb); if(unlikely(NULL == entry_path->dst)){ if(!fp_iproute_output(pskb, iph)){ write_unlock_bh(&fp_path_lock); return 0; } SetFPDst(pskb, &entry_path->dst); entry_path->out_ifname = fastpath_getdstifName(entry_path->dst); setSkbDst(pskb, NULL); } #ifdef CONFIG_PPP if (entry_path->out_ifname && (!strncmp(entry_path->out_ifname, "ppp", 3))) { DEBUGP_PKT("%s %d pppoe proxy or upstream pppoe\n", __func__, __LINE__); dev = getDevFromDestentry(entry_path->dst); pppdev = 1; } #endif /* ARP Cache check */ if ((entry_path->arp_entry && entry_path->arp_entry->valid ) #ifdef CONFIG_PPP || pppdev #endif ) { //if (!pppdev) { /* ARP Cache valid */ setSkbDst(pskb, entry_path->dst); FastPathHoldDst(pskb); if (ipip_sanity_check(pskb, dst) == 0) goto FINISH; if (isDestLo(pskb)) goto FINISH; //} DEBUGP_PKT("FORWARD to [%s] \n", entry_path->out_ifname); if(br_port) { // Kevin, if the original source interface is under bridge (ex.br0) // update its aging time before the source MAC being modifeid in ip_finish_output3() #if 0//krammer move this to fp_common.c for making lib clean br_fdb_update(br_port->br, br_port , eth_hdr(((struct sk_buff *)pskb))->h_source); #else fp_br_fdb_update(br_port, pskb); #endif } if (entry_path->course == 1) { setQoSMark(pskb, entry_path->mark); setQosDscp(pskb, entry_path->mdscp, entry_path->mark); #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) setQoSIMQ(pskb, entry_path->imq_flags); #endif } entry_path->pps ++; if ((entry_path->pps > heavy_traffic) && !entry_path->add_into_asic_checked) { add_fastpath_to_asic(pskb, entry_path); } // Kevin, refresh nf_conntrack timeout if( jiffies - entry_path->last_refresh_time > 20*HZ) { entry_path->last_refresh_time = jiffies; fp_updateConxTimer(entry_path); } course = entry_path->course; #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) imq_flags = entry_path->imq_flags; #endif write_unlock_bh(&fp_path_lock); #ifdef CONFIG_PPP if (pppdev) #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) pppoe_proxy_output(pskb, dev, course, imq_flags); #else pppoe_proxy_output(pskb, dev, course); #endif else { #endif initSkbHdr(pskb); ip_finish_output3(pskb, course, imq_flags); #ifdef CONFIG_PPP } #endif return NET_RX_DROP; } else { /* Arp Cache update */ struct Arp_List_Entry *ep; __u32 hash = FastPath_Hash_ARP_Entry(*entry_path->out_dIp); //printk("%s %d out_dIP:%x\n", __func__, __LINE__, *entry_path->out_dIp); //printk("%s %d hash=%x\n", __func__, __LINE__, hash); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { //printk("%s %d ep->ip=%x out_dIP=%x\n", __func__, __LINE__, ep->ip, *entry_path->out_dIp); if (ep->ip == *entry_path->out_dIp) { entry_path->arp_entry = ep; goto FINISH; } } do { struct Route_List_Entry *rep; CTAILQ_FOREACH(rep, &route_list_inuse, tqe_link) { if((rep->ip & rep->mask) == (*entry_path->out_dIp & rep->mask)) { if (rep->gateway) { hash = FastPath_Hash_ARP_Entry(rep->gateway); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == rep->gateway) { entry_path->arp_entry = ep; goto FINISH; } } break; } } } //printk("arp entry still not found.\n\n"); } while (0); } break; } } //printk("no rule found.\n"); break; } //#endif//end of CONFIG_NET_IPIP case IPPROTO_ICMP:{ //cathy break; } default: { //cathy __u32 hash; struct Path_List_Entry *entry_path; hash = FastPath_Hash_PATH_Entry(sIp, sPort, dIp, dPort, iph->protocol); CTAILQ_FOREACH(entry_path, &table_path->list[hash], path_link) { if ((*entry_path->protocol == iph->protocol) && (*entry_path->in_sIp == sIp) && (*entry_path->in_dIp == dIp) ) { if(unlikely(NULL == entry_path->dst)){ if(!fp_iproute_input(pskb, iph, entry_path->out_dIp)){ write_unlock_bh(&fp_path_lock); return 0; } SetFPDst(pskb, &entry_path->dst); entry_path->out_ifname = fastpath_getdstifName(entry_path->dst); setSkbDst(pskb, NULL); if (isDestLo(pskb)) goto FINISH; } #ifdef CONFIG_PPP if (entry_path->out_ifname && (!strncmp(entry_path->out_ifname, "ppp", 3))) { DEBUGP_PKT("%s %d pppoe proxy or upstream pppoe\n", __func__, __LINE__); dev = getDevFromDestentry(entry_path->dst); pppdev = 1; } #endif /* ARP Cache check */ if ((entry_path->arp_entry && entry_path->arp_entry->valid ) #ifdef CONFIG_PPP || pppdev #endif ) { //if (!pppdev) { /* ARP Cache valid */ setSkbDst(pskb, entry_path->dst); FastPathHoldDst(pskb); if (isDestLo(pskb)) goto FINISH; //} DEBUGP_PKT("FORWARD to [%s] \n", entry_path->out_ifname); switch(entry_path->type) { case 0: { /* Only Routing */ break; } case 4: { /* DNAT */ FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_dIp, iph->daddr, iph->check); //FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_dIp, pskb->nh.iph->daddr, udph->check); iph->daddr = *entry_path->out_dIp; break; } default: { FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_sIp, iph->saddr, iph->check); FASTPATH_ADJUST_CHKSUM_NAT(*entry_path->out_dIp, iph->daddr, iph->check); //FASTPATH_ADJUST_CHKSUM_NAPT(*entry_path->out_sIp, pskb->nh.iph->saddr, *entry_path->out_sPort, udph->source, udph->check); //FASTPATH_ADJUST_CHKSUM_NAPT(*entry_path->out_dIp, pskb->nh.iph->daddr, *entry_path->out_dPort, udph->dest, udph->check); iph->saddr = *entry_path->out_sIp; //udph->source = *entry_path->out_sPort; iph->daddr = *entry_path->out_dIp; //udph->dest = *entry_path->out_dPort; break; } } //pskb->ip_summed = 0x0; //pskb->dst->output(pskb); /* ip_output() */ //pskb->dev = pskb->dst->dev; if(br_port) { // Kevin, if the original source interface is under bridge (ex.br0) // update its aging time before the source MAC being modifeid in ip_finish_output3() #if 0//krammer move this to fp_common.c for making lib clean br_fdb_update(br_port->br, br_port , eth_hdr(((struct sk_buff *)pskb))->h_source); #else fp_br_fdb_update(br_port, pskb); #endif } if (entry_path->course == 1) { setQoSMark(pskb, entry_path->mark); setQosDscp(pskb, entry_path->mdscp, entry_path->mark); #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) setQoSIMQ(pskb, entry_path->imq_flags); #endif } entry_path->pps ++; if ((entry_path->pps > heavy_traffic) && !entry_path->add_into_asic_checked) { add_fastpath_to_asic(pskb, entry_path); } // Kevin, refresh nf_conntrack timeout if( jiffies - entry_path->last_refresh_time > 20*HZ) { entry_path->last_refresh_time = jiffies; fp_updateConxTimer(entry_path); } course = entry_path->course; #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) imq_flags = entry_path->imq_flags; #endif write_unlock_bh(&fp_path_lock); #ifdef CONFIG_PPP if (pppdev) #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)||defined(CONFIG_ATP_SUPPORT_ETHUP) pppoe_proxy_output(pskb, dev, course, imq_flags); #else pppoe_proxy_output(pskb, dev, course); #endif else { #endif initSkbHdr(pskb); ip_finish_output3(pskb, course, imq_flags); #ifdef CONFIG_PPP } #endif return NET_RX_DROP; } else { /* Arp Cache update */ struct Arp_List_Entry *ep; __u32 hash = FastPath_Hash_ARP_Entry(*entry_path->out_dIp); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == *entry_path->out_dIp) { entry_path->arp_entry = ep; goto FINISH; } } do { struct Route_List_Entry *rep; CTAILQ_FOREACH(rep, &route_list_inuse, tqe_link) { if((rep->ip & rep->mask) == (*entry_path->out_dIp & rep->mask)) { if (rep->gateway) { hash = FastPath_Hash_ARP_Entry(rep->gateway); CTAILQ_FOREACH(ep, &table_arp->list[hash], arp_link) { if (ep->ip == rep->gateway) { entry_path->arp_entry = ep; goto FINISH; } } break; } } } } while (0); } break; } } break; } } FINISH: write_unlock_bh(&fp_path_lock); //if (dev) // dev_put(dev); return 0; } #ifdef DEBUG_PROCFILE /* static int fastpath_forward_proc(char *buffer, char **start, off_t offset, int length) { int len=0; len += sprnitf(buffer + len, "%d\n", fastpath_forward_flag); return len; } */ #if 0 static int __SWAP fastpath_table_arp(char *buffer, char **start, off_t offset, int length) { struct Arp_List_Entry *ep; int len=0; CTAILQ_FOREACH(ep, &arp_list_inuse, tqe_link) { len += sprintf(buffer + len, "~Arp: ip=0x%08X mac=%02X:%02X:%02X:%02X:%02X:%02X flags=0x%08X \n", ep->ip, MAC2STR(ep->mac), ep->flags); } return len; } #endif static int fastpath_table_arp_show(struct seq_file *m, void *v) { struct Arp_List_Entry *ep; CTAILQ_FOREACH(ep, &arp_list_inuse, tqe_link) { seq_printf(m, "~Arp: ip=0x%08X mac=%02X:%02X:%02X:%02X:%02X:%02X flags=0x%08X \n", ep->ip, MAC2STR(ep->mac), ep->flags); } return 0; } static int fastpath_table_arp_open(struct inode *inode, struct file *file) { return single_open(file, fastpath_table_arp_show, NULL); } static const struct file_operations fastpath_table_arp_proc_fops = { .open = fastpath_table_arp_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .owner = THIS_MODULE, }; #if 0 static int __SWAP fastpath_table_route(char *buffer, char **start, off_t offset, int length) { struct Route_List_Entry *ep; int len=0; CTAILQ_FOREACH(ep, &route_list_inuse, tqe_link) { len += sprintf(buffer + len, "~Route: ip=0x%08X mask=0x%08X gateway=0x%08X ifname=%-5s flags=0x%08X \n", ep->ip, ep->mask, ep->gateway, ep->ifname, ep->flags); } return len; } #endif static int fastpath_table_route_show(struct seq_file *m, void *v) { struct Route_List_Entry *ep; CTAILQ_FOREACH(ep, &route_list_inuse, tqe_link) { #if 0 seq_printf(m, "~Route: ip=0x%08X mask=0x%08X gateway=0x%08X ifname=%-5s flags=0x%08X \n", ep->ip, ep->mask, ep->gateway, ep->ifname, ep->flags); #else printk("~Route: ip=0x%08X mask=0x%08X gateway=0x%08X ifname=%-5s flags=0x%08X \n", ep->ip, ep->mask, ep->gateway, ep->ifname, ep->flags); #endif } return 0; } static int fastpath_table_route_open(struct inode *inode, struct file *file) { return single_open(file, fastpath_table_route_show, NULL); } static const struct file_operations fastpath_table_route_proc_fops = { .open = fastpath_table_route_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .owner = THIS_MODULE, }; #if 0 static int __SWAP fastpath_table_napt(char *buffer, char **start, off_t offset, int length) { struct Napt_List_Entry *ep; unsigned int len=0, newlen=0; //cathy __u8 *proto; off_t upto = 0; CTAILQ_FOREACH(ep, &napt_list_inuse, tqe_link) { if( upto++ < offset ) continue; if( ep->protocol == IPPROTO_TCP ) { proto = "TCP"; } else if( ep->protocol == IPPROTO_UDP ) { proto = "UDP"; } else { proto = "unknow"; } newlen = sprintf(buffer + len, "~Napt: [%s] int=0x%08X:%-5u ext=0x%08X:%-5u rem=0x%08X:%-5u flags=0x%08X \n", proto, ep->intIp, ep->intPort, ep->extIp, ep->extPort, ep->remIp, ep->remPort, ep->flags); if ( (len + newlen) > length) { goto finished; } else { len += newlen; } } finished: /* `start' hack - see fs/proc/generic.c line ~165 */ *start = (char *)((unsigned int)upto - offset); return len; } #endif static int fastpath_table_napt_show(struct seq_file *m, void *v) { struct Napt_List_Entry *ep; //cathy __u8 *proto; CTAILQ_FOREACH(ep, &napt_list_inuse, tqe_link) { if( ep->protocol == IPPROTO_TCP ) { proto = "TCP"; } else if( ep->protocol == IPPROTO_UDP ) { proto = "UDP"; } else { proto = "unknow"; } seq_printf(m, "~Napt: [%s] int=%u.%u.%u.%u:%u ext=%u.%u.%u.%u:%u rem=%u.%u.%u.%u:%u int_rem=%u.%u.%u.%u:%u flags=0x%08X state=%d \n", proto, NIPQUAD(ep->intIp), ep->intPort, NIPQUAD(ep->extIp), ep->extPort, NIPQUAD(ep->remIp), ep->remPort, NIPQUAD(ep->int_remIp), ep->int_remPort, ep->flags,ep->state); } return 0; } static int fastpath_table_napt_open(struct inode *inode, struct file *file) { return single_open(file, fastpath_table_napt_show, NULL); } static const struct file_operations fastpath_table_napt_proc_fops = { .open = fastpath_table_napt_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .owner = THIS_MODULE, }; #if 0 static int __SWAP fastpath_table_path(char *buffer, char **start, off_t offset, int length) { struct Path_List_Entry *ep; unsigned int len=0, newlen=0; //cathy __u8 *proto; off_t upto = 0; CTAILQ_FOREACH(ep, &path_list_inuse, tqe_link) { if( upto++ < offset ) continue; if( *ep->protocol == IPPROTO_TCP ) { proto = "TCP"; } else if( *ep->protocol == IPPROTO_UDP ) { proto = "UDP"; } else { proto = "unknow"; } newlen = sprintf(buffer + len, "~Path: [%s] in-S=0x%08X:%-5u in-D=0x%08X:%-5u out-S=0x%08X:%-5u out-D=0x%08X:%-5u out-ifname=%-5s <%u> {%d}\n", proto, *ep->in_sIp, *ep->in_sPort, *ep->in_dIp, *ep->in_dPort, *ep->out_sIp, *ep->out_sPort, *ep->out_dIp, *ep->out_dPort, ep->out_ifname, ep->course, ep->type); if ( (len + newlen) > length) { goto finished; } else { len += newlen; } } finished: /* `start' hack - see fs/proc/generic.c line ~165 */ *start = (char *)((unsigned int)upto - offset); return len; } #endif static int fastpath_table_path_show(struct seq_file *m, void *v) { struct Path_List_Entry *ep; //cathy __u8 *proto; seq_printf(m, "FP:\n"); CTAILQ_FOREACH(ep, &path_list_inuse, tqe_link) { if( *ep->protocol == IPPROTO_TCP ) { proto = "TCP"; } else if( *ep->protocol == IPPROTO_UDP ) { proto = "UDP"; } //#ifdef CONFIG_PPTP else if( *ep->protocol == IPPROTO_GRE ) { proto = "GRE"; } //#endif//end of CONFIG_PPTP //#ifdef CONFIG_NET_IPIP else if( *ep->protocol == IPPROTO_IPIP ) { proto = "IPIP"; } //#endif//end of CONFIG_NET_IPIP else { proto = "unknow"; } seq_printf(m, "<%5u> Path: [%s] in-S=%u.%u.%u.%u:%u in-D=%u.%u.%u.%u:%u out-S=%u.%u.%u.%u:%u out-D=%u.%u.%u.%u:%u out-ifname=%-5s <%u> {%d} => %x/%x" #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) "/%x" #endif "\n" , ep->pps, proto, NIPQUAD(*ep->in_sIp), *ep->in_sPort, NIPQUAD(*ep->in_dIp), *ep->in_dPort, NIPQUAD(*ep->out_sIp), *ep->out_sPort, NIPQUAD(*ep->out_dIp), *ep->out_dPort, ep->out_ifname, ep->course, ep->type, ep->mdscp, ep->mark #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) , ep->imq_flags #endif ); } #if defined(CONFIG_RTL_HW_NAPT_4KENTRY) seq_printf(m, "\nHW:\n"); { int i; struct Path_List_Entry *fp; for(i=0;i<RTL8676_TCPUDPTBL_SIZE_HW;i++) { fp = RTL_HWNAT_FP_MAPPING[i]; if(fp != NULL) { seq_printf(m, "HWNAT[%d] <%5u> Path: [%s] in-S=%u.%u.%u.%u:%u in-D=%u.%u.%u.%u:%u out-S=%u.%u.%u.%u:%u out-D=%u.%u.%u.%u:%u out-ifname=%-5s <%u> {%d} => %x/%x" #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) "/%x" #endif "\n" ,i, fp->pps, *fp->protocol==IPPROTO_TCP?"TCP":"UDP", NIPQUAD(*fp->in_sIp), *fp->in_sPort, NIPQUAD(*fp->in_dIp), *fp->in_dPort, NIPQUAD(*fp->out_sIp), *fp->out_sPort, NIPQUAD(*fp->out_dIp), *fp->out_dPort, fp->out_ifname, fp->course, fp->type, fp->mdscp, fp->mark #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) , fp->imq_flags #endif ); } } } #endif return 0; } static int fastpath_table_path_open(struct inode *inode, struct file *file) { return single_open(file, fastpath_table_path_show, NULL); } static const struct file_operations fastpath_table_path_proc_fops = { .open = fastpath_table_path_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .owner = THIS_MODULE, }; #if 0 static int __SWAP fastpath_hash_path(char *buffer, char **start, off_t offset, int length) { int i, len=0; for (i=0; i<PATH_TABLE_LIST_MAX; i++) { len += sprintf(buffer + len, "%5d ", CTAILQ_TOTAL(&table_path->list[i])); if (i%12 == 11) len += sprintf(buffer + len, "\n"); } len += sprintf(buffer + len, "\n"); return len; } #endif static int fastpath_hash_path_show(struct seq_file *m, void *v) { int i; for (i=0; i<PATH_TABLE_LIST_MAX; i++) { seq_printf(m, "%5d ", CTAILQ_TOTAL(&table_path->list[i])); if (i%12 == 11) seq_printf(m, "\n"); } seq_printf(m, "\n"); return 0; } static int fastpath_hash_path_open(struct inode *inode, struct file *file) { return single_open(file, fastpath_hash_path_show, NULL); } static const struct file_operations fastpath_hash_path_proc_fops = { .open = fastpath_hash_path_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, .owner = THIS_MODULE, }; #endif /* DEBUG_PROCFILE */ static struct proc_dir_entry *FP_Proc_File; static struct proc_dir_entry *FP_Proc_File_heavy_traffic_thres; #define PROCFS_NAME "FastPath" #define PROCFS_NAME_H "FastPath_heavy_traffic_thres" #define REALTEK_FASTPATH_VERSION "Realtek FastPath-betaV1.00" #include <asm/uaccess.h> #ifdef CONFIG_IPV6 extern int ip6_fp_on; #endif static int fp_proc_read( struct seq_file* s, void* v ) { int len=0; #ifdef CONFIG_DSL_CODESWAP len = seq_printf(s, "admin:%d op:%d\n", fp_admin, fp_on); #else if(fp_on==2) len = seq_printf(s, "%s fastpath ON!(both up and downstream)\n",REALTEK_FASTPATH_VERSION); if(fp_on==1) len = seq_printf(s, "%s fastpath ON!(only downstream)\n",REALTEK_FASTPATH_VERSION); if(fp_on==0) len = seq_printf(s, "%s fastpath OFF!\n",REALTEK_FASTPATH_VERSION); #ifdef CONFIG_IPV6 if(ip6_fp_on==0) len = seq_printf(s, "%s IPv6 fastpath OFF!\n",REALTEK_FASTPATH_VERSION); else if(ip6_fp_on==1) len = seq_printf(s, "%s IPv6 fastpath ON!\n",REALTEK_FASTPATH_VERSION); #endif #endif return len; } #ifdef CONFIG_RTL867X_KERNEL_MIPS16_NET __NOMIPS16 #endif static ssize_t fp_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) { char proc_buffer[count]; /* write data to the buffer */ memset(proc_buffer, 0, sizeof(proc_buffer)); if ( copy_from_user(proc_buffer, buffer, count) ) { return -EFAULT; } //DEBUGP_API("Old_State:%d ", fp_state); switch(proc_buffer[0]) { #ifdef CONFIG_DSL_CODESWAP case '0': fastpath_notify(EVT_ADMIN_DOWN); break; case '1': fastpath_notify(EVT_ADMIN_UP); break; /* case '2': fastpath_notify(EVT_SAR_UP); break; case '3': fastpath_notify(EVT_SAR_DOWN); break; */ #else #ifdef CONFIG_IPV6 case '0': fp_on = 0; ip6_fp_on = 0; break; case '1': fp_on = 1; ip6_fp_on = 1; break; case '2': fp_on = 2; ip6_fp_on = 1; break; #else case '0': fp_on = 0; break; case '1': fp_on = 1; break; case '2': fp_on = 2; break; #endif #endif default: printk("Error setting!\n"); } //DEBUGP_API("New_State:%d\n", fp_state); return count; } static int fp_proc_open(struct inode *inode, struct file *file) { return(single_open(file, fp_proc_read, NULL)); } static const struct file_operations fp_proc_fops = { .open = fp_proc_open, .write = fp_proc_write, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int fp_proc_heavy_traffic_thres_read( struct seq_file* s, void* v ) { int len=0; len = seq_printf(s, "heavy traffic thres. = %d\n",heavy_traffic); return len; } static ssize_t fp_proc_heavy_traffic_thres_write(struct file *file, const char __user *buffer, size_t count, loff_t *data) { char tmpbuf[512]; char *strptr; if (buffer && !copy_from_user(tmpbuf, buffer, count)) { tmpbuf[count] = '\0'; strptr=tmpbuf; heavy_traffic=simple_strtol(strptr, NULL, 0); printk("heavy traffic thres. = %d\n",heavy_traffic); } return count; } static int fp_proc_heavy_traffic_thres_proc_open(struct inode *inode, struct file *file) { return(single_open(file, fp_proc_heavy_traffic_thres_read, NULL)); } static const struct file_operations fp_proc_heavy_traffic_thres_proc_fops = { .open = fp_proc_heavy_traffic_thres_proc_open, .write = fp_proc_heavy_traffic_thres_write, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; #ifdef CONFIG_DSL_CODESWAP //static int xxxx __attribute__((section (".DSPShowtime.data"))); static struct Arp_Table table_arp_0 __SWAP_DATA; static struct Arp_List_Entry entry_arp_array[ARP_TABLE_ENTRY_MAX] __SWAP_DATA; static struct Route_Table table_route_0 __SWAP_DATA; static struct Route_List_Entry entry_route_array[ROUTE_TABLE_ENTRY_MAX] __SWAP_DATA; static struct Napt_Table table_napt_0 __SWAP_DATA; static struct Napt_List_Entry entry_napt_array[NAPT_TABLE_ENTRY_MAX] __SWAP_DATA; static struct Path_Table table_path_0 __SWAP_DATA; static struct Path_List_Entry entry_path_array[PATH_TABLE_ENTRY_MAX] __SWAP_DATA; #endif static int __SWAP fastpath_memory_init(void) { int i; #ifdef CONFIG_DSL_CODESWAP /* Arp-Table Init */ table_arp = &table_arp_0; CTAILQ_INIT(&arp_list_inuse); CTAILQ_INIT(&arp_list_free); for (i=0; i<ARP_TABLE_LIST_MAX; i++) { CTAILQ_INIT(&table_arp->list[i]); } /* Arp-List Init */ for (i=0; i<ARP_TABLE_ENTRY_MAX; i++) { struct Arp_List_Entry *entry_arp; entry_arp = &entry_arp_array[i]; CTAILQ_INSERT_TAIL(&arp_list_free, entry_arp, tqe_link); } /* Route-Table Init */ table_route = &table_route_0; CTAILQ_INIT(&route_list_inuse); CTAILQ_INIT(&route_list_free); for (i=0; i<ROUTE_TABLE_LIST_MAX; i++) { CTAILQ_INIT(&table_route->list[i]); } /* Route-List Init */ for (i=0; i<ROUTE_TABLE_ENTRY_MAX; i++) { struct Route_List_Entry *entry_route; entry_route = &entry_route_array[i]; CTAILQ_INSERT_TAIL(&route_list_free, entry_route, tqe_link); } /* Napt-Table Init */ table_napt = &table_napt_0; CTAILQ_INIT(&napt_list_inuse); CTAILQ_INIT(&napt_list_free); for (i=0; i<NAPT_TABLE_LIST_MAX; i++) { CTAILQ_INIT(&table_napt->list[i]); } /* Napt-List Init */ for (i=0; i<NAPT_TABLE_ENTRY_MAX; i++) { struct Napt_List_Entry *entry_napt; entry_napt = &entry_napt_array[i]; /*struct Napt_List_Entry *entry_napt = (struct Napt_List_Entry *)kmalloc(sizeof(struct Napt_List_Entry), GFP_ATOMIC); if (entry_napt == NULL) { DEBUGP_SYS("MALLOC Failed! (Napt Table Entry) \n"); return -2; }*/ CTAILQ_INSERT_TAIL(&napt_list_free, entry_napt, tqe_link); } /* Path-Table Init */ table_path = &table_path_0; CTAILQ_INIT(&path_list_inuse); CTAILQ_INIT(&path_list_free); MAX_FASTPATH_NUMBER=0; for (i=0; i<PATH_TABLE_LIST_MAX; i++) { CTAILQ_INIT(&table_path->list[i]); } /* Path-List Init */ for (i=0; i<PATH_TABLE_ENTRY_MAX; i++) { struct Path_List_Entry *entry_path; entry_path = &entry_path_array[i]; CTAILQ_INSERT_TAIL(&path_list_free, entry_path, tqe_link); } return 0; #else /* Arp-Table Init */ table_arp = (struct Arp_Table *)kmalloc(sizeof(struct Arp_Table), GFP_ATOMIC); if (table_arp == NULL) { DEBUGP_SYS("MALLOC Failed! (Arp Table) \n"); return -1; } CTAILQ_INIT(&arp_list_inuse); CTAILQ_INIT(&arp_list_free); for (i=0; i<ARP_TABLE_LIST_MAX; i++) { CTAILQ_INIT(&table_arp->list[i]); } /* Arp-List Init */ for (i=0; i<ARP_TABLE_ENTRY_MAX; i++) { struct Arp_List_Entry *entry_arp = (struct Arp_List_Entry *)kmalloc(sizeof(struct Arp_List_Entry), GFP_ATOMIC); if (entry_arp == NULL) { DEBUGP_SYS("MALLOC Failed! (Arp Table Entry) \n"); return -2; } CTAILQ_INSERT_TAIL(&arp_list_free, entry_arp, tqe_link); } /* Route-Table Init */ table_route = (struct Route_Table *)kmalloc(sizeof(struct Route_Table), GFP_ATOMIC); if (table_route == NULL) { DEBUGP_SYS("MALLOC Failed! (Route Table) \n"); return -1; } CTAILQ_INIT(&route_list_inuse); CTAILQ_INIT(&route_list_free); for (i=0; i<ROUTE_TABLE_LIST_MAX; i++) { CTAILQ_INIT(&table_route->list[i]); } /* Route-List Init */ for (i=0; i<ROUTE_TABLE_ENTRY_MAX; i++) { struct Route_List_Entry *entry_route = (struct Route_List_Entry *)kmalloc(sizeof(struct Route_List_Entry), GFP_ATOMIC); if (entry_route == NULL) { DEBUGP_SYS("MALLOC Failed! (Route Table Entry) \n"); return -2; } CTAILQ_INSERT_TAIL(&route_list_free, entry_route, tqe_link); } /* Napt-Table Init */ table_napt = (struct Napt_Table *)kmalloc(sizeof(struct Napt_Table), GFP_ATOMIC); if (table_napt == NULL) { DEBUGP_SYS("MALLOC Failed! (Napt Table) \n"); return -1; } CTAILQ_INIT(&napt_list_inuse); CTAILQ_INIT(&napt_list_free); for (i=0; i<NAPT_TABLE_LIST_MAX; i++) { CTAILQ_INIT(&table_napt->list[i]); } /* Napt-List Init */ for (i=0; i<NAPT_TABLE_ENTRY_MAX; i++) { struct Napt_List_Entry *entry_napt = (struct Napt_List_Entry *)kmalloc(sizeof(struct Napt_List_Entry), GFP_ATOMIC); if (entry_napt == NULL) { DEBUGP_SYS("MALLOC Failed! (Napt Table Entry) \n"); return -2; } CTAILQ_INSERT_TAIL(&napt_list_free, entry_napt, tqe_link); } /* Path-Table Init */ table_path = (struct Path_Table *)kmalloc(sizeof(struct Path_Table), GFP_ATOMIC); if (table_path == NULL) { DEBUGP_SYS("MALLOC Failed! (Path Table) \n"); return -1; } CTAILQ_INIT(&path_list_inuse); CTAILQ_INIT(&path_list_free); MAX_FASTPATH_NUMBER=0; for (i=0; i<PATH_TABLE_LIST_MAX; i++) { CTAILQ_INIT(&table_path->list[i]); } /* Path-List Init */ for (i=0; i<PATH_TABLE_ENTRY_MAX; i++) { struct Path_List_Entry *entry_path = (struct Path_List_Entry *)kmalloc(sizeof(struct Path_List_Entry), GFP_ATOMIC); if (entry_path == NULL) { DEBUGP_SYS("MALLOC Failed! (Path Table Entry) \n"); return -2; } CTAILQ_INSERT_TAIL(&path_list_free, entry_path, tqe_link); } rwlock_init(&fp_arp_lock); rwlock_init(&fp_route_lock); rwlock_init(&fp_napt_lock); rwlock_init(&fp_path_lock); return 0; #endif } #ifdef CONFIG_DSL_CODESWAP static void __SWAP fastpath_swap_start(void) { extern void ARP_Fastpath_Init(void); extern void Route_Fastpath_Init(void); extern void IPCT_Fastpath_Init(void); fastpath_memory_init(); ARP_Fastpath_Init(); Route_Fastpath_Init(); IPCT_Fastpath_Init(); } // called by lower layer (ie. SAR) to enable FP, return OP status. (0 down, 1 up) void fastpath_notify(int event) { DEBUGP_API("Event:%d ", event); switch (fp_state) { case ST_INIT: switch (event) { case EVT_SAR_UP: fp_on = 1; fastpath_swap_start(); fp_state = ST_OPERATIONAL; break; case EVT_ADMIN_DOWN: fp_on = fp_admin = 0; fp_state = ST_ADMIN_DOWN; break; } break; case ST_OPERATIONAL: switch (event) { case EVT_SAR_DOWN: fp_on = 0; fp_state = ST_INIT; break; case EVT_ADMIN_DOWN: fp_on = fp_admin = 0; fp_state = ST_ADMIN_DOWN; break; } break; case ST_ADMIN_DOWN: switch (event) { case EVT_ADMIN_UP: fp_admin = 1; if (DSPInShowtime) { fp_on = 1; fp_state = ST_OPERATIONAL; fastpath_swap_start(); } else { fp_state = ST_INIT; } break; } break; } } #endif static int __init fastpath_init(void) { #if defined(CONFIG_NF_CONNTRACK_EVENTS) && defined(CONFIG_NF_CT_NETLINK) && defined(CONFIG_RTL_EVENT_TRIGGER_HWNAT) extern int fastpath_event_init(void); #endif #ifdef DEBUG_PROCFILE /* proc file for debug */ proc_create("fp_arp", 0, init_net.proc_net, &fastpath_table_arp_proc_fops); proc_create("fp_route", 0, init_net.proc_net, &fastpath_table_route_proc_fops); proc_create("fp_napt", 0, init_net.proc_net, &fastpath_table_napt_proc_fops); proc_create("fp_path", 0, init_net.proc_net, &fastpath_table_path_proc_fops); proc_create("fp_hash_path", 0, init_net.proc_net, &fastpath_hash_path_proc_fops); #endif /* DEBUG_PROCFILE */ printk("%s %s\n",MODULE_NAME, MODULE_VERSION_FP); //create proc FP_Proc_File = proc_create_data(PROCFS_NAME, 0644, NULL, &fp_proc_fops, NULL); if (FP_Proc_File == NULL) { printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", PROCFS_NAME); return -ENOMEM; } printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME); FP_Proc_File_heavy_traffic_thres = proc_create_data(PROCFS_NAME_H, 0644, NULL, &fp_proc_heavy_traffic_thres_proc_fops, NULL); if (FP_Proc_File_heavy_traffic_thres == NULL) { printk(KERN_ALERT "Error: Could not initialize /proc/%s\n", PROCFS_NAME_H); return -ENOMEM; } printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME_H); #ifndef CONFIG_DSL_CODESWAP fastpath_memory_init(); #endif #if defined(CONFIG_RTL_HW_NAPT_4KENTRY) { int i; for(i=0;i<RTL8676_TCPUDPTBL_SIZE_HW;i++) RTL_HWNAT_FP_MAPPING[i] = NULL; } #endif init_timer(&fp_monitor_timer); #if defined(CONFIG_RTL_HW_NAPT_4KENTRY) fp_monitor_timer.function = trf_monitor_timeout; #else fp_monitor_timer.function = fp_monitor_timeout; #endif fp_monitor_timer.data = (unsigned long)NULL; mod_timer(&fp_monitor_timer, jiffies + HZ); #if defined(CONFIG_NF_CONNTRACK_EVENTS) && defined(CONFIG_NF_CT_NETLINK) && defined(CONFIG_RTL_EVENT_TRIGGER_HWNAT) fastpath_event_init(); #endif return 0; } static void __exit fastpath_exit(void) { printk("%s %s removed!\n", MODULE_NAME, MODULE_VERSION_FP); if(timer_pending(&fp_monitor_timer)){ del_timer(&fp_monitor_timer); } } module_init(fastpath_init); module_exit(fastpath_exit); MODULE_LICENSE("GPL"); /* 2006-08/29: ! Ignore TCP packet with FIN/RST/SYN flag (OR). ! Ignore fragment of UDP packet. 2006-08/28: ! NAT/NAPT bug fixed(RNAT/RNAPT NOT Working). */ #if defined(CONFIG_RTL_EVENT_TRIGGER_HWNAT) && defined(CONFIG_NF_CONNTRACK_EVENTS) #if (defined(CONFIG_RTL_HARDWARE_NAT) && defined(CONFIG_RTL8676_Dynamic_ACL)) || defined(CONFIG_RTK_FASTPATH) #include <linux/kernel.h> #include <linux/module.h> #include <asm/atomic.h> #include <linux/ip.h> #include <linux/version.h> #include <linux/skbuff.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #include <linux/moduleparam.h> #include <linux/netfilter_ipv4/ip_tables.h> #include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_helper.h> #if defined(CONFIG_RTK_FASTPATH) #include "../../../realtek/fastpath/ipv4/fastpath_core.h" #if defined(CONFIG_RTL_ADV_FAST_PATH) #include <net/dsfield.h> #include <linux/netfilter/xt_dscp.h> #include <linux/netfilter_bridge/ebt_ftos_t.h> #define XT_DSCP_MASK 0xfc /* 11111100 */ #define XT_DSCP_SHIFT 2 #define XT_DSCP_MAX 0x3f /* 00111111 */ #define XT_DSCP_EN 0x1000000 #define XT_DSCP_TYPE_SHIFT 16 #endif #endif static unsigned int fastpath_hook_func(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { u_int8_t dscp; struct nf_conn *ct; enum ip_conntrack_info ctinfo; extern int isWanDevice(struct net_device *dev); ct = nf_ct_get(skb, &ctinfo); if(ct && nf_ct_l3num(ct)==PF_INET) { const struct nf_conn_help *help; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); help = nfct_help(ct); /* udp fastpath is allowed to be built on uni direction, and other fastpath is needed to be built when kernel conntrack status is assued */ if((!test_bit(IPS_ASSURED_BIT, &ct->status)) && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != IPPROTO_UDP) goto FINISH; if(test_bit(IPS_SEEN_REPLY_BIT, &ct->status) && dir == IP_CT_DIR_REPLY && !test_bit(IPS_FASTPATH_FIREWALL_BIT, &ct->status)) set_bit(IPS_FASTPATH_FIREWALL_BIT, &ct->status); ct->m_1p=skb->mark; #if defined(CONFIG_RTL_ADV_FAST_PATH) if (skb->dev && isWanDevice(skb->dev)){ ct->qosmark=skb->mark; /* Fill the mdscp */ dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; if(dscp){ //printk("[%s] dscp = 0x%X\n",__func__,dscp); skb->mdscp = (XT_DSCP_EN | (FTOS_SETFTOS << XT_DSCP_TYPE_SHIFT) | (dscp << XT_DSCP_SHIFT) ); } } #endif /* CONFIG_RTL_ADV_FAST_PATH */ if (!(help && help->helper) && ( // uni-direction UDP stream to go fastpath #ifdef SUPPORT_UDP_UNI_DIRECTION (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) || #endif test_bit(IPS_FASTPATH_FIREWALL_BIT, &ct->status) ) && ( ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != IPPROTO_ICMP ) #if 0 //(defined(CONFIG_RTL_HARDWARE_NAT) && defined(CONFIG_RTL8676_Dynamic_ACL)) || defined(CONFIG_RTL867X_IPTABLES_FAST_PATH) && ((skb->from_dev && (skb->from_dev->priv_flags&(IFF_DOMAIN_ELAN|IFF_DOMAIN_WLAN))) || ((skb->dev && (skb->dev->priv_flags&IFF_DOMAIN_WAN)))) #endif && (ops->hooknum==NF_INET_POST_ROUTING) ) { #ifdef CONFIG_RTL_ADV_FAST_PATH if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_TCP) { if (ct->proto.tcp.state==TCP_CONNTRACK_ESTABLISHED) { if (!test_bit(IPS_FASTPATH_TCP_DONE_BIT, &ct->status)) { /* After establishing the TCP connection, bypass the first LAN to WAN packet due to unclear DSCP mark */ set_bit(IPS_FASTPATH_TCP_DONE_BIT, &ct->status); goto FINISH; } } else goto FINISH; } #endif /* CONFIG_RTL_ADV_FAST_PATH */ #ifdef CONFIG_RTK_FASTPATH if (!test_bit(IPS_FASTPATH_DONE_BIT, &ct->status) && FastPath_Enabled()) { int ret; ret = fastpath_addRoutedNaptConnection(skb,ct,ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, ct->tuplehash[IP_CT_DIR_REPLY].tuple, NP_NONE,1); #if defined(SIP_LIMIT_CHECK) ct->stream_num=0; #endif if(ret==LR_SUCCESS) { set_bit(IPS_FASTPATH_DONE_BIT, &ct->status); } } #endif #if !defined(TRAFFIC_MONITOR) #if defined(CONFIG_RTL_HARDWARE_NAT) && defined(CONFIG_RTL8676_Dynamic_ACL) #if defined(CONFIG_RTL_LAYERED_DRIVER) && defined(CONFIG_RTL_LAYERED_DRIVER_L2) if(!test_bit(IPS_8676HW_NAPT_DONE_BIT, &ct->status) && skb->dst && skb->dst->neighbour) { /*QL 20111223 : L2 header will be determinated in ip_finish_ouput, here it is uncertain, so we should check if l2 header is retrievable here?*/ if (skb_mac_header_was_set(skb) && (SUCCESS == rtl865x_Lookup_L2_by_MAC(eth_hdr(skb)->h_source)) && (strncmp(skb->dst->dev->name,"lo",2)!=0) /* ysleu@20140612:Does not support HWNAT on " lo" interface. */) { int ret; u32 upstream_nexthop_ip; read_lock_bh(&skb->dst->neighbour->lock); upstream_nexthop_ip = *(u32*)skb->dst->neighbour->primary_key; read_unlock_bh(&skb->dst->neighbour->lock); #ifdef CONFIG_RTL_HW_QOS_SUPPORT { struct smux_dev_info *dev_info; struct net_device *master_dev=NULL; rtl865x_netif_local_t *slave_netif, *master_n etif=NULL; //ysleu: Get master device while dest. interface is PPP. if(strncmp(skb->dst->dev->name,"ppp",3)==0) { slave_netif = _rtl865x_getSWNetifByName(skb->dst->dev->name); if (!slave_netif) goto FINISH; master_netif = slave_netif->master; if(master_netif) master_dev = dev_get_by_name( &init_net,master_netif->name); } if(master_dev){ dev_info = SMUX_DEV_INFO(master_dev); dev_put(master_dev); } else dev_info = SMUX_DEV_INFO(skb->dst->dev); if(dev_info && dev_info->m_1p!=0) { if((ct->m_1p&0xffff)>>8>=1) { ret = rtl8676_add_L34Unicast_hwacc_ct(ct,upstream_nexthop_ip, skb->dst->dev->name,1,0,ct->m_1p&0x7,0); } else { ret = rtl8676_add_L34Unicast_hwacc_ct(ct,upstream_nexthop_ip, skb->dst->dev->name,1,0,dev_info->m_1p-1,0); } } else{ ret = rtl8676_add_L34Unicast_hwacc_ct(ct,upstream_nexthop_ip, skb->dst->dev->name,0,0,0,0); } } #else ret = rtl8676_add_L34Unicast_hwacc_ct(ct,upstream_nexthop_ip, skb->dst->dev->name); #endif if(ret==SUCCESS) set_bit(IPS_8676HW_NAPT_BIT, &ct->status); } set_bit(IPS_8676HW_NAPT_DONE_BIT, &ct->status); } #endif #endif #endif } } FINISH: return NF_ACCEPT; } static struct nf_hook_ops fastpath_hook_ops = { .hook = fastpath_hook_func, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP_PRI_CONNTRACK_CONFIRM, }; static int __init fastpath_hook_init(void) { return nf_register_hook(&fastpath_hook_ops); } static void __exit fastpath_hook_fini(void) { nf_unregister_hook(&fastpath_hook_ops); } module_init(fastpath_hook_init); module_exit(fastpath_hook_fini); #endif #endif