static unsigned int ipv6_confirm(unsigned int hooknum,
				 struct sk_buff **pskb,
				 const struct net_device *in,
				 const struct net_device *out,
				 int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	enum ip_conntrack_info ctinfo;

	/* This is where we call the helper: as the packet goes out. */
	ct = nf_ct_get(*pskb, &ctinfo);
	if (ct && ct->helper) {
		unsigned int ret, protoff;
		unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
				      - (*pskb)->data;
		unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;

		protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
						 (*pskb)->len - extoff);
		if (protoff < 0 || protoff > (*pskb)->len ||
		    pnum == NEXTHDR_FRAGMENT) {
			DEBUGP("proto header not found\n");
			return NF_ACCEPT;
		}

		ret = ct->helper->help(pskb, protoff, ct, ctinfo);
		if (ret != NF_ACCEPT)
			return ret;
	}

	/* We've seen it coming out the other side: confirm it */

	return nf_conntrack_confirm(pskb);
}
static int
ipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
	     u_int8_t *protonum)
{
	unsigned int extoff;
	unsigned char pnum;
	int protoff;

	extoff = (u8*)((*pskb)->nh.ipv6h + 1) - (*pskb)->data;
	pnum = (*pskb)->nh.ipv6h->nexthdr;

	protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
					 (*pskb)->len - extoff);

	/*
	 * (protoff == (*pskb)->len) mean that the packet doesn't have no data
	 * except of IPv6 & ext headers. but it's tracked anyway. - YK
	 */
	if ((protoff < 0) || (protoff > (*pskb)->len)) {
		DEBUGP("ip6_conntrack_core: can't find proto in pkt\n");
		NF_CT_STAT_INC_ATOMIC(error);
		NF_CT_STAT_INC_ATOMIC(invalid);
		return -NF_ACCEPT;
	}

	*dataoff = protoff;
	*protonum = pnum;
	return NF_ACCEPT;
}
static unsigned int ipv6_confirm(unsigned int hooknum,
				 struct sk_buff **pskb,
				 const struct net_device *in,
				 const struct net_device *out,
				 int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	struct nf_conn_help *help;
	enum ip_conntrack_info ctinfo;
	unsigned int ret, protoff;
	unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
			      - (*pskb)->data;
	unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;


	/* This is where we call the helper: as the packet goes out. */
	ct = nf_ct_get(*pskb, &ctinfo);
	if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
		goto out;

	help = nfct_help(ct);
	if (!help || !help->helper)
		goto out;

	protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
					 (*pskb)->len - extoff);
	if (protoff < 0 || protoff > (*pskb)->len ||
	    pnum == NEXTHDR_FRAGMENT) {
		DEBUGP("proto header not found\n");
		return NF_ACCEPT;
	}

#if defined(CONFIG_RA_HW_NAT) || defined(CONFIG_RA_HW_NAT_MODULE)
	if( (skb_headroom(*pskb) >=4)  &&
		((FOE_MAGIC_TAG(*pskb) == FOE_MAGIC_PCI) ||
		 (FOE_MAGIC_TAG(*pskb) == FOE_MAGIC_WLAN) ||
		 (FOE_MAGIC_TAG(*pskb) == FOE_MAGIC_GE))){
	    FOE_ALG_RXIF(*pskb)=1;
	}
#endif

	ret = help->helper->help(pskb, protoff, ct, ctinfo);
	if (ret != NF_ACCEPT)
		return ret;
out:
	/* We've seen it coming out the other side: confirm it */
	return nf_conntrack_confirm(pskb);
}
static unsigned int ipv6_confirm(unsigned int hooknum,
				 struct sk_buff **pskb,
				 const struct net_device *in,
				 const struct net_device *out,
				 int (*okfn)(struct sk_buff *))
{
	struct nf_conn *ct;
	struct nf_conn_help *help;
	struct nf_conntrack_helper *helper;
	enum ip_conntrack_info ctinfo;
	unsigned int ret, protoff;
	unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
	unsigned char pnum = ipv6_hdr(*pskb)->nexthdr;


	/* This is where we call the helper: as the packet goes out. */
	ct = nf_ct_get(*pskb, &ctinfo);
	if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
		goto out;

	help = nfct_help(ct);
	if (!help)
		goto out;
	/* rcu_read_lock()ed by nf_hook_slow */
	helper = rcu_dereference(help->helper);
	if (!helper)
		goto out;

	protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
					 (*pskb)->len - extoff);
	if (protoff > (*pskb)->len || pnum == NEXTHDR_FRAGMENT) {
		DEBUGP("proto header not found\n");
		return NF_ACCEPT;
	}

	ret = helper->help(pskb, protoff, ct, ctinfo);
	if (ret != NF_ACCEPT)
		return ret;
out:
	/* We've seen it coming out the other side: confirm it */
	return nf_conntrack_confirm(pskb);
}