--- zzzz-none-000/linux-2.6.32.61/net/netfilter/nf_conntrack_core.c 2013-06-10 09:43:48.000000000 +0000 +++ ar9-7330-650/linux-2.6.32.61/net/netfilter/nf_conntrack_core.c 2012-01-10 08:39:55.000000000 +0000 @@ -45,6 +45,11 @@ #include #include +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + #include + static atomic_t g_ppa_force_timeout = {0}; +#endif + #define NF_CONNTRACK_VERSION "0.5.0" int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, @@ -67,6 +72,15 @@ static int nf_conntrack_hash_rnd_initted; static unsigned int nf_conntrack_hash_rnd; +#ifdef CONFIG_ATHRS_HW_NAT + +athr_nf_nat_ops_t *athr_nat_sw_ops; +EXPORT_SYMBOL_GPL(athr_nat_sw_ops); + +uint32_t hash_conntrack(const struct nf_conntrack_tuple *tuple); +EXPORT_SYMBOL(hash_conntrack); +#endif + static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple, unsigned int size, unsigned int rnd) { @@ -85,8 +99,13 @@ return ((u64)h * size) >> 32; } +#ifdef CONFIG_ATHRS_HW_NAT +uint32_t hash_conntrack(const struct net *net, + const struct nf_conntrack_tuple *tuple) +#else static inline u_int32_t hash_conntrack(const struct net *net, const struct nf_conntrack_tuple *tuple) +#endif { return __hash_conntrack(tuple, net->ct.htable_size, nf_conntrack_hash_rnd); @@ -166,6 +185,12 @@ clean_from_lists(struct nf_conn *ct) { pr_debug("clean_from_lists(%p)\n", ct); +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + if ( ppa_hook_session_del_fn != NULL ) + { + ppa_hook_session_del_fn(ct, PPA_F_SESSION_ORG_DIR | PPA_F_SESSION_REPLY_DIR); + } +#endif hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode); @@ -184,6 +209,12 @@ NF_CT_ASSERT(atomic_read(&nfct->use) == 0); NF_CT_ASSERT(!timer_pending(&ct->timeout)); +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + if ( ppa_hook_session_del_fn != NULL ) + { + ppa_hook_session_del_fn(ct, PPA_F_SESSION_ORG_DIR | PPA_F_SESSION_REPLY_DIR); + } +#endif /* To make sure we don't get any weird locking issues here: * destroy_conntrack() MUST NOT be called with a write lock * to nf_conntrack_lock!!! -HW */ @@ -201,6 +232,14 @@ * too. */ nf_ct_remove_expectations(ct); + #if defined(CONFIG_NETFILTER_XT_MATCH_LAYER7) || defined(CONFIG_NETFILTER_XT_MATCH_LAYER7_MODULE) + if(ct->layer7.app_proto) + kfree(ct->layer7.app_proto); + if(ct->layer7.app_data) + kfree(ct->layer7.app_data); + #endif + + /* We overload first tuple to link into unconfirmed list. */ if (!nf_ct_is_confirmed(ct)) { BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode)); @@ -272,6 +311,39 @@ { struct nf_conn *ct = (void *)ul_conntrack; +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + /* if this function is called from within a timer interrupt then the timer + has actually expired. We need to make this distinction since this function + is also called to remove conntrack's for various reasons other than inactivity + timeout */ + + if ( !atomic_read(&g_ppa_force_timeout) && ppa_hook_inactivity_status_fn != NULL) + { + if ( ppa_hook_inactivity_status_fn((PPA_U_SESSION *)ct) == IFX_PPA_HIT ) + { + nf_ct_refresh(ct, 0, 60 * HZ); //to check again after default seconds + + if( !timer_pending(&ct->timeout) ) + { + ct->timeout.expires = jiffies + 60 * HZ; + add_timer(&ct->timeout); + } + return; + } + } +#endif + +#ifdef CONFIG_ATHRS_HW_NAT + void (*athr_process_hwnat)(struct sk_buff *, struct nf_conn *, + enum ip_conntrack_info, u_int8_t); + + if (athr_nat_sw_ops) { + athr_process_hwnat = rcu_dereference(athr_nat_sw_ops->nf_process_nat); + if (athr_process_hwnat) + athr_process_hwnat(NULL, ct, 0, 0); + } +#endif + if (!test_bit(IPS_DYING_BIT, &ct->status) && unlikely(nf_conntrack_event(IPCT_DESTROY, ct) < 0)) { /* destroy event was not delivered */ @@ -469,6 +541,12 @@ struct net *net = nf_ct_net(ignored_conntrack); struct nf_conntrack_tuple_hash *h; struct hlist_nulls_node *n; + unsigned int hash = hash_conntrack(tuple); +#ifdef CONFIG_ATHRS_HW_NAT + int (*athr_tuple_taken)(const struct nf_conntrack_tuple *, + const struct nf_conn *); +#endif /*--- #ifdef CONFIG_ATHRS_HW_NAT ---*/ + unsigned int hash = hash_conntrack(net, tuple); /* Disable BHs the entire time since we need to disable them at @@ -486,6 +564,14 @@ } rcu_read_unlock_bh(); +#ifdef CONFIG_ATHRS_HW_NAT + if (athr_nat_sw_ops) { + athr_tuple_taken = rcu_dereference(athr_nat_sw_ops->nf_tuple_taken); + if (athr_tuple_taken) + return athr_tuple_taken(tuple, ignored_conntrack); + } +#endif + return 0; } EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken); @@ -527,7 +613,14 @@ return dropped; if (del_timer(&ct->timeout)) { +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + atomic_inc(&g_ppa_force_timeout); +#endif death_by_timeout((unsigned long)ct); +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + atomic_dec(&g_ppa_force_timeout); +#endif + dropped = 1; NF_CT_STAT_INC_ATOMIC(net, early_drop); } @@ -535,6 +628,80 @@ return dropped; } +#define LTQ_IP_CONNTRACK_REPLACEMENT + +#undef LTQ_IP_CONNTRACK_REPLACEMENT_DEBUG + +#ifdef LTQ_IP_CONNTRACK_REPLACEMENT +static inline int drop_decision(void) +{ /*return value: 1-drop currnet nf_conn, 0-not drop current nf_conntrack */ + + /*Later we need to optimize here, like how to keep sip ALG, + * voice RTP and so on */ + return 1; +} + + +//static int FindReplacement( const struct nf_conntrack_tuple *tuple, const struct nf_conntrack_l3proto *protoco) +/* Enhance : need to traverse reverse in the list , right now implementation is + * similiar as early_drop*/ +static int FindReplacement(struct net *net) +{ + /* Traverse backwards: gives us oldest, which is roughly LRU */ + struct nf_conntrack_tuple_hash *h; + int dropped = 0, i; + struct hlist_nulls_node *n; + static unsigned int hash_next=0 ; //save for next replacement + struct nf_conn *ct = NULL, *tmp; + +#ifdef LTQ_IP_CONNTRACK_REPLACEMENT_DEBUG + printk(KERN_WARNING "iptables full:ip_conntrack_max(%d)_ip_conntrack_count(%d)_hash_next(%d)\n", nf_conntrack_max, atomic_read(&net->ct.count),hash_next ); +#endif + rcu_read_lock(); + + for (i=0; i < net->ct.htable_size; i++) /*control loop times*/ { + hash_next = (hash_next + 1) % net->ct.htable_size; + hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash_next],hnnode) + { + tmp = nf_ct_tuplehash_to_ctrack(h); + if (drop_decision() && (atomic_read(&tmp->ct_general.use) == 1)) { + ct = tmp; + break; + } + } + } + + rcu_read_unlock(); + + if (!ct) { +#ifdef LTQ_IP_CONNTRACK_REPLACEMENT_DEBUG + printk(KERN_WARNING "Not found replacemnet ???\n"); +#endif + return dropped; + } +#ifdef LTQ_IP_CONNTRACK_REPLACEMENT_DEBUG + printk(KERN_WARNING "replace ok:%d\n", hash_next); +#endif + if (del_timer(&ct->timeout)) { +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + atomic_inc(&g_ppa_force_timeout); +#endif + + death_by_timeout((unsigned long)ct); + +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + atomic_dec(&g_ppa_force_timeout); +#endif + dropped = 1; + NF_CT_STAT_INC_ATOMIC(net, early_drop); + } + nf_ct_put(ct); + return dropped; +} + +#endif + + struct nf_conn *nf_conntrack_alloc(struct net *net, const struct nf_conntrack_tuple *orig, const struct nf_conntrack_tuple *repl, @@ -555,6 +722,15 @@ unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) { unsigned int hash = hash_conntrack(net, orig); if (!early_drop(net, hash)) { +#ifdef LTQ_IP_CONNTRACK_REPLACEMENT + if( FindReplacement(net) ) + { +#ifdef LTQ_IP_CONNTRACK_REPLACEMENT_DEBUG + printk(KERN_WARNING "inside nf_conntrack_alloc ok\n"); +#endif + goto SUCCESS_REPLACEMENT; + } +#endif atomic_dec(&net->ct.count); if (net_ratelimit()) printk(KERN_WARNING @@ -564,6 +740,9 @@ } } +#ifdef LTQ_IP_CONNTRACK_REPLACEMENT +SUCCESS_REPLACEMENT: +#endif /* * Do not use kmem_cache_zalloc(), as this cache uses * SLAB_DESTROY_BY_RCU. @@ -625,12 +804,21 @@ struct nf_conn_help *help; struct nf_conntrack_tuple repl_tuple; struct nf_conntrack_expect *exp; +#ifdef CONFIG_ATHRS_HW_NAT + void (*athr_get_wan_addr)(uint32_t *); +#endif if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) { pr_debug("Can't invert tuple.\n"); return NULL; } - +#ifdef CONFIG_ATHRS_HW_NAT + if ((skb->ath_hw_nat_fw_flags == 3) && athr_nat_sw_ops) { + athr_get_wan_addr = rcu_dereference(athr_nat_sw_ops->get_wan_ipaddr); + if (athr_get_wan_addr) + athr_get_wan_addr(&tuple->dst.u3.ip); + } +#endif ct = nf_conntrack_alloc(net, tuple, &repl_tuple, GFP_ATOMIC); if (IS_ERR(ct)) { pr_debug("Can't allocate conntrack.\n"); @@ -677,6 +865,10 @@ hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, &net->ct.unconfirmed); +#ifdef CONFIG_ATHRS_HW_NAT + if(skb->ath_hw_nat_fw_flags == 3) + set_bit(IPS_ATHR_SW_NAT_SKIPPED_BIT, &ct->status); +#endif spin_unlock_bh(&nf_conntrack_lock); if (exp) { @@ -701,8 +893,12 @@ enum ip_conntrack_info *ctinfo) { struct nf_conntrack_tuple tuple; - struct nf_conntrack_tuple_hash *h; - struct nf_conn *ct; + struct nf_conntrack_tuple_hash *h = NULL; + struct nf_conn *ct = NULL; +#ifdef CONFIG_ATHRS_HW_NAT + struct nf_conn *(*athr_find_get)(struct net *, struct nf_conntrack_tuple *, + __u32, struct nf_conntrack_tuple_hash **); +#endif if (!nf_ct_get_tuple(skb, skb_network_offset(skb), dataoff, l3num, protonum, &tuple, l3proto, @@ -711,6 +907,21 @@ return NULL; } +#ifdef CONFIG_ATHRS_HW_NAT + /* + * for ingress, change the dest ip addr to wan router ip addr + * so as to make conntrack to find the match. Should be called only + * for DNAT */ + if (athr_nat_sw_ops) { + athr_find_get = rcu_dereference(athr_nat_sw_ops->nf_find_get); + if (athr_find_get) { + ct = athr_find_get(net, &tuple, skb->ath_hw_nat_fw_flags, &h); + if (ct) + goto out; + } + } +#endif + /* look for tuple match */ h = nf_conntrack_find_get(net, &tuple); if (!h) { @@ -721,7 +932,9 @@ return (void *)h; } ct = nf_ct_tuplehash_to_ctrack(h); - +#ifdef CONFIG_ATHRS_HW_NAT +out: +#endif /* It exists; we have (non-exclusive) reference. */ if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) { *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY; @@ -759,6 +972,10 @@ u_int8_t protonum; int set_reply = 0; int ret; +#ifdef CONFIG_ATHRS_HW_NAT + void (*athr_process_hwnat)(struct sk_buff *, struct nf_conn *, + enum ip_conntrack_info, u_int8_t); +#endif /* Previously seen (loopback or untracked)? Ignore. */ if (skb->nfct) { @@ -782,7 +999,8 @@ /* It may be an special packet, error, unclean... * inverse of the return code tells to the netfilter * core what to do with the packet. */ - if (l4proto->error != NULL) { + + if ((protonum == IPPROTO_ICMP) && (l4proto->error != NULL)) { ret = l4proto->error(net, skb, dataoff, &ctinfo, pf, hooknum); if (ret <= 0) { NF_CT_STAT_INC_ATOMIC(net, error); @@ -823,6 +1041,26 @@ if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status)) nf_conntrack_event_cache(IPCT_STATUS, ct); +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + if ( ret == NF_ACCEPT && ct != NULL && ppa_hook_session_add_fn != NULL ) + { + uint32_t flags; + + flags = PPA_F_BEFORE_NAT_TRANSFORM; + flags |= CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL ? PPA_F_SESSION_ORG_DIR : PPA_F_SESSION_REPLY_DIR; + + ppa_hook_session_add_fn(skb, ct, flags); + } +#endif + +#ifdef CONFIG_ATHRS_HW_NAT + if (athr_nat_sw_ops) { + athr_process_hwnat = rcu_dereference(athr_nat_sw_ops->nf_process_nat); + if (athr_process_hwnat) + athr_process_hwnat(skb, ct, ctinfo, protonum); + } +#endif + return ret; } EXPORT_SYMBOL_GPL(nf_conntrack_in); @@ -905,6 +1143,14 @@ spin_unlock_bh(&ct->lock); } } + +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + if ( ppa_hook_set_inactivity_fn != NULL ) + { + ppa_hook_set_inactivity_fn((PPA_U_SESSION *)ct, extra_jiffies / HZ); + } +#endif + } EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); @@ -1037,6 +1283,10 @@ struct nf_conn *ct; unsigned int bucket = 0; +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + atomic_inc(&g_ppa_force_timeout); +#endif + while ((ct = get_next_corpse(net, iter, data, &bucket)) != NULL) { /* Time to push up daises... */ if (del_timer(&ct->timeout)) @@ -1045,6 +1295,10 @@ nf_ct_put(ct); } +#if !defined(CONFIG_IFX_PPA_AVM_USAGE) && (defined(CONFIG_IFX_PPA_API) || defined(CONFIG_IFX_PPA_API_MODULE)) + atomic_dec(&g_ppa_force_timeout); +#endif + } EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup);