/* Called when a new connection for this protocol found. */
static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb,
                       unsigned int dataoff)
{
    static const u_int8_t valid_new[] = {
        [ICMPV6_ECHO_REQUEST - 128] = 1,
        [ICMPV6_NI_QUERY - 128] = 1
    };
    int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128;

    if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) {
        /* Can't create a new ICMPv6 `conn' with this. */
        pr_debug("icmpv6: can't create new conn with type %u\n",
                 type + 128);
        nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple);
        if (LOG_INVALID(nf_ct_net(ct), IPPROTO_ICMPV6))
            nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
                          "nf_ct_icmpv6: invalid new with type %d ",
                          type + 128);
        return false;
    }
    return true;
}
/* Returns verdict for packet, or -1 for invalid. */
static int icmpv6_packet(struct nf_conn *ct,
		         struct sk_buff *skb,
		         unsigned int dataoff,
		         enum ip_conntrack_info ctinfo,
		         const struct nf_hook_state *state)
{
	unsigned int *timeout = nf_ct_timeout_lookup(ct);
	static const u8 valid_new[] = {
		[ICMPV6_ECHO_REQUEST - 128] = 1,
		[ICMPV6_NI_QUERY - 128] = 1
	};

	if (state->pf != NFPROTO_IPV6)
		return -NF_ACCEPT;

	if (!nf_ct_is_confirmed(ct)) {
		int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128;

		if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) {
			/* Can't create a new ICMPv6 `conn' with this. */
			pr_debug("icmpv6: can't create new conn with type %u\n",
				 type + 128);
			nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple);
			return -NF_ACCEPT;
		}
	}

	if (!timeout)
		timeout = icmpv6_get_timeouts(nf_ct_net(ct));

	/* Do not immediately delete the connection after the first
	   successful reply to avoid excessive conntrackd traffic
	   and also to handle correctly ICMP echo reply duplicates. */
	nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);

	return NF_ACCEPT;
}