Ejemplo n.º 1
0
int nf_nat_rule_find(struct sk_buff *skb,
		     unsigned int hooknum,
		     const struct net_device *in,
		     const struct net_device *out,
		     struct nf_conn *ct)
{
	struct net *net = nf_ct_net(ct);
	int ret;
#ifdef CONFIG_ATHRS_HW_NAT
        void (*athr_ct_check_layer2if)(struct sk_buff *, struct nf_conn *, int nf_nat_manip_type);
#endif

	ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table);
#ifdef CONFIG_ATHRS_HW_NAT
        if (athr_nat_sw_ops) {
		athr_ct_check_layer2if = rcu_dereference(athr_nat_sw_ops->check_layer2if);
                if (athr_ct_check_layer2if)
                	athr_ct_check_layer2if(skb, ct, HOOK2MANIP(hooknum));
        }
#endif
	if (ret == NF_ACCEPT) {
		if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
			/* NUL mapping */
			ret = alloc_null_binding(ct, hooknum);
	}
	return ret;
}
static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum,
				     const struct net_device *in,
				     const struct net_device *out,
				     struct nf_conn *ct)
{
	struct net *net = nf_ct_net(ct);
	unsigned int ret;

	ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table);
	if (ret == NF_ACCEPT) {
		if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
			ret = alloc_null_binding(ct, hooknum);
	}
	return ret;
}
Ejemplo n.º 3
0
int nf_nat_rule_find(struct sk_buff *skb,
		     unsigned int hooknum,
		     const struct net_device *in,
		     const struct net_device *out,
		     struct nf_conn *ct)
{
	struct net *net = nf_ct_net(ct);
	int ret;

	ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table);

	if (ret == NF_ACCEPT) {
/*
 * Reason: Hairpin translation for TCP/UDP not working
 * Modified: Ubicom
 * Date: 2009.11.18
 */
		if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) {
#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
			if ((HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST)){
				struct nf_conntrack_tuple reply_tuple, new_tuple;

				nf_ct_invert_tuplepr(&reply_tuple,
					&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);

				if (find_appropriate_p2p_dst(net, &reply_tuple, &new_tuple)) {
					struct nf_nat_range range;
					/* This must be a fresh one. */
					BUG_ON(ct->status & IPS_SNATP2P_DONE_MASK);
					ct->status |= IPS_SNATP2P_DST;
					range.flags = (IP_NAT_RANGE_MAP_IPS);
					//range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
					//range.min = range.max = new_tuple.dst.u;

					range.min_ip = range.max_ip = new_tuple.dst.u3.ip;
					ret = nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
					range.min_ip = range.max_ip = new_tuple.src.u3.ip;
					ret = nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
				}
			}
			if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
#endif
				/* NUL mapping */
				ret = alloc_null_binding(ct, hooknum);
		}
	}
	return ret;
}
Ejemplo n.º 4
0
int nf_nat_rule_find(struct sk_buff *skb,
		     unsigned int hooknum,
		     const struct net_device *in,
		     const struct net_device *out,
		     struct nf_conn *ct)
{
	int ret;

	ret = ipt_do_table(skb, hooknum, in, out, &nat_table);

