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