parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
             const struct in6_addr **nd_target,
             struct eth_addr arp_buf[2])
{
    if (icmp->icmp6_code != 0 ||
        (icmp->icmp6_type != ND_NEIGHBOR_SOLICIT &&
         icmp->icmp6_type != ND_NEIGHBOR_ADVERT)) {
        return false;
    }

    arp_buf[0] = eth_addr_zero;
    arp_buf[1] = eth_addr_zero;
    *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;
            } 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;
            } 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_hdr *icmp,
             const struct in6_addr **nd_target,
             struct eth_addr arp_buf[2])
{
    if (icmp->icmp6_code != 0 ||
        (icmp->icmp6_type != ND_NEIGHBOR_SOLICIT &&
         icmp->icmp6_type != ND_NEIGHBOR_ADVERT)) {
        return false;
    }

    arp_buf[0] = eth_addr_zero;
    arp_buf[1] = eth_addr_zero;
    *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;
            } 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;
            } 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;
}