	if (ret == NF_ACCEPT) {
		if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
			/* NUL mapping */
			ret = alloc_null_binding(ct, hooknum);
	}
	return ret;
}
Ejemplo n.º 5
0
int ip_nat_rule_find(struct sk_buff **pskb,
		     unsigned int hooknum,
		     const struct net_device *in,
		     const struct net_device *out,
		     struct ip_conntrack *ct,
		     struct ip_nat_info *info)
{
	int ret;

	ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);

	if (ret == NF_ACCEPT) {
		if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
			/* NUL mapping */
			ret = alloc_null_binding(ct, info, hooknum);
	}
	return ret;
}
Ejemplo n.º 6
0
static unsigned int
ip_nat_fn(unsigned int hooknum,
	  struct sk_buff **pskb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	struct ip_nat_info *info;
	/* maniptype == SRC for postrouting. */
	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);

	/* We never see fragments: conntrack defrags on pre-routing
	   and local-out, and ip_nat_out protects post-routing. */
	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
		       & htons(IP_MF|IP_OFFSET)));

	(*pskb)->nfcache |= NFC_UNKNOWN;

	/* If we had a hardware checksum before, it's now invalid */
	if ((*pskb)->ip_summed == CHECKSUM_HW)
		if (skb_checksum_help(*pskb, (out == NULL)))
			return NF_DROP;

	ct = ip_conntrack_get(*pskb, &ctinfo);
	/* Can't track?  It's not due to stress, or conntrack would
	   have dropped it.  Hence it's the user's responsibilty to
	   packet filter it out, or implement conntrack/NAT for that
	   protocol. 8) --RR */
	if (!ct) {
		/* Exception: ICMP redirect to new connection (not in
                   hash table yet).  We must not let this through, in
                   case we're doing NAT to the same network. */
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			struct icmphdr _hdr, *hp;

			hp = skb_header_pointer(*pskb,
						(*pskb)->nh.iph->ihl*4,
						sizeof(_hdr), &_hdr);
			if (hp != NULL &&
			    hp->type == ICMP_REDIRECT)
				return NF_DROP;
		}
		return NF_ACCEPT;
	}

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			if (!icmp_reply_translation(pskb, ct, maniptype,
						    CTINFO2DIR(ctinfo)))
				return NF_DROP;
			else
				return NF_ACCEPT;
		}
		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
	case IP_CT_NEW:
		info = &ct->nat.info;

		/* Seen it before?  This can happen for loopback, retrans,
		   or local packets.. */
		if (!ip_nat_initialized(ct, maniptype)) {
			unsigned int ret;

			/* LOCAL_IN hook doesn't have a chain!  */
			if (hooknum == NF_IP_LOCAL_IN)
				ret = alloc_null_binding(ct, info, hooknum);
			else
				ret = ip_nat_rule_find(pskb, hooknum,
						       in, out, ct,
						       info);

			if (ret != NF_ACCEPT) {
				return ret;
			}
		} else
			DEBUGP("Already setup manip %s for ct %p\n",
			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
			       ct);
		break;

	default:
		/* ESTABLISHED */
		IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
			     || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
		info = &ct->nat.info;
	}

	IP_NF_ASSERT(info);
	return nat_packet(ct, ctinfo, hooknum, pskb);
}
Ejemplo n.º 7
0
static unsigned int
nf_nat_fn(unsigned int hooknum,
	  struct sk_buff *skb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	struct nf_conn_nat *nat;
	/* maniptype == SRC for postrouting. */
	enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);

	/* We never see fragments: conntrack defrags on pre-routing
	   and local-out, and nf_nat_out protects post-routing. */
	NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));

	ct = nf_ct_get(skb, &ctinfo);
	/* Can't track?  It's not due to stress, or conntrack would
	   have dropped it.  Hence it's the user's responsibilty to
	   packet filter it out, or implement conntrack/NAT for that
	   protocol. 8) --RR */
	if (!ct)
		return NF_ACCEPT;

	/* Don't try to NAT if this packet is not conntracked */
	if (ct == &nf_conntrack_untracked)
		return NF_ACCEPT;

	nat = nfct_nat(ct);
	if (!nat) {
		/* NAT module was loaded late. */
		if (nf_ct_is_confirmed(ct))
			return NF_ACCEPT;
		nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
		if (nat == NULL) {
			pr_debug("failed to add NAT extension\n");
			return NF_ACCEPT;
		}
	}

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
			if (!nf_nat_icmp_reply_translation(ct, ctinfo,
							   hooknum, skb))
				return NF_DROP;
			else
				return NF_ACCEPT;
		}
		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
	case IP_CT_NEW:

		/* Seen it before?  This can happen for loopback, retrans,
		   or local packets.. */
		if (!nf_nat_initialized(ct, maniptype)) {
			unsigned int ret;

			if (hooknum == NF_INET_LOCAL_IN)
				/* LOCAL_IN hook doesn't have a chain!  */
				ret = alloc_null_binding(ct, hooknum);
			else
				ret = nf_nat_rule_find(skb, hooknum, in, out,
						       ct);

			if (ret != NF_ACCEPT) {
				return ret;
			}
		} else
			pr_debug("Already setup manip %s for ct %p\n",
				 maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
				 ct);
		break;

	default:
		/* ESTABLISHED */
		NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
			     ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
	}

	return nf_nat_packet(ct, ctinfo, hooknum, skb);
}
Ejemplo n.º 8
0
static unsigned int
nf_nat_fn(unsigned int hooknum,
	  struct sk_buff *skb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	struct nf_conn_nat *nat;
	/* maniptype == SRC for postrouting. */
	enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);

	/* We never see fragments: conntrack defrags on pre-routing
	   and local-out, and nf_nat_out protects post-routing. */
	NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));

	ct = nf_ct_get(skb, &ctinfo);
	/* Can't track?  It's not due to stress, or conntrack would
	   have dropped it.  Hence it's the user's responsibilty to
	   packet filter it out, or implement conntrack/NAT for that
	   protocol. 8) --RR */
	if (!ct) {
		/* Exception: ICMP redirect to new connection (not in
		   hash table yet).  We must not let this through, in
		   case we're doing NAT to the same network. */
		if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
			struct icmphdr _hdr, *hp;

			hp = skb_header_pointer(skb, ip_hdrlen(skb),
						sizeof(_hdr), &_hdr);
			if (hp != NULL &&
			    hp->type == ICMP_REDIRECT)
				return NF_DROP;
		}
		return NF_ACCEPT;
	}

	/* Don't try to NAT if this packet is not conntracked */
	if (ct == &nf_conntrack_untracked)
		return NF_ACCEPT;

	nat = nfct_nat(ct);
	if (!nat)
		return NF_ACCEPT;

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
			if (!nf_nat_icmp_reply_translation(ct, ctinfo,
							   hooknum, skb))
				return NF_DROP;
			else
				return NF_ACCEPT;
		}
		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
	case IP_CT_NEW:

		/* Seen it before?  This can happen for loopback, retrans,
		   or local packets.. */
		if (!nf_nat_initialized(ct, maniptype)) {
			unsigned int ret;

			if (unlikely(nf_ct_is_confirmed(ct)))
				/* NAT module was loaded late */
				ret = alloc_null_binding_confirmed(ct, hooknum);
			else if (hooknum == NF_IP_LOCAL_IN)
				/* LOCAL_IN hook doesn't have a chain!  */
				ret = alloc_null_binding(ct, hooknum);
			else
				ret = nf_nat_rule_find(skb, hooknum, in, out,
						       ct);

			if (ret != NF_ACCEPT) {
				return ret;
			}

			ipt_cone_place_in_hashes(ct);
			
		} else
			DEBUGP("Already setup manip %s for ct %p\n",
			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
			       ct);
		break;

	default:
		/* ESTABLISHED */
		NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
			     ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
	}

	return nf_nat_packet(ct, ctinfo, hooknum, skb);
}
static unsigned int
ip_nat_fn(unsigned int hooknum,
	  struct sk_buff **pskb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct ip_conntrack *ct;
	enum ip_conntrack_info ctinfo;
	struct ip_nat_info *info;
	/* maniptype == SRC for postrouting. */
	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
/* jimmy added 20080324 */
	struct sip_rtp_binding *sip_rtp_binding_tmp = NULL;
/* --------------------------------- */

	/* We never see fragments: conntrack defrags on pre-routing
	   and local-out, and ip_nat_out protects post-routing. */
	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
		       & htons(IP_MF|IP_OFFSET)));

	/* If we had a hardware checksum before, it's now invalid */
	if ((*pskb)->ip_summed == CHECKSUM_HW)
		if (skb_checksum_help(*pskb, (out == NULL)))
			return NF_DROP;

	ct = ip_conntrack_get(*pskb, &ctinfo);
	/* Can't track?  It's not due to stress, or conntrack would
	   have dropped it.  Hence it's the user's responsibilty to
	   packet filter it out, or implement conntrack/NAT for that
	   protocol. 8) --RR */
	if (!ct) {
		/* Exception: ICMP redirect to new connection (not in
                   hash table yet).  We must not let this through, in
                   case we're doing NAT to the same network. */
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			struct icmphdr _hdr, *hp;

			hp = skb_header_pointer(*pskb,
						(*pskb)->nh.iph->ihl*4,
						sizeof(_hdr), &_hdr);
			if (hp != NULL &&
			    hp->type == ICMP_REDIRECT)
				return NF_DROP;
		}
		return NF_ACCEPT;
	}

	/* Don't try to NAT if this packet is not conntracked */
	if (ct == &ip_conntrack_untracked)
		return NF_ACCEPT;

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
			if (!ip_nat_icmp_reply_translation(pskb, ct, maniptype,
							   CTINFO2DIR(ctinfo)))
				return NF_DROP;
			else
				return NF_ACCEPT;
		}
		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
	case IP_CT_NEW:
		info = &ct->nat.info;

		/* Seen it before?  This can happen for loopback, retrans,
		   or local packets.. */
		if (!ip_nat_initialized(ct, maniptype)) {
			unsigned int ret;

			if (unlikely(is_confirmed(ct)))
				/* NAT module was loaded late */
				ret = alloc_null_binding_confirmed(ct, info,
				                                   hooknum);
			else if (hooknum == NF_IP_LOCAL_IN)
				/* LOCAL_IN hook doesn't have a chain!  */
				ret = alloc_null_binding(ct, info, hooknum);
			else{
				ret = ip_nat_rule_find(pskb, hooknum,
						       in, out, ct,
						       info);
/* jimmy added 20080324 */
				if((hooknum == NF_IP_POST_ROUTING) && ((*pskb)->nh.iph->protocol == IPPROTO_UDP)){
					sip_rtp_binding_tmp = sip_rtp_binding_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
										ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip);
					if(sip_rtp_binding_tmp){
					/* jimmy added 20080328, for avoid sip pattern 100 run through in */
						if( sip_rtp_binding_tmp->wan_uac_port && 
							(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all == sip_rtp_binding_tmp->wan_uac_port)){
					/* ----------------------------------------------- */
						if(sip_rtp_binding_tmp->router_port && sip_rtp_binding_tmp->router_ip &&
							(sip_rtp_binding_tmp->router_ip == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) &&
							(sip_rtp_binding_tmp->router_port != ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all)){
							write_lock_bh(&ip_conntrack_lock);
							ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all = sip_rtp_binding_tmp->router_port;
							write_unlock_bh(&ip_conntrack_lock);

							DEBUGP("After modified conntrack for sip incoming conntrack hash, this ct are\n");
							DEBUGP("[IP_CT_DIR_REPLY] : %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",
								ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum,
								NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip), ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all),
								NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all));
							DEBUGP("[IP_CT_DIR_ORIGINAL] : %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",
								ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
								NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all),
								NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all));
						}
					/* jimmy added 20080328, for avoid sip pattern 100 */
						}
					/* ----------------------------------------------- */
					}
				}
