blob: 80c1edbddbd07521f44a9e88b3762103b0e4c0bf [file] [log] [blame]
julhal01734dbad2020-12-21 10:27:41 +00001/*
2 * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "tlv.h"
8#include <string.h>
9
10size_t tlv_required_space(size_t length)
11{
12 return TLV_HDR_LEN + length;
13}
14
15void tlv_iterator_begin(struct tlv_iterator *iter, uint8_t *buf, size_t bufsize)
16{
17 iter->pos = buf;
18 iter->limit = &buf[bufsize];
19
20 /* Defend against overflow */
21 if (iter->limit < buf) iter->limit = buf;
22
23 /* Used to enforce ascending tag order when encoding */
24 iter->prev_tag = 0;
25}
26
27void tlv_const_iterator_begin(struct tlv_const_iterator *iter, const uint8_t *buf, size_t bufsize)
28{
29 iter->pos = buf;
30 iter->limit = &buf[bufsize];
31
32 /* Defend against overflow */
33 if (iter->limit < buf) iter->limit = buf;
34}
35
36bool tlv_encode(struct tlv_iterator *iter, const struct tlv_record *input)
37{
38 bool success = false;
39 size_t required_space = tlv_required_space(input->length);
40 size_t available_space = iter->limit - iter->pos;
41
42 if (required_space <= available_space && input->tag >= iter->prev_tag) {
43
44 iter->pos[TLV_TAG_OFFSET + 0] = (uint8_t)(input->tag >> 8);
45 iter->pos[TLV_TAG_OFFSET + 1] = (uint8_t)(input->tag);
46 iter->pos[TLV_LENGTH_OFFSET + 0] = (uint8_t)(input->length >> 8);
47 iter->pos[TLV_LENGTH_OFFSET + 1] = (uint8_t)(input->length);
48
49 memcpy(&iter->pos[TLV_VALUE_OFFSET], input->value, input->length);
50
51 iter->pos += required_space;
52 iter->prev_tag = input->tag;
53 success = true;
54 }
55
56 return success;
57}
58
59bool tlv_decode(struct tlv_const_iterator *iter, struct tlv_record *output)
60{
61 bool success = false;
62 size_t max_space = iter->limit - iter->pos;
63
64 if (max_space >= TLV_HDR_LEN) {
65
66 size_t record_len;
67 output->tag = (iter->pos[TLV_TAG_OFFSET + 0] << 8) | iter->pos[TLV_TAG_OFFSET + 1];
68 output->length = (iter->pos[TLV_LENGTH_OFFSET + 0] << 8) | iter->pos[TLV_LENGTH_OFFSET + 1];
69 output->value = &iter->pos[TLV_VALUE_OFFSET];
70
71 record_len = output->length + TLV_HDR_LEN;
72
73 if (record_len <= max_space) {
74
75 iter->pos += record_len;
76 success = true;
77 }
78 }
79
80 return success;
81}
82
83bool tlv_find_decode(struct tlv_const_iterator *iter, uint16_t tag, struct tlv_record *output)
84{
julhal013ec4c322021-02-05 17:30:49 +000085 struct tlv_const_iterator temp_iter = *iter;
86
87 while (tlv_decode(&temp_iter, output)) {
julhal01734dbad2020-12-21 10:27:41 +000088
89 if (output->tag == tag) {
julhal013ec4c322021-02-05 17:30:49 +000090 /* Found a record - update input iterator to next record */
91 *iter = temp_iter;
julhal01734dbad2020-12-21 10:27:41 +000092 return true;
93 }
94 else if (output->tag > tag) {
95 /* Iterated beyond the expected parameter */
96 return false;
97 }
98 }
99
100 /* Reached the end of the buffer without finding a record with the requested tag */
101 return false;
102}