-
Notifications
You must be signed in to change notification settings - Fork 265
Expand file tree
/
Copy pathgtp_field.c
More file actions
345 lines (321 loc) · 11.7 KB
/
gtp_field.c
File metadata and controls
345 lines (321 loc) · 11.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
#include <string.h>
#include "gtp_field.h"
#include "utils.h"
#include "os_print.h"
#include "shared_context.h" // strings
#include "mem.h" // app_mem_free
#include "mem_utils.h" // mem_buffer_cleanup
#include "list.h" // flist_push_back
enum {
BIT_VERSION = 0,
BIT_NAME,
BIT_PARAM_TYPE,
BIT_PARAM,
BIT_VISIBLE,
};
enum {
TAG_VERSION = 0x00,
TAG_NAME = 0x01,
PARAM_TYPE = 0x02,
PARAM = 0x03,
VISIBLE = 0x04,
CONSTRAINT = 0x05,
};
typedef union {
s_param_raw_context raw_ctx;
s_param_amount_context amount_ctx;
s_param_token_amount_context token_amount_ctx;
s_param_nft_context nft_ctx;
s_param_datetime_context datetime_ctx;
s_param_duration_context duration_ctx;
s_param_unit_context unit_ctx;
s_param_enum_context enum_ctx;
s_param_trusted_name_context trusted_name_ctx;
s_param_calldata_context calldata_ctx;
s_param_token_context token_ctx;
s_param_network_context network_ctx;
} u_param_context;
static bool handle_version(const s_tlv_data *data, s_field_ctx *context) {
if (data->length != sizeof(context->field->version)) {
return false;
}
context->field->version = data->value[0];
context->set_flags |= SET_BIT(BIT_VERSION);
return true;
}
static bool handle_name(const s_tlv_data *data, s_field_ctx *context) {
str_cpy_explicit_trunc((const char *) data->value,
data->length,
context->field->name,
sizeof(context->field->name));
context->set_flags |= SET_BIT(BIT_NAME);
return true;
}
static bool handle_param_type(const s_tlv_data *data, s_field_ctx *context) {
if (data->length != sizeof(context->field->param_type)) {
return false;
}
if (context->set_flags & SET_BIT(BIT_PARAM_TYPE)) {
PRINTF("Error: More than one PARAM_TYPE in a FIELD struct!\n");
return false;
}
context->field->param_type = data->value[0];
switch (context->field->param_type) {
case PARAM_TYPE_RAW:
case PARAM_TYPE_AMOUNT:
case PARAM_TYPE_TOKEN_AMOUNT:
case PARAM_TYPE_NFT:
case PARAM_TYPE_DATETIME:
case PARAM_TYPE_DURATION:
case PARAM_TYPE_UNIT:
case PARAM_TYPE_ENUM:
case PARAM_TYPE_TRUSTED_NAME:
case PARAM_TYPE_CALLDATA:
case PARAM_TYPE_TOKEN:
case PARAM_TYPE_NETWORK:
break;
default:
PRINTF("Error: Unsupported param type (%u)\n", context->field->param_type);
return false;
}
context->set_flags |= SET_BIT(BIT_PARAM_TYPE);
return true;
}
static bool handle_param_visible(const s_tlv_data *data, s_field_ctx *context) {
e_param_visibility visibility = PARAM_VISIBILITY_ALWAYS;
// Check length
if (data->length != sizeof(context->field->visibility)) {
return false;
}
// Check duplicates
if (context->set_flags & SET_BIT(BIT_VISIBLE)) {
PRINTF("Error: More than one VISIBLE in a FIELD struct!\n");
return false;
}
// Set visibility
visibility = data->value[0];
// Check visibility field validity
if (visibility >= PARAM_VISIBILITY_MAX) {
PRINTF("Error: Unsupported visibility (%u)\n", context->field->visibility);
return false;
}
// Set visibility
context->field->visibility = visibility;
context->set_flags |= SET_BIT(BIT_VISIBLE);
return true;
}
static bool handle_param_constraint(const s_tlv_data *data, s_field_ctx *context) {
// Check visibility presence
if (!(context->set_flags & SET_BIT(BIT_VISIBLE))) {
PRINTF("Error: No VISIBLE detected for the current FIELD struct!\n");
return false;
}
// Check visibility type
if (context->field->visibility == PARAM_VISIBILITY_ALWAYS) {
PRINTF("Error: CONSTRAINT present but VISIBLE is not MUST_BE or IF_NOT_IN!\n");
return false;
}
if (data->length == 0 || data->value == NULL) {
PRINTF("Error: Empty constraint value!\n");
return false;
}
// Allocate new constraint node
s_field_constraint *node = NULL;
if (mem_buffer_allocate((void **) &node, sizeof(s_field_constraint)) == false) {
PRINTF("Error: Failed to allocate memory for constraint node!\n");
return false;
}
node->size = data->length;
// Allocate value buffer
if (mem_buffer_allocate((void **) &node->value, data->length) == false) {
PRINTF("Error: Failed to allocate memory for constraint value!\n");
app_mem_free((void **) &node);
return false;
}
memcpy(node->value, data->value, data->length);
// Add to linked list
flist_push_back((s_flist_node **) &context->field->constraints, (s_flist_node *) node);
return true;
}
static bool handle_param(const s_tlv_data *data, s_field_ctx *context) {
f_tlv_data_handler handler;
u_param_context param_ctx = {0};
if (context->set_flags & SET_BIT(BIT_PARAM)) {
PRINTF("Error: More than one PARAM in a FIELD struct!\n");
return false;
}
if (!(context->set_flags & SET_BIT(BIT_PARAM_TYPE))) {
PRINTF("Error: Received PARAM without a previous PARAM_TYPE!\n");
return false;
}
switch (context->field->param_type) {
case PARAM_TYPE_RAW:
handler = (f_tlv_data_handler) &handle_param_raw_struct;
param_ctx.raw_ctx.param = &context->field->param_raw;
break;
case PARAM_TYPE_AMOUNT:
handler = (f_tlv_data_handler) &handle_param_amount_struct;
param_ctx.amount_ctx.param = &context->field->param_amount;
break;
case PARAM_TYPE_TOKEN_AMOUNT:
handler = (f_tlv_data_handler) &handle_param_token_amount_struct;
param_ctx.token_amount_ctx.param = &context->field->param_token_amount;
break;
case PARAM_TYPE_NFT:
handler = (f_tlv_data_handler) &handle_param_nft_struct;
param_ctx.nft_ctx.param = &context->field->param_nft;
break;
case PARAM_TYPE_DATETIME:
handler = (f_tlv_data_handler) &handle_param_datetime_struct;
param_ctx.datetime_ctx.param = &context->field->param_datetime;
break;
case PARAM_TYPE_DURATION:
handler = (f_tlv_data_handler) &handle_param_duration_struct;
param_ctx.duration_ctx.param = &context->field->param_duration;
break;
case PARAM_TYPE_UNIT:
handler = (f_tlv_data_handler) &handle_param_unit_struct;
param_ctx.unit_ctx.param = &context->field->param_unit;
break;
case PARAM_TYPE_ENUM:
handler = (f_tlv_data_handler) &handle_param_enum_struct;
param_ctx.enum_ctx.param = &context->field->param_enum;
break;
case PARAM_TYPE_TRUSTED_NAME:
handler = (f_tlv_data_handler) &handle_param_trusted_name_struct;
param_ctx.trusted_name_ctx.param = &context->field->param_trusted_name;
break;
case PARAM_TYPE_CALLDATA:
handler = (f_tlv_data_handler) &handle_param_calldata_struct;
param_ctx.calldata_ctx.param = &context->field->param_calldata;
break;
case PARAM_TYPE_TOKEN:
handler = (f_tlv_data_handler) &handle_param_token_struct;
param_ctx.token_ctx.param = &context->field->param_token;
break;
case PARAM_TYPE_NETWORK:
handler = (f_tlv_data_handler) &handle_param_network_struct;
param_ctx.network_ctx.param = &context->field->param_network;
break;
default:
return false;
}
context->set_flags |= SET_BIT(BIT_PARAM);
return tlv_parse(data->value, data->length, handler, ¶m_ctx);
}
bool handle_field_struct(const s_tlv_data *data, s_field_ctx *context) {
bool ret;
switch (data->tag) {
case TAG_VERSION:
ret = handle_version(data, context);
break;
case TAG_NAME:
ret = handle_name(data, context);
break;
case PARAM_TYPE:
ret = handle_param_type(data, context);
break;
case PARAM:
ret = handle_param(data, context);
break;
case VISIBLE:
ret = handle_param_visible(data, context);
break;
case CONSTRAINT:
ret = handle_param_constraint(data, context);
break;
default:
PRINTF(TLV_TAG_ERROR_MSG, data->tag);
ret = false;
}
return ret;
}
bool verify_field_struct(const s_field_ctx *context) {
uint8_t required_bits = 0;
// check if struct version was provided
required_bits |= SET_BIT(BIT_VERSION);
if ((context->set_flags & required_bits) != required_bits) {
PRINTF("Error: no struct version specified!\n");
return false;
}
// verify required fields
switch (context->field->version) {
case 1:
required_bits |= SET_BIT(BIT_NAME) | SET_BIT(BIT_PARAM_TYPE) | SET_BIT(BIT_PARAM);
break;
default:
PRINTF("Error: unsupported field struct version (%u)\n", context->field->version);
return false;
}
if ((context->set_flags & required_bits) != required_bits) {
PRINTF("Error: missing required field(s)\n");
return false;
}
// check optional visibility field
if (!(context->set_flags & SET_BIT(BIT_VISIBLE))) {
// set default visibility if not provided
context->field->visibility = PARAM_VISIBILITY_ALWAYS;
}
return true;
}
bool format_field(s_field *field) {
bool ret;
switch (field->param_type) {
case PARAM_TYPE_RAW:
ret = format_param_raw(field);
break;
case PARAM_TYPE_AMOUNT:
ret = format_param_amount(&field->param_amount, field->name);
break;
case PARAM_TYPE_TOKEN_AMOUNT:
ret = format_param_token_amount(&field->param_token_amount, field->name);
break;
case PARAM_TYPE_NFT:
ret = format_param_nft(&field->param_nft, field->name);
break;
case PARAM_TYPE_DATETIME:
ret = format_param_datetime(&field->param_datetime, field->name);
break;
case PARAM_TYPE_DURATION:
ret = format_param_duration(&field->param_duration, field->name);
break;
case PARAM_TYPE_UNIT:
ret = format_param_unit(&field->param_unit, field->name);
break;
case PARAM_TYPE_ENUM:
ret = format_param_enum(&field->param_enum, field->name);
break;
case PARAM_TYPE_TRUSTED_NAME:
ret = format_param_trusted_name(field);
break;
case PARAM_TYPE_CALLDATA:
ret = format_param_calldata(&field->param_calldata, field->name);
break;
case PARAM_TYPE_TOKEN:
ret = format_param_token(&field->param_token, field->name);
break;
case PARAM_TYPE_NETWORK:
ret = format_param_network(&field->param_network, field->name);
break;
default:
ret = false;
}
// Cleanup constraints after formatting (they are no longer needed)
// This is safe to call even if constraints are NULL
cleanup_field_constraints(field);
// so that EIP-712 error-handling does trigger
strings.tmp.tmp[0] = '\0';
return ret;
}
static void constraint_node_del(s_flist_node *node) {
if (node != NULL) {
s_field_constraint *constraint = (s_field_constraint *) node;
app_mem_free((void *) constraint->value);
app_mem_free((void *) constraint);
}
}
void cleanup_field_constraints(s_field *field) {
if (field != NULL && field->constraints != NULL) {
flist_clear((s_flist_node **) &field->constraints, constraint_node_del);
}
}