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