root/src/libs/libfdt/fdt_check.c
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
/*
 * libfdt - Flat Device Tree manipulation
 * Copyright (C) 2006 David Gibson, IBM Corporation.
 */
#include "libfdt_env.h"

#include <fdt.h>
#include <libfdt.h>

#include "libfdt_internal.h"

int fdt_check_full(const void *fdt, size_t bufsize)
{
        int err;
        int num_memrsv;
        int offset, nextoffset = 0;
        uint32_t tag;
        unsigned int depth = 0;
        const void *prop;
        const char *propname;
        bool expect_end = false;

        if (bufsize < FDT_V1_SIZE)
                return -FDT_ERR_TRUNCATED;
        if (bufsize < fdt_header_size(fdt))
                return -FDT_ERR_TRUNCATED;
        err = fdt_check_header(fdt);
        if (err != 0)
                return err;
        if (bufsize < fdt_totalsize(fdt))
                return -FDT_ERR_TRUNCATED;

        num_memrsv = fdt_num_mem_rsv(fdt);
        if (num_memrsv < 0)
                return num_memrsv;

        while (1) {
                offset = nextoffset;
                tag = fdt_next_tag(fdt, offset, &nextoffset);

                if (nextoffset < 0)
                        return nextoffset;

                /* If we see two root nodes, something is wrong */
                if (expect_end && tag != FDT_END)
                        return -FDT_ERR_BADSTRUCTURE;

                switch (tag) {
                case FDT_NOP:
                        break;

                case FDT_END:
                        if (depth != 0)
                                return -FDT_ERR_BADSTRUCTURE;
                        return 0;

                case FDT_BEGIN_NODE:
                        depth++;
                        if (depth > INT_MAX)
                                return -FDT_ERR_BADSTRUCTURE;

                        /* The root node must have an empty name */
                        if (depth == 1) {
                                const char *name;
                                int len;

                                name = fdt_get_name(fdt, offset, &len);
                                if (*name || len)
                                        return -FDT_ERR_BADSTRUCTURE;
                        }
                        break;

                case FDT_END_NODE:
                        if (depth == 0)
                                return -FDT_ERR_BADSTRUCTURE;
                        depth--;
                        if (depth == 0)
                                expect_end = true;
                        break;

                case FDT_PROP:
                        prop = fdt_getprop_by_offset(fdt, offset, &propname,
                                                     &err);
                        if (!prop)
                                return err;
                        break;

                default:
                        return -FDT_ERR_INTERNAL;
                }
        }
}