<commit_before>/**
 * @file ipv6_prefix.c
 * @author <NAME> <<EMAIL>>
 * @brief ietf-inet-types ipv6-prefix type plugin.
 *
 * Copyright (c) 2019-2021 CESNET, z.s.p.o.
 *
 * This source code is licensed under BSD 3-Clause License (the "License").
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://opensource.org/licenses/BSD-3-Clause
 */

#define _GNU_SOURCE /* asprintf, strdup */
#include <sys/cdefs.h>

#include "plugins_types.h"

#include <arpa/inet.h>
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__)
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>

#include "libyang.h"

#include "common.h"
#include "compat.h"

/**
 * @page howtoDataLYB LYB Binary Format
 * @subsection howtoDataLYBTypesIPv6Prefix ipv6-prefix (ietf-inet-types)
 *
 * | Size (B) | Mandatory | Type | Meaning |
 * | :------  | :-------: | :--: | :-----: |
 * | 16 | yes | `struct in6_addr *` | IPv6 address in network-byte order |
 * | 1 | yes | `uint8_t *` | prefix length up to 128 |
 */

static void lyplg_type_free_ipv6_prefix(const struct ly_ctx *ctx, struct lyd_value *value);

/**
 * @brief Convert IP address with a prefix in string to a binary network-byte order value.
 *
 * @param[in] value String to convert.
 * @param[in] value_len Length of @p value.
 * @param[in,out] addr Allocated address value to fill.
 * @param[out] prefix Prefix length.
 * @param[out] err Error information on error.
 * @return LY_ERR value.
 */
static LY_ERR
ipv6prefix_str2ip(const char *value, size_t value_len, struct in6_addr *addr, uint8_t *prefix, struct ly_err_item **err)
{
    LY_ERR ret = LY_SUCCESS;
    const char *pref_str;
    char *mask_str = NULL;

    /* it passed the pattern validation */
    pref_str = ly_strnchr(value, '/', value_len);
    ly_strntou8(pref_str + 1, value_len - (pref_str + 1 - value), prefix);

    /* get just the network prefix */
    mask_str = strndup(value, pref_str - value);
    LY_CHECK_ERR_GOTO(!mask_str, ret = LY_EMEM, cleanup);

    /* convert it to netword-byte order */
    if (inet_pton(AF_INET6, mask_str, addr) != 1) {
        ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Failed to convert IPv6 address \"%s\".", mask_str);
        goto cleanup;
    }

cleanup:
    free(mask_str);
    return ret;
}

/**
 * @brief Zero host-portion of the IP address.
 *
 * @param[in,out] addr IP address.
 * @param[in] prefix Prefix length.
 */
static void
ipv6prefix_zero_host(struct in6_addr *addr, uint8_t prefix)
{
    uint32_t i, j, mask;

    /* zero host bits */
    for (i = 0; i < 4; ++i) {
        mask = 0;
        for (j = 0; j < 32; ++j) {
            mask <<= 1;
            if (prefix > (i * 32) + j) {
                mask |= 1;
            }
        }
        mask = htonl(mask);
        ((uint32_t *)addr->s6_addr)[i] &= mask;
    }
}

/**
 * @brief Implementation of ::lyplg_type_store_clb for the ipv6-prefix ietf-inet-types type.
 */
static LY_ERR
lyplg_type_store_ipv6_prefix(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
        uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
        const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
        struct ly_err_item **err)
{
    LY_ERR ret = LY_SUCCESS;
    struct lysc_type_str *type_str = (struct lysc_type_str *)type;
    struct lyd_value_ipv6_prefix *val;

    /* init storage */
    memset(storage, 0, sizeof *storage);
    storage->realtype = type;

    if (format == LY_VALUE_LYB) {
        /* validation */
        if (value_len != 17) {
            ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB ipv6-prefix value size %zu (expected 17).",
                    value_len);
            goto cleanup;
        }
        if (((uint8_t *)value)[16] > 128) {
            ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB ipv6-prefix prefix length %" PRIu8 ".",
                    ((uint8_t *)value)[16]);
            goto cleanup;
        }

        /* store/allocate value */
        if (options & LYPLG_TYPE_STORE_DYNAMIC) {
            storage->dyn_mem = (void *)value;
            options &= ~LYPLG_TYPE_STORE_DYNAMIC;

            LYD_VALUE_GET(storage, val);
        } else {
            LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val);
            LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);

            memcpy(val, value, value_len);
        }

        /* zero host */
        ipv6prefix_zero_host(&val->addr, val->prefix);

        /* success */
        goto cleanup;
    }

    /* allocate value */
    LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val);
    LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);

    /* check hints */
    ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
    LY_CHECK_GOTO(ret, cleanup);
<commit_msg>plugins types BUGFIX missing dynamic/fixed value check<commit_after>/**
 * @file ipv6_prefix.c
 * @author <NAME> <<EMAIL>>
 * @brief ietf-inet-types ipv6-prefix type plugin.
 *
 * Copyright (c) 2019-2021 CESNET, z.s.p.o.
 *
 * This source code is licensed under BSD 3-Clause License (the "License").
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://opensource.org/licenses/BSD-3-Clause
 */

