xref: /aosp_15_r20/system/media/radio/src/radio_metadata.c (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker  *
4*b9df5ad1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker  *
8*b9df5ad1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker  *
10*b9df5ad1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker  * limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker  */
16*b9df5ad1SAndroid Build Coastguard Worker 
17*b9df5ad1SAndroid Build Coastguard Worker #define LOG_TAG "radio_metadata"
18*b9df5ad1SAndroid Build Coastguard Worker /*#define LOG_NDEBUG 0*/
19*b9df5ad1SAndroid Build Coastguard Worker 
20*b9df5ad1SAndroid Build Coastguard Worker #include <errno.h>
21*b9df5ad1SAndroid Build Coastguard Worker #include <limits.h>
22*b9df5ad1SAndroid Build Coastguard Worker #include <stdlib.h>
23*b9df5ad1SAndroid Build Coastguard Worker #include <string.h>
24*b9df5ad1SAndroid Build Coastguard Worker 
25*b9df5ad1SAndroid Build Coastguard Worker #include <log/log.h>
26*b9df5ad1SAndroid Build Coastguard Worker 
27*b9df5ad1SAndroid Build Coastguard Worker #include <system/radio.h>
28*b9df5ad1SAndroid Build Coastguard Worker #include <system/radio_metadata.h>
29*b9df5ad1SAndroid Build Coastguard Worker #include "radio_metadata_hidden.h"
30*b9df5ad1SAndroid Build Coastguard Worker 
31*b9df5ad1SAndroid Build Coastguard Worker const radio_metadata_type_t metadata_key_type_table[] =
32*b9df5ad1SAndroid Build Coastguard Worker {
33*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_INT,
34*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_TEXT,
35*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_INT,
36*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_INT,
37*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_TEXT,
38*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_TEXT,
39*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_TEXT,
40*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_TEXT,
41*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_TEXT,
42*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_RAW,
43*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_RAW,
44*b9df5ad1SAndroid Build Coastguard Worker     RADIO_METADATA_TYPE_CLOCK,
45*b9df5ad1SAndroid Build Coastguard Worker };
46*b9df5ad1SAndroid Build Coastguard Worker 
47*b9df5ad1SAndroid Build Coastguard Worker /**
48*b9df5ad1SAndroid Build Coastguard Worker  * private functions
49*b9df5ad1SAndroid Build Coastguard Worker  */
50*b9df5ad1SAndroid Build Coastguard Worker 
is_valid_metadata_key(const radio_metadata_key_t key)51*b9df5ad1SAndroid Build Coastguard Worker bool is_valid_metadata_key(const radio_metadata_key_t key)
52*b9df5ad1SAndroid Build Coastguard Worker {
53*b9df5ad1SAndroid Build Coastguard Worker     if (key < RADIO_METADATA_KEY_MIN || key > RADIO_METADATA_KEY_MAX) {
54*b9df5ad1SAndroid Build Coastguard Worker         return false;
55*b9df5ad1SAndroid Build Coastguard Worker     }
56*b9df5ad1SAndroid Build Coastguard Worker     return true;
57*b9df5ad1SAndroid Build Coastguard Worker }
58*b9df5ad1SAndroid Build Coastguard Worker 
check_size(radio_metadata_buffer_t ** metadata_ptr,const uint32_t size_int)59*b9df5ad1SAndroid Build Coastguard Worker int check_size(radio_metadata_buffer_t **metadata_ptr, const uint32_t size_int)
60*b9df5ad1SAndroid Build Coastguard Worker {
61*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *metadata = *metadata_ptr;
62*b9df5ad1SAndroid Build Coastguard Worker     uint32_t index_offset = metadata->size_int - metadata->count - 1;
63*b9df5ad1SAndroid Build Coastguard Worker     uint32_t data_offset = *((uint32_t *)metadata + index_offset);
64*b9df5ad1SAndroid Build Coastguard Worker     uint32_t req_size_int;
65*b9df5ad1SAndroid Build Coastguard Worker     uint32_t new_size_int;
66*b9df5ad1SAndroid Build Coastguard Worker 
67*b9df5ad1SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(metadata->size_int < (metadata->count + 1),
68*b9df5ad1SAndroid Build Coastguard Worker                         "%s: invalid size %u", __func__, metadata->size_int);
69*b9df5ad1SAndroid Build Coastguard Worker     if (size_int == 0) {
70*b9df5ad1SAndroid Build Coastguard Worker         return 0;
71*b9df5ad1SAndroid Build Coastguard Worker     }
72*b9df5ad1SAndroid Build Coastguard Worker 
73*b9df5ad1SAndroid Build Coastguard Worker     req_size_int = data_offset + metadata->count + 1 + 1 + size_int;
74*b9df5ad1SAndroid Build Coastguard Worker     /* do not grow buffer if it can accommodate the new entry plus an additional index entry */
75*b9df5ad1SAndroid Build Coastguard Worker 
76*b9df5ad1SAndroid Build Coastguard Worker     if (req_size_int <= metadata->size_int) {
77*b9df5ad1SAndroid Build Coastguard Worker         return 0;
78*b9df5ad1SAndroid Build Coastguard Worker     }
79*b9df5ad1SAndroid Build Coastguard Worker 
80*b9df5ad1SAndroid Build Coastguard Worker     if (req_size_int > RADIO_METADATA_MAX_SIZE || metadata->size_int >= RADIO_METADATA_MAX_SIZE) {
81*b9df5ad1SAndroid Build Coastguard Worker         return -ENOMEM;
82*b9df5ad1SAndroid Build Coastguard Worker     }
83*b9df5ad1SAndroid Build Coastguard Worker     /* grow meta data buffer by a factor of 2 until new data fits */
84*b9df5ad1SAndroid Build Coastguard Worker     new_size_int = metadata->size_int;
85*b9df5ad1SAndroid Build Coastguard Worker     while (new_size_int < req_size_int)
86*b9df5ad1SAndroid Build Coastguard Worker         new_size_int *= 2;
87*b9df5ad1SAndroid Build Coastguard Worker 
88*b9df5ad1SAndroid Build Coastguard Worker     ALOGV("%s growing from %u to %u", __func__, metadata->size_int, new_size_int);
89*b9df5ad1SAndroid Build Coastguard Worker     /* NOLINTNEXTLINE(clang-analyzer-unix.MallocSizeof) */
90*b9df5ad1SAndroid Build Coastguard Worker     metadata = realloc(metadata, new_size_int * sizeof(uint32_t));
91*b9df5ad1SAndroid Build Coastguard Worker     if (metadata == NULL) {
92*b9df5ad1SAndroid Build Coastguard Worker         return -ENOMEM;
93*b9df5ad1SAndroid Build Coastguard Worker     }
94*b9df5ad1SAndroid Build Coastguard Worker     /* move index table */
95*b9df5ad1SAndroid Build Coastguard Worker     memmove((uint32_t *)metadata + new_size_int - (metadata->count + 1),
96*b9df5ad1SAndroid Build Coastguard Worker             (uint32_t *)metadata + metadata->size_int - (metadata->count + 1),
97*b9df5ad1SAndroid Build Coastguard Worker             (metadata->count + 1) * sizeof(uint32_t));
98*b9df5ad1SAndroid Build Coastguard Worker     metadata->size_int = new_size_int;
99*b9df5ad1SAndroid Build Coastguard Worker 
100*b9df5ad1SAndroid Build Coastguard Worker     *metadata_ptr = metadata;
101*b9df5ad1SAndroid Build Coastguard Worker     return 0;
102*b9df5ad1SAndroid Build Coastguard Worker }
103*b9df5ad1SAndroid Build Coastguard Worker 
104*b9df5ad1SAndroid Build Coastguard Worker /* checks on size and key validity are done before calling this function */
add_metadata(radio_metadata_buffer_t ** metadata_ptr,const radio_metadata_key_t key,const radio_metadata_type_t type,const void * value,const size_t size)105*b9df5ad1SAndroid Build Coastguard Worker int add_metadata(radio_metadata_buffer_t **metadata_ptr,
106*b9df5ad1SAndroid Build Coastguard Worker                  const radio_metadata_key_t key,
107*b9df5ad1SAndroid Build Coastguard Worker                  const radio_metadata_type_t type,
108*b9df5ad1SAndroid Build Coastguard Worker                  const void *value,
109*b9df5ad1SAndroid Build Coastguard Worker                  const size_t size)
110*b9df5ad1SAndroid Build Coastguard Worker {
111*b9df5ad1SAndroid Build Coastguard Worker     uint32_t entry_size_int;
112*b9df5ad1SAndroid Build Coastguard Worker     int ret;
113*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_entry_t *entry;
114*b9df5ad1SAndroid Build Coastguard Worker     uint32_t index_offset;
115*b9df5ad1SAndroid Build Coastguard Worker     uint32_t data_offset;
116*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *metadata = *metadata_ptr;
117*b9df5ad1SAndroid Build Coastguard Worker 
118*b9df5ad1SAndroid Build Coastguard Worker     entry_size_int = (uint32_t)(size + sizeof(radio_metadata_entry_t));
119*b9df5ad1SAndroid Build Coastguard Worker     entry_size_int = (entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
120*b9df5ad1SAndroid Build Coastguard Worker 
121*b9df5ad1SAndroid Build Coastguard Worker     ret = check_size(metadata_ptr, entry_size_int);
122*b9df5ad1SAndroid Build Coastguard Worker     if (ret < 0) {
123*b9df5ad1SAndroid Build Coastguard Worker         return ret;
124*b9df5ad1SAndroid Build Coastguard Worker     }
125*b9df5ad1SAndroid Build Coastguard Worker     metadata = *metadata_ptr;
126*b9df5ad1SAndroid Build Coastguard Worker     index_offset = metadata->size_int - metadata->count - 1;
127*b9df5ad1SAndroid Build Coastguard Worker     data_offset = *((uint32_t *)metadata + index_offset);
128*b9df5ad1SAndroid Build Coastguard Worker 
129*b9df5ad1SAndroid Build Coastguard Worker     entry = (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
130*b9df5ad1SAndroid Build Coastguard Worker     entry->key = key;
131*b9df5ad1SAndroid Build Coastguard Worker     entry->type = type;
132*b9df5ad1SAndroid Build Coastguard Worker     entry->size = (uint32_t)size;
133*b9df5ad1SAndroid Build Coastguard Worker     memcpy(entry->data, value, size);
134*b9df5ad1SAndroid Build Coastguard Worker 
135*b9df5ad1SAndroid Build Coastguard Worker     data_offset += entry_size_int;
136*b9df5ad1SAndroid Build Coastguard Worker     *((uint32_t *)metadata + index_offset -1) = data_offset;
137*b9df5ad1SAndroid Build Coastguard Worker     metadata->count++;
138*b9df5ad1SAndroid Build Coastguard Worker 
139*b9df5ad1SAndroid Build Coastguard Worker     return 0;
140*b9df5ad1SAndroid Build Coastguard Worker }
141*b9df5ad1SAndroid Build Coastguard Worker 
get_entry_at_index(const radio_metadata_buffer_t * metadata,const unsigned index,bool check)142*b9df5ad1SAndroid Build Coastguard Worker radio_metadata_entry_t *get_entry_at_index(
143*b9df5ad1SAndroid Build Coastguard Worker                                     const radio_metadata_buffer_t *metadata,
144*b9df5ad1SAndroid Build Coastguard Worker                                     const unsigned index,
145*b9df5ad1SAndroid Build Coastguard Worker                                     bool check)
146*b9df5ad1SAndroid Build Coastguard Worker {
147*b9df5ad1SAndroid Build Coastguard Worker     uint32_t index_offset = metadata->size_int - index - 1;
148*b9df5ad1SAndroid Build Coastguard Worker     uint32_t data_offset = *((uint32_t *)metadata + index_offset);
149*b9df5ad1SAndroid Build Coastguard Worker 
150*b9df5ad1SAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(metadata->size_int < (index + 1),
151*b9df5ad1SAndroid Build Coastguard Worker                         "%s: invalid size %u", __func__, metadata->size_int);
152*b9df5ad1SAndroid Build Coastguard Worker     if (check) {
153*b9df5ad1SAndroid Build Coastguard Worker         if (index >= metadata->count) {
154*b9df5ad1SAndroid Build Coastguard Worker             return NULL;
155*b9df5ad1SAndroid Build Coastguard Worker         }
156*b9df5ad1SAndroid Build Coastguard Worker         uint32_t min_offset;
157*b9df5ad1SAndroid Build Coastguard Worker         uint32_t max_offset;
158*b9df5ad1SAndroid Build Coastguard Worker         uint32_t min_entry_size_int;
159*b9df5ad1SAndroid Build Coastguard Worker         min_offset = (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
160*b9df5ad1SAndroid Build Coastguard Worker                         sizeof(uint32_t);
161*b9df5ad1SAndroid Build Coastguard Worker         if (data_offset < min_offset) {
162*b9df5ad1SAndroid Build Coastguard Worker             return NULL;
163*b9df5ad1SAndroid Build Coastguard Worker         }
164*b9df5ad1SAndroid Build Coastguard Worker         min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
165*b9df5ad1SAndroid Build Coastguard Worker         min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
166*b9df5ad1SAndroid Build Coastguard Worker 
167*b9df5ad1SAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(metadata->size_int < (metadata->count + 1),
168*b9df5ad1SAndroid Build Coastguard Worker                             "%s: invalid size %u vs count %u", __func__,
169*b9df5ad1SAndroid Build Coastguard Worker                             metadata->size_int, metadata->count);
170*b9df5ad1SAndroid Build Coastguard Worker 
171*b9df5ad1SAndroid Build Coastguard Worker         max_offset = metadata->size_int - metadata->count - 1 - min_entry_size_int;
172*b9df5ad1SAndroid Build Coastguard Worker         if (data_offset > max_offset) {
173*b9df5ad1SAndroid Build Coastguard Worker             return NULL;
174*b9df5ad1SAndroid Build Coastguard Worker         }
175*b9df5ad1SAndroid Build Coastguard Worker     }
176*b9df5ad1SAndroid Build Coastguard Worker     return (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
177*b9df5ad1SAndroid Build Coastguard Worker }
178*b9df5ad1SAndroid Build Coastguard Worker 
179*b9df5ad1SAndroid Build Coastguard Worker /**
180*b9df5ad1SAndroid Build Coastguard Worker  * metadata API functions
181*b9df5ad1SAndroid Build Coastguard Worker  */
182*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_type_of_key(const radio_metadata_key_t key)183*b9df5ad1SAndroid Build Coastguard Worker radio_metadata_type_t radio_metadata_type_of_key(const radio_metadata_key_t key)
184*b9df5ad1SAndroid Build Coastguard Worker {
185*b9df5ad1SAndroid Build Coastguard Worker     if (!is_valid_metadata_key(key)) {
186*b9df5ad1SAndroid Build Coastguard Worker         return RADIO_METADATA_TYPE_INVALID;
187*b9df5ad1SAndroid Build Coastguard Worker     }
188*b9df5ad1SAndroid Build Coastguard Worker     return metadata_key_type_table[key - RADIO_METADATA_KEY_MIN];
189*b9df5ad1SAndroid Build Coastguard Worker }
190*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_allocate(radio_metadata_t ** metadata,const uint32_t channel,const uint32_t sub_channel)191*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_allocate(radio_metadata_t **metadata,
192*b9df5ad1SAndroid Build Coastguard Worker                             const uint32_t channel,
193*b9df5ad1SAndroid Build Coastguard Worker                             const uint32_t sub_channel)
194*b9df5ad1SAndroid Build Coastguard Worker {
195*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *metadata_buf =
196*b9df5ad1SAndroid Build Coastguard Worker             /* NOLINTNEXTLINE(clang-analyzer-unix.MallocSizeof) */
197*b9df5ad1SAndroid Build Coastguard Worker             (radio_metadata_buffer_t *)calloc(RADIO_METADATA_DEFAULT_SIZE, sizeof(uint32_t));
198*b9df5ad1SAndroid Build Coastguard Worker     if (metadata_buf == NULL) {
199*b9df5ad1SAndroid Build Coastguard Worker         return -ENOMEM;
200*b9df5ad1SAndroid Build Coastguard Worker     }
201*b9df5ad1SAndroid Build Coastguard Worker 
202*b9df5ad1SAndroid Build Coastguard Worker     metadata_buf->channel = channel;
203*b9df5ad1SAndroid Build Coastguard Worker     metadata_buf->sub_channel = sub_channel;
204*b9df5ad1SAndroid Build Coastguard Worker     metadata_buf->size_int = RADIO_METADATA_DEFAULT_SIZE;
205*b9df5ad1SAndroid Build Coastguard Worker     *((uint32_t *)metadata_buf + RADIO_METADATA_DEFAULT_SIZE - 1) =
206*b9df5ad1SAndroid Build Coastguard Worker             (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
207*b9df5ad1SAndroid Build Coastguard Worker                 sizeof(uint32_t);
208*b9df5ad1SAndroid Build Coastguard Worker     *metadata = (radio_metadata_t *)metadata_buf;
209*b9df5ad1SAndroid Build Coastguard Worker     return 0;
210*b9df5ad1SAndroid Build Coastguard Worker }
211*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_deallocate(radio_metadata_t * metadata)212*b9df5ad1SAndroid Build Coastguard Worker void radio_metadata_deallocate(radio_metadata_t *metadata)
213*b9df5ad1SAndroid Build Coastguard Worker {
214*b9df5ad1SAndroid Build Coastguard Worker     free(metadata);
215*b9df5ad1SAndroid Build Coastguard Worker }
216*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_add_int(radio_metadata_t ** metadata,const radio_metadata_key_t key,const int32_t value)217*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_add_int(radio_metadata_t **metadata,
218*b9df5ad1SAndroid Build Coastguard Worker                            const radio_metadata_key_t key,
219*b9df5ad1SAndroid Build Coastguard Worker                            const int32_t value)
220*b9df5ad1SAndroid Build Coastguard Worker {
221*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_type_t type = radio_metadata_type_of_key(key);
222*b9df5ad1SAndroid Build Coastguard Worker     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_INT) {
223*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
224*b9df5ad1SAndroid Build Coastguard Worker     }
225*b9df5ad1SAndroid Build Coastguard Worker     return add_metadata((radio_metadata_buffer_t **)metadata,
226*b9df5ad1SAndroid Build Coastguard Worker                         key, type, &value, sizeof(int32_t));
227*b9df5ad1SAndroid Build Coastguard Worker }
228*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_add_text(radio_metadata_t ** metadata,const radio_metadata_key_t key,const char * value)229*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_add_text(radio_metadata_t **metadata,
230*b9df5ad1SAndroid Build Coastguard Worker                             const radio_metadata_key_t key,
231*b9df5ad1SAndroid Build Coastguard Worker                             const char *value)
232*b9df5ad1SAndroid Build Coastguard Worker {
233*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_type_t type = radio_metadata_type_of_key(key);
234*b9df5ad1SAndroid Build Coastguard Worker     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_TEXT ||
235*b9df5ad1SAndroid Build Coastguard Worker             value == NULL || strlen(value) >= RADIO_METADATA_TEXT_LEN_MAX) {
236*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
237*b9df5ad1SAndroid Build Coastguard Worker     }
238*b9df5ad1SAndroid Build Coastguard Worker     return add_metadata((radio_metadata_buffer_t **)metadata, key, type, value, strlen(value) + 1);
239*b9df5ad1SAndroid Build Coastguard Worker }
240*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_add_raw(radio_metadata_t ** metadata,const radio_metadata_key_t key,const unsigned char * value,const size_t size)241*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_add_raw(radio_metadata_t **metadata,
242*b9df5ad1SAndroid Build Coastguard Worker                            const radio_metadata_key_t key,
243*b9df5ad1SAndroid Build Coastguard Worker                            const unsigned char *value,
244*b9df5ad1SAndroid Build Coastguard Worker                            const size_t size)
245*b9df5ad1SAndroid Build Coastguard Worker {
246*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_type_t type = radio_metadata_type_of_key(key);
247*b9df5ad1SAndroid Build Coastguard Worker     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_RAW || value == NULL) {
248*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
249*b9df5ad1SAndroid Build Coastguard Worker     }
250*b9df5ad1SAndroid Build Coastguard Worker     return add_metadata((radio_metadata_buffer_t **)metadata, key, type, value, size);
251*b9df5ad1SAndroid Build Coastguard Worker }
252*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_add_clock(radio_metadata_t ** metadata,const radio_metadata_key_t key,const radio_metadata_clock_t * clock)253*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_add_clock(radio_metadata_t **metadata,
254*b9df5ad1SAndroid Build Coastguard Worker                              const radio_metadata_key_t key,
255*b9df5ad1SAndroid Build Coastguard Worker                              const radio_metadata_clock_t *clock) {
256*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_type_t type = radio_metadata_type_of_key(key);
257*b9df5ad1SAndroid Build Coastguard Worker     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_CLOCK ||
258*b9df5ad1SAndroid Build Coastguard Worker         clock == NULL || clock->timezone_offset_in_minutes < (-12 * 60) ||
259*b9df5ad1SAndroid Build Coastguard Worker         clock->timezone_offset_in_minutes > (14 * 60)) {
260*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
261*b9df5ad1SAndroid Build Coastguard Worker     }
262*b9df5ad1SAndroid Build Coastguard Worker     return add_metadata(
263*b9df5ad1SAndroid Build Coastguard Worker         (radio_metadata_buffer_t **)metadata, key, type, clock, sizeof(radio_metadata_clock_t));
264*b9df5ad1SAndroid Build Coastguard Worker }
265*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_add_metadata(radio_metadata_t ** dst_metadata,radio_metadata_t * src_metadata)266*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_add_metadata(radio_metadata_t **dst_metadata,
267*b9df5ad1SAndroid Build Coastguard Worker                            radio_metadata_t *src_metadata)
268*b9df5ad1SAndroid Build Coastguard Worker {
269*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *src_metadata_buf = (radio_metadata_buffer_t *)src_metadata;
270*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *dst_metadata_buf;
271*b9df5ad1SAndroid Build Coastguard Worker     int status;
272*b9df5ad1SAndroid Build Coastguard Worker     uint32_t index;
273*b9df5ad1SAndroid Build Coastguard Worker 
274*b9df5ad1SAndroid Build Coastguard Worker     if (dst_metadata == NULL || src_metadata == NULL) {
275*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
276*b9df5ad1SAndroid Build Coastguard Worker     }
277*b9df5ad1SAndroid Build Coastguard Worker     if (*dst_metadata == NULL) {
278*b9df5ad1SAndroid Build Coastguard Worker         status = radio_metadata_allocate(dst_metadata, src_metadata_buf->channel,
279*b9df5ad1SAndroid Build Coastguard Worker                                 src_metadata_buf->sub_channel);
280*b9df5ad1SAndroid Build Coastguard Worker         if (status != 0) {
281*b9df5ad1SAndroid Build Coastguard Worker             return status;
282*b9df5ad1SAndroid Build Coastguard Worker         }
283*b9df5ad1SAndroid Build Coastguard Worker     }
284*b9df5ad1SAndroid Build Coastguard Worker 
285*b9df5ad1SAndroid Build Coastguard Worker     dst_metadata_buf = (radio_metadata_buffer_t *)*dst_metadata;
286*b9df5ad1SAndroid Build Coastguard Worker     dst_metadata_buf->channel = src_metadata_buf->channel;
287*b9df5ad1SAndroid Build Coastguard Worker     dst_metadata_buf->sub_channel = src_metadata_buf->sub_channel;
288*b9df5ad1SAndroid Build Coastguard Worker 
289*b9df5ad1SAndroid Build Coastguard Worker     for (index = 0; index < src_metadata_buf->count; index++) {
290*b9df5ad1SAndroid Build Coastguard Worker         radio_metadata_key_t key;
291*b9df5ad1SAndroid Build Coastguard Worker         radio_metadata_type_t type;
292*b9df5ad1SAndroid Build Coastguard Worker         void *value;
293*b9df5ad1SAndroid Build Coastguard Worker         size_t size;
294*b9df5ad1SAndroid Build Coastguard Worker         status = radio_metadata_get_at_index(src_metadata, index, &key, &type, &value, &size);
295*b9df5ad1SAndroid Build Coastguard Worker         if (status != 0)
296*b9df5ad1SAndroid Build Coastguard Worker             continue;
297*b9df5ad1SAndroid Build Coastguard Worker         status = add_metadata((radio_metadata_buffer_t **)dst_metadata, key, type, value, size);
298*b9df5ad1SAndroid Build Coastguard Worker         if (status != 0)
299*b9df5ad1SAndroid Build Coastguard Worker             break;
300*b9df5ad1SAndroid Build Coastguard Worker     }
301*b9df5ad1SAndroid Build Coastguard Worker     return status;
302*b9df5ad1SAndroid Build Coastguard Worker }
303*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_check(const radio_metadata_t * metadata)304*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_check(const radio_metadata_t *metadata)
305*b9df5ad1SAndroid Build Coastguard Worker {
306*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *metadata_buf =
307*b9df5ad1SAndroid Build Coastguard Worker             (radio_metadata_buffer_t *)metadata;
308*b9df5ad1SAndroid Build Coastguard Worker     uint32_t count;
309*b9df5ad1SAndroid Build Coastguard Worker     uint32_t min_entry_size_int;
310*b9df5ad1SAndroid Build Coastguard Worker 
311*b9df5ad1SAndroid Build Coastguard Worker     if (metadata_buf == NULL) {
312*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
313*b9df5ad1SAndroid Build Coastguard Worker     }
314*b9df5ad1SAndroid Build Coastguard Worker 
315*b9df5ad1SAndroid Build Coastguard Worker     if (metadata_buf->size_int > RADIO_METADATA_MAX_SIZE) {
316*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
317*b9df5ad1SAndroid Build Coastguard Worker     }
318*b9df5ad1SAndroid Build Coastguard Worker 
319*b9df5ad1SAndroid Build Coastguard Worker     /* sanity check on entry count versus buffer size */
320*b9df5ad1SAndroid Build Coastguard Worker     min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
321*b9df5ad1SAndroid Build Coastguard Worker     min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) /
322*b9df5ad1SAndroid Build Coastguard Worker                                 sizeof(uint32_t);
323*b9df5ad1SAndroid Build Coastguard Worker     if ((metadata_buf->count * min_entry_size_int + metadata_buf->count + 1 +
324*b9df5ad1SAndroid Build Coastguard Worker             (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) / sizeof(uint32_t)) >
325*b9df5ad1SAndroid Build Coastguard Worker                     metadata_buf->size_int) {
326*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
327*b9df5ad1SAndroid Build Coastguard Worker     }
328*b9df5ad1SAndroid Build Coastguard Worker 
329*b9df5ad1SAndroid Build Coastguard Worker     /* sanity check on each entry */
330*b9df5ad1SAndroid Build Coastguard Worker     for (count = 0; count < metadata_buf->count; count++) {
331*b9df5ad1SAndroid Build Coastguard Worker         radio_metadata_entry_t *entry = get_entry_at_index(metadata_buf, count, true);
332*b9df5ad1SAndroid Build Coastguard Worker         radio_metadata_entry_t *next_entry;
333*b9df5ad1SAndroid Build Coastguard Worker         if (entry == NULL) {
334*b9df5ad1SAndroid Build Coastguard Worker             return -EINVAL;
335*b9df5ad1SAndroid Build Coastguard Worker         }
336*b9df5ad1SAndroid Build Coastguard Worker         if (!is_valid_metadata_key(entry->key)) {
337*b9df5ad1SAndroid Build Coastguard Worker             return -EINVAL;
338*b9df5ad1SAndroid Build Coastguard Worker         }
339*b9df5ad1SAndroid Build Coastguard Worker         if (entry->type != radio_metadata_type_of_key(entry->key)) {
340*b9df5ad1SAndroid Build Coastguard Worker             return -EINVAL;
341*b9df5ad1SAndroid Build Coastguard Worker         }
342*b9df5ad1SAndroid Build Coastguard Worker 
343*b9df5ad1SAndroid Build Coastguard Worker         /* do not request check because next entry can be the free slot */
344*b9df5ad1SAndroid Build Coastguard Worker         next_entry = get_entry_at_index(metadata_buf, count + 1, false);
345*b9df5ad1SAndroid Build Coastguard Worker         if ((char *)entry->data + entry->size > (char *)next_entry) {
346*b9df5ad1SAndroid Build Coastguard Worker             return -EINVAL;
347*b9df5ad1SAndroid Build Coastguard Worker         }
348*b9df5ad1SAndroid Build Coastguard Worker     }
349*b9df5ad1SAndroid Build Coastguard Worker 
350*b9df5ad1SAndroid Build Coastguard Worker     return 0;
351*b9df5ad1SAndroid Build Coastguard Worker }
352*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_get_size(const radio_metadata_t * metadata)353*b9df5ad1SAndroid Build Coastguard Worker size_t radio_metadata_get_size(const radio_metadata_t *metadata)
354*b9df5ad1SAndroid Build Coastguard Worker {
355*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *metadata_buf =
356*b9df5ad1SAndroid Build Coastguard Worker             (radio_metadata_buffer_t *)metadata;
357*b9df5ad1SAndroid Build Coastguard Worker 
358*b9df5ad1SAndroid Build Coastguard Worker     if (metadata_buf == NULL) {
359*b9df5ad1SAndroid Build Coastguard Worker         return 0;
360*b9df5ad1SAndroid Build Coastguard Worker     }
361*b9df5ad1SAndroid Build Coastguard Worker     return metadata_buf->size_int * sizeof(uint32_t);
362*b9df5ad1SAndroid Build Coastguard Worker }
363*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_get_count(const radio_metadata_t * metadata)364*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_get_count(const radio_metadata_t *metadata)
365*b9df5ad1SAndroid Build Coastguard Worker {
366*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *metadata_buf =
367*b9df5ad1SAndroid Build Coastguard Worker             (radio_metadata_buffer_t *)metadata;
368*b9df5ad1SAndroid Build Coastguard Worker 
369*b9df5ad1SAndroid Build Coastguard Worker     if (metadata_buf == NULL) {
370*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
371*b9df5ad1SAndroid Build Coastguard Worker     }
372*b9df5ad1SAndroid Build Coastguard Worker     return (int)metadata_buf->count;
373*b9df5ad1SAndroid Build Coastguard Worker }
374*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_get_at_index(const radio_metadata_t * metadata,const uint32_t index,radio_metadata_key_t * key,radio_metadata_type_t * type,void ** value,size_t * size)375*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_get_at_index(const radio_metadata_t *metadata,
376*b9df5ad1SAndroid Build Coastguard Worker                                 const uint32_t index,
377*b9df5ad1SAndroid Build Coastguard Worker                                 radio_metadata_key_t *key,
378*b9df5ad1SAndroid Build Coastguard Worker                                 radio_metadata_type_t *type,
379*b9df5ad1SAndroid Build Coastguard Worker                                 void **value,
380*b9df5ad1SAndroid Build Coastguard Worker                                 size_t *size)
381*b9df5ad1SAndroid Build Coastguard Worker {
382*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_entry_t *entry;
383*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *metadata_buf =
384*b9df5ad1SAndroid Build Coastguard Worker             (radio_metadata_buffer_t *)metadata;
385*b9df5ad1SAndroid Build Coastguard Worker 
386*b9df5ad1SAndroid Build Coastguard Worker     if (metadata_buf == NULL || key == NULL || type == NULL ||
387*b9df5ad1SAndroid Build Coastguard Worker             value == NULL || size == NULL) {
388*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
389*b9df5ad1SAndroid Build Coastguard Worker     }
390*b9df5ad1SAndroid Build Coastguard Worker     if (index >= metadata_buf->count) {
391*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
392*b9df5ad1SAndroid Build Coastguard Worker     }
393*b9df5ad1SAndroid Build Coastguard Worker 
394*b9df5ad1SAndroid Build Coastguard Worker     entry = get_entry_at_index(metadata_buf, index, false);
395*b9df5ad1SAndroid Build Coastguard Worker     *key = entry->key;
396*b9df5ad1SAndroid Build Coastguard Worker     *type = entry->type;
397*b9df5ad1SAndroid Build Coastguard Worker     *value = (void *)entry->data;
398*b9df5ad1SAndroid Build Coastguard Worker     *size = (size_t)entry->size;
399*b9df5ad1SAndroid Build Coastguard Worker 
400*b9df5ad1SAndroid Build Coastguard Worker     return 0;
401*b9df5ad1SAndroid Build Coastguard Worker }
402*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_get_from_key(const radio_metadata_t * metadata,const radio_metadata_key_t key,radio_metadata_type_t * type,void ** value,size_t * size)403*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_get_from_key(const radio_metadata_t *metadata,
404*b9df5ad1SAndroid Build Coastguard Worker                                 const radio_metadata_key_t key,
405*b9df5ad1SAndroid Build Coastguard Worker                                 radio_metadata_type_t *type,
406*b9df5ad1SAndroid Build Coastguard Worker                                 void **value,
407*b9df5ad1SAndroid Build Coastguard Worker                                 size_t *size)
408*b9df5ad1SAndroid Build Coastguard Worker {
409*b9df5ad1SAndroid Build Coastguard Worker     uint32_t count;
410*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_entry_t *entry = NULL;
411*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *metadata_buf =
412*b9df5ad1SAndroid Build Coastguard Worker             (radio_metadata_buffer_t *)metadata;
413*b9df5ad1SAndroid Build Coastguard Worker 
414*b9df5ad1SAndroid Build Coastguard Worker     if (metadata_buf == NULL || type == NULL || value == NULL || size == NULL) {
415*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
416*b9df5ad1SAndroid Build Coastguard Worker     }
417*b9df5ad1SAndroid Build Coastguard Worker     if (!is_valid_metadata_key(key)) {
418*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
419*b9df5ad1SAndroid Build Coastguard Worker     }
420*b9df5ad1SAndroid Build Coastguard Worker 
421*b9df5ad1SAndroid Build Coastguard Worker     for (count = 0; count < metadata_buf->count; entry = NULL, count++) {
422*b9df5ad1SAndroid Build Coastguard Worker         entry = get_entry_at_index(metadata_buf, count, false);
423*b9df5ad1SAndroid Build Coastguard Worker         if (entry->key == key) {
424*b9df5ad1SAndroid Build Coastguard Worker             break;
425*b9df5ad1SAndroid Build Coastguard Worker         }
426*b9df5ad1SAndroid Build Coastguard Worker     }
427*b9df5ad1SAndroid Build Coastguard Worker     if (entry == NULL) {
428*b9df5ad1SAndroid Build Coastguard Worker         return -ENOENT;
429*b9df5ad1SAndroid Build Coastguard Worker     }
430*b9df5ad1SAndroid Build Coastguard Worker     *type = entry->type;
431*b9df5ad1SAndroid Build Coastguard Worker     *value = (void *)entry->data;
432*b9df5ad1SAndroid Build Coastguard Worker     *size = (size_t)entry->size;
433*b9df5ad1SAndroid Build Coastguard Worker     return 0;
434*b9df5ad1SAndroid Build Coastguard Worker }
435*b9df5ad1SAndroid Build Coastguard Worker 
radio_metadata_get_channel(radio_metadata_t * metadata,uint32_t * channel,uint32_t * sub_channel)436*b9df5ad1SAndroid Build Coastguard Worker int radio_metadata_get_channel(radio_metadata_t *metadata,
437*b9df5ad1SAndroid Build Coastguard Worker                                uint32_t *channel,
438*b9df5ad1SAndroid Build Coastguard Worker                                uint32_t *sub_channel)
439*b9df5ad1SAndroid Build Coastguard Worker {
440*b9df5ad1SAndroid Build Coastguard Worker     radio_metadata_buffer_t *metadata_buf =
441*b9df5ad1SAndroid Build Coastguard Worker             (radio_metadata_buffer_t *)metadata;
442*b9df5ad1SAndroid Build Coastguard Worker 
443*b9df5ad1SAndroid Build Coastguard Worker     if (metadata_buf == NULL || channel == NULL || sub_channel == NULL) {
444*b9df5ad1SAndroid Build Coastguard Worker         return -EINVAL;
445*b9df5ad1SAndroid Build Coastguard Worker     }
446*b9df5ad1SAndroid Build Coastguard Worker     *channel = metadata_buf->channel;
447*b9df5ad1SAndroid Build Coastguard Worker     *sub_channel = metadata_buf->sub_channel;
448*b9df5ad1SAndroid Build Coastguard Worker     return 0;
449*b9df5ad1SAndroid Build Coastguard Worker }
450