• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     metadata = realloc(metadata, new_size_int * sizeof(uint32_t));
90     if (metadata == NULL) {
91         return -ENOMEM;
92     }
93     /* move index table */
94     memmove((uint32_t *)metadata + new_size_int - (metadata->count + 1),
95             (uint32_t *)metadata + metadata->size_int - (metadata->count + 1),
96             (metadata->count + 1) * sizeof(uint32_t));
97     metadata->size_int = new_size_int;
98 
99     *metadata_ptr = metadata;
100     return 0;
101 }
102 
103 /* 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)104 int add_metadata(radio_metadata_buffer_t **metadata_ptr,
105                  const radio_metadata_key_t key,
106                  const radio_metadata_type_t type,
107                  const void *value,
108                  const size_t size)
109 {
110     uint32_t entry_size_int;
111     int ret;
112     radio_metadata_entry_t *entry;
113     uint32_t index_offset;
114     uint32_t data_offset;
115     radio_metadata_buffer_t *metadata = *metadata_ptr;
116 
117     entry_size_int = (uint32_t)(size + sizeof(radio_metadata_entry_t));
118     entry_size_int = (entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
119 
120     ret = check_size(metadata_ptr, entry_size_int);
121     if (ret < 0) {
122         return ret;
123     }
124     metadata = *metadata_ptr;
125     index_offset = metadata->size_int - metadata->count - 1;
126     data_offset = *((uint32_t *)metadata + index_offset);
127 
128     entry = (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
129     entry->key = key;
130     entry->type = type;
131     entry->size = (uint32_t)size;
132     memcpy(entry->data, value, size);
133 
134     data_offset += entry_size_int;
135     *((uint32_t *)metadata + index_offset -1) = data_offset;
136     metadata->count++;
137 
138     return 0;
139 }
140 
get_entry_at_index(const radio_metadata_buffer_t * metadata,const unsigned index,bool check)141 radio_metadata_entry_t *get_entry_at_index(
142                                     const radio_metadata_buffer_t *metadata,
143                                     const unsigned index,
144                                     bool check)
145 {
146     uint32_t index_offset = metadata->size_int - index - 1;
147     uint32_t data_offset = *((uint32_t *)metadata + index_offset);
148 
149     LOG_ALWAYS_FATAL_IF(metadata->size_int < (index + 1),
150                         "%s: invalid size %u", __func__, metadata->size_int);
151     if (check) {
152         if (index >= metadata->count) {
153             return NULL;
154         }
155         uint32_t min_offset;
156         uint32_t max_offset;
157         uint32_t min_entry_size_int;
158         min_offset = (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
159                         sizeof(uint32_t);
160         if (data_offset < min_offset) {
161             return NULL;
162         }
163         min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
164         min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) / sizeof(uint32_t);
165 
166         LOG_ALWAYS_FATAL_IF(metadata->size_int < (metadata->count + 1),
167                             "%s: invalid size %u vs count %u", __func__,
168                             metadata->size_int, metadata->count);
169 
170         max_offset = metadata->size_int - metadata->count - 1 - min_entry_size_int;
171         if (data_offset > max_offset) {
172             return NULL;
173         }
174     }
175     return (radio_metadata_entry_t *)((uint32_t *)metadata + data_offset);
176 }
177 
178 /**
179  * metadata API functions
180  */
181 
radio_metadata_type_of_key(const radio_metadata_key_t key)182 radio_metadata_type_t radio_metadata_type_of_key(const radio_metadata_key_t key)
183 {
184     if (!is_valid_metadata_key(key)) {
185         return RADIO_METADATA_TYPE_INVALID;
186     }
187     return metadata_key_type_table[key - RADIO_METADATA_KEY_MIN];
188 }
189 
radio_metadata_allocate(radio_metadata_t ** metadata,const uint32_t channel,const uint32_t sub_channel)190 int radio_metadata_allocate(radio_metadata_t **metadata,
191                             const uint32_t channel,
192                             const uint32_t sub_channel)
193 {
194     radio_metadata_buffer_t *metadata_buf =
195             (radio_metadata_buffer_t *)calloc(RADIO_METADATA_DEFAULT_SIZE, sizeof(uint32_t));
196     if (metadata_buf == NULL) {
197         return -ENOMEM;
198     }
199 
200     metadata_buf->channel = channel;
201     metadata_buf->sub_channel = sub_channel;
202     metadata_buf->size_int = RADIO_METADATA_DEFAULT_SIZE;
203     *((uint32_t *)metadata_buf + RADIO_METADATA_DEFAULT_SIZE - 1) =
204             (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) /
205                 sizeof(uint32_t);
206     *metadata = (radio_metadata_t *)metadata_buf;
207     return 0;
208 }
209 
radio_metadata_deallocate(radio_metadata_t * metadata)210 void radio_metadata_deallocate(radio_metadata_t *metadata)
211 {
212     free(metadata);
213 }
214 
radio_metadata_add_int(radio_metadata_t ** metadata,const radio_metadata_key_t key,const int32_t value)215 int radio_metadata_add_int(radio_metadata_t **metadata,
216                            const radio_metadata_key_t key,
217                            const int32_t value)
218 {
219     radio_metadata_type_t type = radio_metadata_type_of_key(key);
220     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_INT) {
221         return -EINVAL;
222     }
223     return add_metadata((radio_metadata_buffer_t **)metadata,
224                         key, type, &value, sizeof(int32_t));
225 }
226 
radio_metadata_add_text(radio_metadata_t ** metadata,const radio_metadata_key_t key,const char * value)227 int radio_metadata_add_text(radio_metadata_t **metadata,
228                             const radio_metadata_key_t key,
229                             const char *value)
230 {
231     radio_metadata_type_t type = radio_metadata_type_of_key(key);
232     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_TEXT ||
233             value == NULL || strlen(value) >= RADIO_METADATA_TEXT_LEN_MAX) {
234         return -EINVAL;
235     }
236     return add_metadata((radio_metadata_buffer_t **)metadata, key, type, value, strlen(value) + 1);
237 }
238 
radio_metadata_add_raw(radio_metadata_t ** metadata,const radio_metadata_key_t key,const unsigned char * value,const size_t size)239 int radio_metadata_add_raw(radio_metadata_t **metadata,
240                            const radio_metadata_key_t key,
241                            const unsigned char *value,
242                            const size_t size)
243 {
244     radio_metadata_type_t type = radio_metadata_type_of_key(key);
245     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_RAW || value == NULL) {
246         return -EINVAL;
247     }
248     return add_metadata((radio_metadata_buffer_t **)metadata, key, type, value, size);
249 }
250 
radio_metadata_add_clock(radio_metadata_t ** metadata,const radio_metadata_key_t key,const radio_metadata_clock_t * clock)251 int radio_metadata_add_clock(radio_metadata_t **metadata,
252                              const radio_metadata_key_t key,
253                              const radio_metadata_clock_t *clock) {
254     radio_metadata_type_t type = radio_metadata_type_of_key(key);
255     if (metadata == NULL || *metadata == NULL || type != RADIO_METADATA_TYPE_CLOCK ||
256         clock == NULL || clock->timezone_offset_in_minutes < (-12 * 60) ||
257         clock->timezone_offset_in_minutes > (14 * 60)) {
258         return -EINVAL;
259     }
260     return add_metadata(
261         (radio_metadata_buffer_t **)metadata, key, type, clock, sizeof(radio_metadata_clock_t));
262 }
263 
radio_metadata_add_metadata(radio_metadata_t ** dst_metadata,radio_metadata_t * src_metadata)264 int radio_metadata_add_metadata(radio_metadata_t **dst_metadata,
265                            radio_metadata_t *src_metadata)
266 {
267     radio_metadata_buffer_t *src_metadata_buf = (radio_metadata_buffer_t *)src_metadata;
268     radio_metadata_buffer_t *dst_metadata_buf;
269     int status;
270     uint32_t index;
271 
272     if (dst_metadata == NULL || src_metadata == NULL) {
273         return -EINVAL;
274     }
275     if (*dst_metadata == NULL) {
276         status = radio_metadata_allocate(dst_metadata, src_metadata_buf->channel,
277                                 src_metadata_buf->sub_channel);
278         if (status != 0) {
279             return status;
280         }
281     }
282 
283     dst_metadata_buf = (radio_metadata_buffer_t *)*dst_metadata;
284     dst_metadata_buf->channel = src_metadata_buf->channel;
285     dst_metadata_buf->sub_channel = src_metadata_buf->sub_channel;
286 
287     for (index = 0; index < src_metadata_buf->count; index++) {
288         radio_metadata_key_t key;
289         radio_metadata_type_t type;
290         void *value;
291         size_t size;
292         status = radio_metadata_get_at_index(src_metadata, index, &key, &type, &value, &size);
293         if (status != 0)
294             continue;
295         status = add_metadata((radio_metadata_buffer_t **)dst_metadata, key, type, value, size);
296         if (status != 0)
297             break;
298     }
299     return status;
300 }
301 
radio_metadata_check(const radio_metadata_t * metadata)302 int radio_metadata_check(const radio_metadata_t *metadata)
303 {
304     radio_metadata_buffer_t *metadata_buf =
305             (radio_metadata_buffer_t *)metadata;
306     uint32_t count;
307     uint32_t min_entry_size_int;
308 
309     if (metadata_buf == NULL) {
310         return -EINVAL;
311     }
312 
313     if (metadata_buf->size_int > RADIO_METADATA_MAX_SIZE) {
314         return -EINVAL;
315     }
316 
317     /* sanity check on entry count versus buffer size */
318     min_entry_size_int = 1 + sizeof(radio_metadata_entry_t);
319     min_entry_size_int = (min_entry_size_int + sizeof(uint32_t) - 1) /
320                                 sizeof(uint32_t);
321     if ((metadata_buf->count * min_entry_size_int + metadata_buf->count + 1 +
322             (sizeof(radio_metadata_buffer_t) + sizeof(uint32_t) - 1) / sizeof(uint32_t)) >
323                     metadata_buf->size_int) {
324         return -EINVAL;
325     }
326 
327     /* sanity check on each entry */
328     for (count = 0; count < metadata_buf->count; count++) {
329         radio_metadata_entry_t *entry = get_entry_at_index(metadata_buf, count, true);
330         radio_metadata_entry_t *next_entry;
331         if (entry == NULL) {
332             return -EINVAL;
333         }
334         if (!is_valid_metadata_key(entry->key)) {
335             return -EINVAL;
336         }
337         if (entry->type != radio_metadata_type_of_key(entry->key)) {
338             return -EINVAL;
339         }
340 
341         /* do not request check because next entry can be the free slot */
342         next_entry = get_entry_at_index(metadata_buf, count + 1, false);
343         if ((char *)entry->data + entry->size > (char *)next_entry) {
344             return -EINVAL;
345         }
346     }
347 
348     return 0;
349 }
350 
radio_metadata_get_size(const radio_metadata_t * metadata)351 size_t radio_metadata_get_size(const radio_metadata_t *metadata)
352 {
353     radio_metadata_buffer_t *metadata_buf =
354             (radio_metadata_buffer_t *)metadata;
355 
356     if (metadata_buf == NULL) {
357         return 0;
358     }
359     return metadata_buf->size_int * sizeof(uint32_t);
360 }
361 
radio_metadata_get_count(const radio_metadata_t * metadata)362 int radio_metadata_get_count(const radio_metadata_t *metadata)
363 {
364     radio_metadata_buffer_t *metadata_buf =
365             (radio_metadata_buffer_t *)metadata;
366 
367     if (metadata_buf == NULL) {
368         return -EINVAL;
369     }
370     return (int)metadata_buf->count;
371 }
372 
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)373 int radio_metadata_get_at_index(const radio_metadata_t *metadata,
374                                 const uint32_t index,
375                                 radio_metadata_key_t *key,
376                                 radio_metadata_type_t *type,
377                                 void **value,
378                                 size_t *size)
379 {
380     radio_metadata_entry_t *entry;
381     radio_metadata_buffer_t *metadata_buf =
382             (radio_metadata_buffer_t *)metadata;
383 
384     if (metadata_buf == NULL || key == NULL || type == NULL ||
385             value == NULL || size == NULL) {
386         return -EINVAL;
387     }
388     if (index >= metadata_buf->count) {
389         return -EINVAL;
390     }
391 
392     entry = get_entry_at_index(metadata_buf, index, false);
393     *key = entry->key;
394     *type = entry->type;
395     *value = (void *)entry->data;
396     *size = (size_t)entry->size;
397 
398     return 0;
399 }
400 
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)401 int radio_metadata_get_from_key(const radio_metadata_t *metadata,
402                                 const radio_metadata_key_t key,
403                                 radio_metadata_type_t *type,
404                                 void **value,
405                                 size_t *size)
406 {
407     uint32_t count;
408     radio_metadata_entry_t *entry = NULL;
409     radio_metadata_buffer_t *metadata_buf =
410             (radio_metadata_buffer_t *)metadata;
411 
412     if (metadata_buf == NULL || type == NULL || value == NULL || size == NULL) {
413         return -EINVAL;
414     }
415     if (!is_valid_metadata_key(key)) {
416         return -EINVAL;
417     }
418 
419     for (count = 0; count < metadata_buf->count; entry = NULL, count++) {
420         entry = get_entry_at_index(metadata_buf, count, false);
421         if (entry->key == key) {
422             break;
423         }
424     }
425     if (entry == NULL) {
426         return -ENOENT;
427     }
428     *type = entry->type;
429     *value = (void *)entry->data;
430     *size = (size_t)entry->size;
431     return 0;
432 }
433 
radio_metadata_get_channel(radio_metadata_t * metadata,uint32_t * channel,uint32_t * sub_channel)434 int radio_metadata_get_channel(radio_metadata_t *metadata,
435                                uint32_t *channel,
436                                uint32_t *sub_channel)
437 {
438     radio_metadata_buffer_t *metadata_buf =
439             (radio_metadata_buffer_t *)metadata;
440 
441     if (metadata_buf == NULL || channel == NULL || sub_channel == NULL) {
442         return -EINVAL;
443     }
444     *channel = metadata_buf->channel;
445     *sub_channel = metadata_buf->sub_channel;
446     return 0;
447 }
448