16caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent/*
26caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * Copyright (C) 2015 The Android Open Source Project
36caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent *
46caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * Licensed under the Apache License, Version 2.0 (the "License");
56caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * you may not use this file except in compliance with the License.
66caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * You may obtain a copy of the License at
76caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent *
86caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent *      http://www.apache.org/licenses/LICENSE-2.0
96caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent *
106caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * Unless required by applicable law or agreed to in writing, software
116caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * distributed under the License is distributed on an "AS IS" BASIS,
126caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * See the License for the specific language governing permissions and
146caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * limitations under the License.
156caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent */
166caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
176caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent#define LOG_TAG "radio_metadata"
186caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent/*#define LOG_NDEBUG 0*/
196caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
206caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent#include <errno.h>
218198c3b752e2fb00acb15345496e2a03eefb5ffbMark Salyzyn#include <limits.h>
226caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent#include <stdlib.h>
236caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent#include <string.h>
248198c3b752e2fb00acb15345496e2a03eefb5ffbMark Salyzyn
254df5a2bb302fb5cb61ab48dff7fa2b1984b6ced8Mark Salyzyn#include <log/log.h>
264df5a2bb302fb5cb61ab48dff7fa2b1984b6ced8Mark Salyzyn
276caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent#include <system/radio.h>
286caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent#include <system/radio_metadata.h>
29a2b50fb31ac5b6192dfe29859a56cee771c9dffeDan Willemsen#include "radio_metadata_hidden.h"
30a2b50fb31ac5b6192dfe29859a56cee771c9dffeDan Willemsen
316caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentconst radio_metadata_type_t metadata_key_type_table[] =
326caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
33acf670dcadd90f8499cef867dfe27770a0188491Tomasz Wasilczyk    RADIO_METADATA_TYPE_INT,
346caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_TEXT,
356caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_INT,
366caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_INT,
376caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_TEXT,
386caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_TEXT,
396caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_TEXT,
406caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_TEXT,
416caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_TEXT,
426caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_RAW,
436caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    RADIO_METADATA_TYPE_RAW,
443c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal    RADIO_METADATA_TYPE_CLOCK,
456caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent};
466caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
476caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent/**
486caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * private functions
496caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent */
506caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
516caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentbool is_valid_metadata_key(const radio_metadata_key_t key)
526caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
536caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (key < RADIO_METADATA_KEY_MIN || key > RADIO_METADATA_KEY_MAX) {
546caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return false;
556caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
566caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return true;
576caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
586caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
59ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurentint check_size(radio_metadata_buffer_t **metadata_ptr, const uint32_t size_int)
606caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
616caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *metadata = *metadata_ptr;
62ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t index_offset = metadata->size_int - metadata->count - 1;
63ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t data_offset = *((uint32_t *)metadata + index_offset);
64ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t req_size_int;
65ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t new_size_int;
666caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
67ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    LOG_ALWAYS_FATAL_IF(metadata->size_int < (metadata->count + 1),
68ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                        "%s: invalid size %u", __func__, metadata->size_int);
696caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (size_int == 0) {
706caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return 0;
716caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
726caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
736caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    req_size_int = data_offset + metadata->count + 1 + 1 + size_int;
746caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    /* do not grow buffer if it can accommodate the new entry plus an additional index entry */
756caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
766caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (req_size_int <= metadata->size_int) {
776caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return 0;
786caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
796caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
806caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (req_size_int > RADIO_METADATA_MAX_SIZE || metadata->size_int >= RADIO_METADATA_MAX_SIZE) {
816caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -ENOMEM;
826caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
836caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    /* grow meta data buffer by a factor of 2 until new data fits */
846caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    new_size_int = metadata->size_int;
856caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    while (new_size_int < req_size_int)
866caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        new_size_int *= 2;
876caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
886caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    ALOGV("%s growing from %u to %u", __func__, metadata->size_int, new_size_int);
89ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    metadata = realloc(metadata, new_size_int * sizeof(uint32_t));
906caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    /* move index table */
91ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    memmove((uint32_t *)metadata + new_size_int - (metadata->count + 1),
92ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent            (uint32_t *)metadata + metadata->size_int - (metadata->count + 1),
93ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent            (metadata->count + 1) * sizeof(uint32_t));
946caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    metadata->size_int = new_size_int;
956caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
966caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    *metadata_ptr = metadata;
976caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return 0;
986caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
996caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
1006caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent/* checks on size and key validity are done before calling this function */
1016caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint add_metadata(radio_metadata_buffer_t **metadata_ptr,
1026caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                 const radio_metadata_key_t key,
1036caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                 const radio_metadata_type_t type,
1046caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                 const void *value,
105ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                 const size_t size)
1066caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
107ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t entry_size_int;
1086caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    int ret;
1096caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_entry_t *entry;
110ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t index_offset;
111ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t data_offset;
1126caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *metadata = *metadata_ptr;
1136caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
114ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    entry_size_int = (uint32_t)(size + sizeof(radio_metadata_entry_t));
115ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    entry_size_int = (entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
1166caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
1176caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    ret = check_size(metadata_ptr, entry_size_int);
1186caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (ret < 0) {
1196caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return ret;
1206caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
1216caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    metadata = *metadata_ptr;
1226caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    index_offset = metadata->size_int - metadata->count - 1;
123ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    data_offset = *((uint32_t *)metadata + index_offset);
1246caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
125ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    entry = (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
1266caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    entry->key = key;
1276caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    entry->type = type;
128ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    entry->size = (uint32_t)size;
1296caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    memcpy(entry->data, value, size);
1306caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
1316caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    data_offset += entry_size_int;
132ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    *((uint32_t *)metadata + index_offset -1) = data_offset;
1336caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    metadata->count++;
134ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent
1356caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return 0;
1366caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
1376caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
1386caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentradio_metadata_entry_t *get_entry_at_index(
1396caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                    const radio_metadata_buffer_t *metadata,
1406caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                    const unsigned index,
1416caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                    bool check)
1426caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
143ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t index_offset = metadata->size_int - index - 1;
144ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t data_offset = *((uint32_t *)metadata + index_offset);
1456caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
146ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    LOG_ALWAYS_FATAL_IF(metadata->size_int < (index + 1),
147ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                        "%s: invalid size %u", __func__, metadata->size_int);
1486caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (check) {
1496caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (index >= metadata->count) {
1506caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            return NULL;
1516caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        }
152ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent        uint32_t min_offset;
153ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent        uint32_t max_offset;
154ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent        uint32_t min_entry_size_int;
155ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent        min_offset = (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
156ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                        sizeof(uint32_t);
1576caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (data_offset < min_offset) {
1586caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            return NULL;
1596caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        }
1606caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
161ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent        min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
162ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent
163ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent        LOG_ALWAYS_FATAL_IF(metadata->size_int < (metadata->count + 1),
164ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                            "%s: invalid size %u vs count %u", __func__,
165ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                            metadata->size_int, metadata->count);
166ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent
1676caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        max_offset = metadata->size_int - metadata->count - 1 - min_entry_size_int;
1686caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (data_offset > max_offset) {
1696caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            return NULL;
1706caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        }
1716caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
172ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    return (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
1736caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
1746caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
1756caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent/**
1766caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent * metadata API functions
1776caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent */
1786caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
1796caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentradio_metadata_type_t radio_metadata_type_of_key(const radio_metadata_key_t key)
1806caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
1816caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (!is_valid_metadata_key(key)) {
1826caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return RADIO_METADATA_TYPE_INVALID;
1836caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
1846caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return metadata_key_type_table[key - RADIO_METADATA_KEY_MIN];
1856caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
1866caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
1876caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint radio_metadata_allocate(radio_metadata_t **metadata,
188ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                            const uint32_t channel,
189ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                            const uint32_t sub_channel)
1906caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
1916caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *metadata_buf =
192ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent            (radio_metadata_buffer_t *)calloc(RADIO_METADATA_DEFAULT_SIZE, sizeof(uint32_t));
1936caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata_buf == NULL) {
1946caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -ENOMEM;
1956caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
1966caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
1976caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    metadata_buf->channel = channel;
1986caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    metadata_buf->sub_channel = sub_channel;
1996caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    metadata_buf->size_int = RADIO_METADATA_DEFAULT_SIZE;
200ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    *((uint32_t *)metadata_buf + RADIO_METADATA_DEFAULT_SIZE - 1) =
201ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent            (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
202ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                sizeof(uint32_t);
2036caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    *metadata = (radio_metadata_t *)metadata_buf;
2046caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return 0;
2056caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
2066caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
2076caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentvoid radio_metadata_deallocate(radio_metadata_t *metadata)
2086caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
2096caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    free(metadata);
2106caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
2116caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
2126caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint radio_metadata_add_int(radio_metadata_t **metadata,
2136caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                           const radio_metadata_key_t key,
214ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                           const int32_t value)
2156caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
2166caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_type_t type = radio_metadata_type_of_key(key);
2176caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_INT) {
2186caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
2196caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
2206caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return add_metadata((radio_metadata_buffer_t **)metadata,
221ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                        key, type, &value, sizeof(int32_t));
2226caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
2236caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
2246caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint radio_metadata_add_text(radio_metadata_t **metadata,
2256caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                            const radio_metadata_key_t key,
2266caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                            const char *value)
2276caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
2286caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_type_t type = radio_metadata_type_of_key(key);
2296caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_TEXT ||
2306caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            value == NULL || strlen(value) >= RADIO_METADATA_TEXT_LEN_MAX) {
2316caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
2326caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
2336caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return add_metadata((radio_metadata_buffer_t **)metadata, key, type, value, strlen(value) + 1);
2346caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
2356caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
2366caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint radio_metadata_add_raw(radio_metadata_t **metadata,
2376caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                           const radio_metadata_key_t key,
2386caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                           const unsigned char *value,
239ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                           const size_t size)
2406caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
2416caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_type_t type = radio_metadata_type_of_key(key);
2426caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_RAW || value == NULL) {
2436caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
2446caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
2456caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return add_metadata((radio_metadata_buffer_t **)metadata, key, type, value, size);
2466caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
2476caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
2483c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwalint radio_metadata_add_clock(radio_metadata_t **metadata,
2493c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal                             const radio_metadata_key_t key,
2503c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal                             const radio_metadata_clock_t *clock) {
2513c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal    radio_metadata_type_t type = radio_metadata_type_of_key(key);
2523c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal    if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_CLOCK ||
2533c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal        clock == NULL || clock->timezone_offset_in_minutes < (-12 * 60) ||
2543c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal        clock->timezone_offset_in_minutes > (14 * 60)) {
2553c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal        return -EINVAL;
2563c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal    }
2573c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal    return add_metadata(
2583c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal        (radio_metadata_buffer_t **)metadata, key, type, clock, sizeof(radio_metadata_clock_t));
2593c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal}
2603c4b35deff3f53ce8eb757bd6b33ad94e4c74d4fSanket Agarwal
2616caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint radio_metadata_add_metadata(radio_metadata_t **dst_metadata,
2626caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                           radio_metadata_t *src_metadata)
2636caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
2646caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *src_metadata_buf = (radio_metadata_buffer_t *)src_metadata;
2656caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *dst_metadata_buf;
2666caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    int status;
267ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t index;
2686caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
2696caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (dst_metadata == NULL || src_metadata == NULL) {
2706caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
2716caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
2726caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (*dst_metadata == NULL) {
2736caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        status = radio_metadata_allocate(dst_metadata, src_metadata_buf->channel,
2746caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                src_metadata_buf->sub_channel);
2756caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (status != 0) {
2766caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            return status;
2776caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        }
2786caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
2796caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
2806caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    dst_metadata_buf = (radio_metadata_buffer_t *)*dst_metadata;
2816caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    dst_metadata_buf->channel = src_metadata_buf->channel;
2826caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    dst_metadata_buf->sub_channel = src_metadata_buf->sub_channel;
2836caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
2846caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    for (index = 0; index < src_metadata_buf->count; index++) {
2856caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        radio_metadata_key_t key;
2866caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        radio_metadata_type_t type;
2876caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        void *value;
288ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent        size_t size;
2896caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        status = radio_metadata_get_at_index(src_metadata, index, &key, &type, &value, &size);
2906caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (status != 0)
2916caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            continue;
2926caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        status = add_metadata((radio_metadata_buffer_t **)dst_metadata, key, type, value, size);
2936caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (status != 0)
2946caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            break;
2956caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
2966caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return status;
2976caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
2986caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
2996caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint radio_metadata_check(const radio_metadata_t *metadata)
3006caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
3016caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *metadata_buf =
3026caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            (radio_metadata_buffer_t *)metadata;
303ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t count;
304ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t min_entry_size_int;
3056caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3066caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata_buf == NULL) {
3076caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
3086caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
3096caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3106caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata_buf->size_int > RADIO_METADATA_MAX_SIZE) {
3116caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
3126caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
3136caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3146caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    /* sanity check on entry count versus buffer size */
3156caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
316ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) /
317ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                                sizeof(uint32_t);
3186caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if ((metadata_buf->count * min_entry_size_int + metadata_buf->count + 1 +
319ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent            (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) / sizeof(uint32_t)) >
3206caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                    metadata_buf->size_int) {
3216caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
3226caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
3236caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3246caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    /* sanity check on each entry */
3256caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    for (count = 0; count < metadata_buf->count; count++) {
3266caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        radio_metadata_entry_t *entry = get_entry_at_index(metadata_buf, count, true);
3276caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        radio_metadata_entry_t *next_entry;
3286caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (entry == NULL) {
3296caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            return -EINVAL;
3306caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        }
3316caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (!is_valid_metadata_key(entry->key)) {
3326caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            return -EINVAL;
3336caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        }
3346caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (entry->type != radio_metadata_type_of_key(entry->key)) {
3356caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            return -EINVAL;
3366caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        }
3376caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3386caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        /* do not request check because next entry can be the free slot */
3396caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        next_entry = get_entry_at_index(metadata_buf, count + 1, false);
3406caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if ((char *)entry->data + entry->size > (char *)next_entry) {
3416caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            return -EINVAL;
3426caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        }
3436caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
3446caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3456caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return 0;
3466caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
3476caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3486caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentsize_t radio_metadata_get_size(const radio_metadata_t *metadata)
3496caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
3506caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *metadata_buf =
3516caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            (radio_metadata_buffer_t *)metadata;
3526caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3536caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata_buf == NULL) {
3546caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return 0;
3556caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
356ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    return metadata_buf->size_int * sizeof(uint32_t);
3576caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
3586caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3596caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint radio_metadata_get_count(const radio_metadata_t *metadata)
3606caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
3616caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *metadata_buf =
3626caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            (radio_metadata_buffer_t *)metadata;
3636caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3646caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata_buf == NULL) {
3656caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
3666caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
3676caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return (int)metadata_buf->count;
3686caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
3696caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3706caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint radio_metadata_get_at_index(const radio_metadata_t *metadata,
371ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                                const uint32_t index,
3726caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                radio_metadata_key_t *key,
3736caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                radio_metadata_type_t *type,
3746caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                void **value,
375ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                                size_t *size)
3766caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
3776caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_entry_t *entry;
3786caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *metadata_buf =
3796caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            (radio_metadata_buffer_t *)metadata;
3806caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3816caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata_buf == NULL || key == NULL || type == NULL ||
3826caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            value == NULL || size == NULL) {
3836caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
3846caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
3856caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (index >= metadata_buf->count) {
3866caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
3876caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
3886caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3896caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    entry = get_entry_at_index(metadata_buf, index, false);
3906caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    *key = entry->key;
3916caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    *type = entry->type;
3926caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    *value = (void *)entry->data;
393ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    *size = (size_t)entry->size;
3946caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3956caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return 0;
3966caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
3976caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
3986caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurentint radio_metadata_get_from_key(const radio_metadata_t *metadata,
3996caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                const radio_metadata_key_t key,
4006caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                radio_metadata_type_t *type,
4016caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent                                void **value,
402ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent                                size_t *size)
4036caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent{
404ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    uint32_t count;
4056caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_entry_t *entry = NULL;
4066caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    radio_metadata_buffer_t *metadata_buf =
4076caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            (radio_metadata_buffer_t *)metadata;
4086caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
4096caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (metadata_buf == NULL || type == NULL || value == NULL || size == NULL) {
4106caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
4116caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
4126caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (!is_valid_metadata_key(key)) {
4136caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -EINVAL;
4146caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
4156caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent
4166caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    for (count = 0; count < metadata_buf->count; entry = NULL, count++) {
4176caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        entry = get_entry_at_index(metadata_buf, count, false);
4186caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        if (entry->key == key) {
4196caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent            break;
4206caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        }
4216caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
4226caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    if (entry == NULL) {
4236caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent        return -ENOENT;
4246caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    }
4256caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    *type = entry->type;
4266caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    *value = (void *)entry->data;
427ff407960d77cad24b90c07a97e7aa431385f3607Eric Laurent    *size = (size_t)entry->size;
4286caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent    return 0;
4296caceaed8856e7e3cf05fa3232bc4fd8a22d2295Eric Laurent}
43071dd3519837738303185b888ed3741763b1ae3eeEric Laurent
43171dd3519837738303185b888ed3741763b1ae3eeEric Laurentint radio_metadata_get_channel(radio_metadata_t *metadata,
43271dd3519837738303185b888ed3741763b1ae3eeEric Laurent                               uint32_t *channel,
43371dd3519837738303185b888ed3741763b1ae3eeEric Laurent                               uint32_t *sub_channel)
43471dd3519837738303185b888ed3741763b1ae3eeEric Laurent{
43571dd3519837738303185b888ed3741763b1ae3eeEric Laurent    radio_metadata_buffer_t *metadata_buf =
43671dd3519837738303185b888ed3741763b1ae3eeEric Laurent            (radio_metadata_buffer_t *)metadata;
43771dd3519837738303185b888ed3741763b1ae3eeEric Laurent
43871dd3519837738303185b888ed3741763b1ae3eeEric Laurent    if (metadata_buf == NULL || channel == NULL || sub_channel == NULL) {
43971dd3519837738303185b888ed3741763b1ae3eeEric Laurent        return -EINVAL;
44071dd3519837738303185b888ed3741763b1ae3eeEric Laurent    }
44171dd3519837738303185b888ed3741763b1ae3eeEric Laurent    *channel = metadata_buf->channel;
44271dd3519837738303185b888ed3741763b1ae3eeEric Laurent    *sub_channel = metadata_buf->sub_channel;
44371dd3519837738303185b888ed3741763b1ae3eeEric Laurent    return 0;
44471dd3519837738303185b888ed3741763b1ae3eeEric Laurent}
445