#define _GNU_SOURCE /* asprintf, strdup */
#include <sys/cdefs.h>

#include "plugins_types.h"

#include <arpa/inet.h>
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__)
#include <netinet/in.h>
#include <sys/socket.h>
#endif
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>

#include "libyang.h"

#include "common.h"
#include "compat.h"

/**
 * @page howtoDataLYB LYB Binary Format
 * @subsection howtoDataLYBTypesIPv6Prefix ipv6-prefix (ietf-inet-types)
 *
 * | Size (B) | Mandatory | Type | Meaning |
 * | :------  | :-------: | :--: | :-----: |
 * | 16 | yes | `struct in6_addr *` | IPv6 address in network-byte order |
 * | 1 | yes | `uint8_t *` | prefix length up to 128 |
 */

static void lyplg_type_free_ipv6_prefix(const struct ly_ctx *ctx, struct lyd_value *value);

/**
 * @brief Convert IP address with a prefix in string to a binary network-byte order value.
 *
 * @param[in] value String to convert.
 * @param[in] value_len Length of @p value.
 * @param[in,out] addr Allocated address value to fill.
 * @param[out] prefix Prefix length.
 * @param[out] err Error information on error.
 * @return LY_ERR value.
 */
static LY_ERR
ipv6prefix_str2ip(const char *value, size_t value_len, struct in6_addr *addr, uint8_t *prefix, struct ly_err_item **err)
{
    LY_ERR ret = LY_SUCCESS;
    const char *pref_str;
    char *mask_str = NULL;

    /* it passed the pattern validation */
    pref_str = ly_strnchr(value, '/', value_len);
    ly_strntou8(pref_str + 1, value_len - (pref_str + 1 - value), prefix);

    /* get just the network prefix */
    mask_str = strndup(value, pref_str - value);
    LY_CHECK_ERR_GOTO(!mask_str, ret = LY_EMEM, cleanup);

    /* convert it to netword-byte order */
    if (inet_pton(AF_INET6, mask_str, addr) != 1) {
        ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Failed to convert IPv6 address \"%s\".", mask_str);
        goto cleanup;
    }

cleanup:
    free(mask_str);
    return ret;
}

/**
 * @brief Zero host-portion of the IP address.
 *
 * @param[in,out] addr IP address.
 * @param[in] prefix Prefix length.
 */
static void
ipv6prefix_zero_host(struct in6_addr *addr, uint8_t prefix)
{
    uint32_t i, j, mask;

    /* zero host bits */
    for (i = 0; i < 4; ++i) {
        mask = 0;
        for (j = 0; j < 32; ++j) {
            mask <<= 1;
            if (prefix > (i * 32) + j) {
                mask |= 1;
            }
        }
        mask = htonl(mask);
        ((uint32_t *)addr->s6_addr)[i] &= mask;
    }
}

/**
 * @brief Implementation of ::lyplg_type_store_clb for the ipv6-prefix ietf-inet-types type.
 */
static LY_ERR
lyplg_type_store_ipv6_prefix(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
        uint32_t options, LY_VALUE_FORMAT format, void *UNUSED(prefix_data), uint32_t hints,
        const struct lysc_node *UNUSED(ctx_node), struct lyd_value *storage, struct lys_glob_unres *UNUSED(unres),
        struct ly_err_item **err)
{
    LY_ERR ret = LY_SUCCESS;
    struct lysc_type_str *type_str = (struct lysc_type_str *)type;
    struct lyd_value_ipv6_prefix *val;

    /* init storage */
    memset(storage, 0, sizeof *storage);
    storage->realtype = type;

    if (format == LY_VALUE_LYB) {
        /* validation */
        if (value_len != 17) {
            ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB ipv6-prefix value size %zu (expected 17).",
                    value_len);
            goto cleanup;
        }
        if (((uint8_t *)value)[16] > 128) {
            ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid LYB ipv6-prefix prefix length %" PRIu8 ".",
                    ((uint8_t *)value)[16]);
            goto cleanup;
        }

        /* store/allocate value */
        if ((options & LYPLG_TYPE_STORE_DYNAMIC) && LYPLG_TYPE_VAL_IS_DYN(val)) {
            storage->dyn_mem = (void *)value;
            options &= ~LYPLG_TYPE_STORE_DYNAMIC;

            LYD_VALUE_GET(storage, val);
        } else {
            LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val);
            LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);

            memcpy(val, value, value_len);
        }

        /* zero host */
        ipv6prefix_zero_host(&val->addr, val->prefix);

        /* success */
        goto cleanup;
    }

    /* allocate value */
    LYPLG_TYPE_VAL_INLINE_PREPARE(storage, val);
    LY_CHECK_ERR_GOTO(!val, ret = LY_EMEM, cleanup);

    /* check hints */
    ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
    LY_CHECK_GOTO(ret, cleanup);

{'fraction_non_alphanumeric': 0.1326580784737929, 'fraction_numerical': 0.01514406529648933, 'mean_word_length': 2.772255192878338, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 43, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4603235', 'n_tokens_mistral': 3758, 'n_tokens_neox': 3603, 'n_words': 943}