/* ---------------------- */
			}
			if (ret != NF_ACCEPT) {
				return ret;
			}
		} else
			DEBUGP("Already setup manip %s for ct %p\n",
			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
			       ct);
		break;

	default:
		/* ESTABLISHED */
		IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
			     || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
		info = &ct->nat.info;
	}

	IP_NF_ASSERT(info);
	return ip_nat_packet(ct, ctinfo, hooknum, pskb);
}
Ejemplo n.º 10
0
static unsigned int
nf_nat_fn(unsigned int hooknum,
	  struct sk_buff *skb,
	  const struct net_device *in,
	  const struct net_device *out,
	  int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;
	struct nf_conn_nat *nat;
	
	enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);

	
	NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));

	ct = nf_ct_get(skb, &ctinfo);
	
	if (!ct)
		return NF_ACCEPT;

	
	if (ct == &nf_conntrack_untracked)
		return NF_ACCEPT;

	nat = nfct_nat(ct);
	if (!nat) {
		
		if (nf_ct_is_confirmed(ct))
			return NF_ACCEPT;
		nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
		if (nat == NULL) {
			pr_debug("failed to add NAT extension\n");
			return NF_ACCEPT;
		}
	}

	switch (ctinfo) {
	case IP_CT_RELATED:
	case IP_CT_RELATED+IP_CT_IS_REPLY:
		if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
			if (!nf_nat_icmp_reply_translation(ct, ctinfo,
							   hooknum, skb))
				return NF_DROP;
			else
				return NF_ACCEPT;
		}
		
	case IP_CT_NEW:

		
		if (!nf_nat_initialized(ct, maniptype)) {
			unsigned int ret;

			if (hooknum == NF_INET_LOCAL_IN)
				
				ret = alloc_null_binding(ct, hooknum);
			else
				ret = nf_nat_rule_find(skb, hooknum, in, out,
						       ct);

			if (ret != NF_ACCEPT) {
				return ret;
			}
		} else
			pr_debug("Already setup manip %s for ct %p\n",
				 maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
				 ct);
		break;

	default:
		
		NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
			     ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
	}

	return nf_nat_packet(ct, ctinfo, hooknum, skb);
}
Ejemplo n.º 11
0
static unsigned int
ip_nat_fn(unsigned int hooknum,
          struct sk_buff **pskb,
          const struct net_device *in,
          const struct net_device *out,
          int (*okfn)(struct sk_buff *))
{
    struct ip_conntrack *ct;
    enum ip_conntrack_info ctinfo;
    struct ip_nat_info *info;
    /* maniptype == SRC for postrouting. */
    enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);

    /* We never see fragments: conntrack defrags on pre-routing
       and local-out, and ip_nat_out protects post-routing. */
    IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
                   & htons(IP_MF|IP_OFFSET)));

    (*pskb)->nfcache |= NFC_UNKNOWN;

    /* If we had a hardware checksum before, it's now invalid */
    if ((*pskb)->ip_summed == CHECKSUM_HW)
        (*pskb)->ip_summed = CHECKSUM_NONE;

    ct = ip_conntrack_get(*pskb, &ctinfo);
    /* Can't track?  It's not due to stress, or conntrack would
       have dropped it.  Hence it's the user's responsibilty to
       packet filter it out, or implement conntrack/NAT for that
       protocol. 8) --RR */
    if (!ct) {
        /* Exception: ICMP redirect to new connection (not in
                   hash table yet).  We must not let this through, in
                   case we're doing NAT to the same network. */
        struct iphdr *iph = (*pskb)->nh.iph;
        struct icmphdr *hdr = (struct icmphdr *)
                              ((u_int32_t *)iph + iph->ihl);
        if (iph->protocol == IPPROTO_ICMP
                && hdr->type == ICMP_REDIRECT)
            return NF_DROP;
        return NF_ACCEPT;
    }

    switch (ctinfo) {
    case IP_CT_RELATED:
    case IP_CT_RELATED+IP_CT_IS_REPLY:
        if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
            return icmp_reply_translation(*pskb, ct, hooknum,
                                          CTINFO2DIR(ctinfo));
        }
    /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
    case IP_CT_NEW:
        info = &ct->nat.info;

        WRITE_LOCK(&ip_nat_lock);
        /* Seen it before?  This can happen for loopback, retrans,
           or local packets.. */
        if (!(info->initialized & (1 << maniptype))) {
            unsigned int ret;

            if (ct->master
                    && master_ct(ct)->nat.info.helper
                    && master_ct(ct)->nat.info.helper->expect) {
                ret = call_expect(master_ct(ct), pskb,
                                  hooknum, ct, info);
            } else {
                if (unlikely(is_confirmed(ct)))
                    /* NAT module was loaded late */
                    ret = alloc_null_binding_confirmed(ct, info,
                                                       hooknum);
                else if (hooknum == NF_IP_LOCAL_IN)
                    /* LOCAL_IN hook doesn't have a chain */
                    ret = alloc_null_binding(ct, info,
                                             hooknum);
                else
                    ret = ip_nat_rule_find(pskb, hooknum,
                                           in, out,
                                           ct, info);
            }

            if (ret != NF_ACCEPT) {
                WRITE_UNLOCK(&ip_nat_lock);
                return ret;
            }
        } else
            DEBUGP("Already setup manip %s for ct %p\n",
                   maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
                   ct);
        WRITE_UNLOCK(&ip_nat_lock);
        break;

    default:
        /* ESTABLISHED */
        IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
                     || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
        info = &ct->nat.info;
    }

    IP_NF_ASSERT(info);
    return do_bindings(ct, ctinfo, info, hooknum, pskb);
}