parse_icmpv6(const void **datap, size_t *sizep,
             const struct icmp6_data_header *icmp6,
             ovs_be32 *rso_flags, const struct in6_addr **nd_target,
             struct eth_addr arp_buf[2], uint8_t *opt_type)
{
    if (icmp6->icmp6_base.icmp6_code != 0 ||
        (icmp6->icmp6_base.icmp6_type != ND_NEIGHBOR_SOLICIT &&
         icmp6->icmp6_base.icmp6_type != ND_NEIGHBOR_ADVERT)) {
        return false;
    }

    arp_buf[0] = eth_addr_zero;
    arp_buf[1] = eth_addr_zero;
    *opt_type = 0;

    *rso_flags = get_16aligned_be32(icmp6->icmp6_data.be32);

    *nd_target = data_try_pull(datap, sizep, sizeof **nd_target);
    if (OVS_UNLIKELY(!*nd_target)) {
        return true;
    }

    while (*sizep >= 8) {
        /* The minimum size of an option is 8 bytes, which also is
         * the size of Ethernet link-layer options. */
        const struct ovs_nd_lla_opt *lla_opt = *datap;
        int opt_len = lla_opt->len * ND_LLA_OPT_LEN;

        if (!opt_len || opt_len > *sizep) {
            return true;
        }

        /* Store the link layer address if the appropriate option is
         * provided.  It is considered an error if the same link
         * layer option is specified twice. */
        if (lla_opt->type == ND_OPT_SOURCE_LINKADDR && opt_len == 8) {
            if (OVS_LIKELY(eth_addr_is_zero(arp_buf[0]))) {
                arp_buf[0] = lla_opt->mac;
                /* We use only first option type present in ND packet. */
                if (*opt_type == 0) {
                    *opt_type = lla_opt->type;
                }
            } else {
                goto invalid;
            }
        } else if (lla_opt->type == ND_OPT_TARGET_LINKADDR && opt_len == 8) {
            if (OVS_LIKELY(eth_addr_is_zero(arp_buf[1]))) {
                arp_buf[1] = lla_opt->mac;
                /* We use only first option type present in ND packet. */
                if (*opt_type == 0) {
                    *opt_type = lla_opt->type;
                }
            } else {
                goto invalid;
            }
        }

        if (OVS_UNLIKELY(!data_try_pull(datap, sizep, opt_len))) {
            return true;
        }
    }
    return true;

invalid:
    *nd_target = NULL;
    arp_buf[0] = eth_addr_zero;
    arp_buf[1] = eth_addr_zero;
    return true;
}
parse_icmpv6(const void **datap, size_t *sizep,
             const struct icmp6_data_header *icmp6,
             ovs_be32 *rso_flags, const struct in6_addr **nd_target,
             struct eth_addr arp_buf[2], uint8_t *opt_type)
{
    if (icmp6->icmp6_base.icmp6_code != 0 ||
        (icmp6->icmp6_base.icmp6_type != ND_NEIGHBOR_SOLICIT &&
         icmp6->icmp6_base.icmp6_type != ND_NEIGHBOR_ADVERT)) {
        return false;
    }

    arp_buf[0] = eth_addr_zero;
    arp_buf[1] = eth_addr_zero;
    *opt_type = 0;

    *rso_flags = get_16aligned_be32(icmp6->icmp6_data.be32);

    *nd_target = data_try_pull(datap, sizep, sizeof **nd_target);
    if (OVS_UNLIKELY(!*nd_target)) {
        return true;
    }

    while (*sizep >= 8) {
         
        const struct ovs_nd_lla_opt *lla_opt = *datap;
        int opt_len = lla_opt->len * ND_LLA_OPT_LEN;

        if (!opt_len || opt_len > *sizep) {
            return true;
        }

         
        if (lla_opt->type == ND_OPT_SOURCE_LINKADDR && opt_len == 8) {
            if (OVS_LIKELY(eth_addr_is_zero(arp_buf[0]))) {
                arp_buf[0] = lla_opt->mac;
                 
                if (*opt_type == 0) {
                    *opt_type = lla_opt->type;
                }
            } else {
                goto invalid;
            }
        } else if (lla_opt->type == ND_OPT_TARGET_LINKADDR && opt_len == 8) {
            if (OVS_LIKELY(eth_addr_is_zero(arp_buf[1]))) {
                arp_buf[1] = lla_opt->mac;
                 
                if (*opt_type == 0) {
                    *opt_type = lla_opt->type;
                }
            } else {
                goto invalid;
            }
        }

        if (OVS_UNLIKELY(!data_try_pull(datap, sizep, opt_len))) {
            return true;
        }
    }
    return true;

invalid:
    *nd_target = NULL;
    arp_buf[0] = eth_addr_zero;
    arp_buf[1] = eth_addr_zero;
    return true;
}