2
* Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3
* Redistribution and modifications are permitted subject to BSD license.
5
#include <asn_internal.h>
8
#define ADVANCE(num_bytes) do { \
9
size_t num = num_bytes; \
10
ptr = ((const char *)ptr) + num; \
12
consumed_myself += num; \
15
#define RETURN(_code) do { \
16
asn_dec_rval_t rval; \
18
if(opt_ctx) opt_ctx->step = step; /* Save context */ \
19
if(_code == RC_OK || opt_ctx) \
20
rval.consumed = consumed_myself; \
22
rval.consumed = 0; /* Context-free */ \
27
* The BER decoder of any type.
30
ber_decode(asn_codec_ctx_t *opt_codec_ctx,
31
asn_TYPE_descriptor_t *type_descriptor,
32
void **struct_ptr, const void *ptr, size_t size) {
33
asn_codec_ctx_t s_codec_ctx;
36
* Satisfy the requirement that the codec context
37
* must be allocated on the stack.
39
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
40
s_codec_ctx = *opt_codec_ctx;
41
opt_codec_ctx = &s_codec_ctx;
45
* Invoke type-specific decoder.
47
return type_descriptor->ber_decoder(opt_codec_ctx, type_descriptor,
48
struct_ptr, /* Pointer to the destination structure */
49
ptr, size, /* Buffer and its size */
50
0 /* Default tag mode is 0 */
55
* Check the set of <TL<TL<TL...>>> tags matches the definition.
58
ber_check_tags(asn_codec_ctx_t *opt_codec_ctx,
59
asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx,
60
const void *ptr, size_t size, int tag_mode, int last_tag_form,
61
ber_tlv_len_t *last_length, int *opt_tlv_form) {
62
ssize_t consumed_myself = 0;
65
ber_tlv_tag_t tlv_tag;
66
ber_tlv_len_t tlv_len;
67
ber_tlv_len_t limit_len = -1;
68
int expect_00_terminators = 0;
69
int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */
70
int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */
74
* Make sure we didn't exceed the maximum stack size.
76
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) {
77
ptrdiff_t usedstack = ((char *)opt_codec_ctx - (char *)&size);
78
/* double negative is required to avoid int wrap-around */
79
if(usedstack > 0) usedstack = -usedstack;
80
ASN_DEBUG("Current stack size %ld", -(long)usedstack);
81
if(usedstack < -(ptrdiff_t)opt_codec_ctx->max_stack_size) {
82
ASN_DEBUG("Stack limit %ld reached",
83
(long)opt_codec_ctx->max_stack_size);
89
* So what does all this implicit skip stuff mean?
91
* A ::= [5] IMPLICIT T
92
* B ::= [2] EXPLICIT T
93
* Where T is defined as
94
* T ::= [4] IMPLICIT SEQUENCE { ... }
96
* Let's say, we are starting to decode type A, given the
97
* following TLV stream: <5> <0>. What does this mean?
98
* It means that the type A contains type T which is,
100
* Remember though, that we are still in A. We cannot
101
* just pass control to the type T decoder. Why? Because
102
* the type T decoder expects <4> <0>, not <5> <0>.
103
* So, we must make sure we are going to receive <5> while
104
* still in A, then pass control to the T decoder, indicating
105
* that the tag <4> was implicitly skipped. The decoder of T
106
* hence will be prepared to treat <4> as valid tag, and decode
110
tagno = step /* Continuing where left previously */
113
ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)",
114
td->name, (long)size, tag_mode, step, tagno);
115
/* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */
117
if(tag_mode == 0 && tagno == td->tags_count) {
119
* This must be the _untagged_ ANY type,
120
* which outermost tag isn't known in advance.
121
* Fetch the tag and length separately.
123
tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
125
case -1: RETURN(RC_FAIL);
126
case 0: RETURN(RC_WMORE);
128
tlv_constr = BER_TLV_CONSTRUCTED(ptr);
129
len_len = ber_fetch_length(tlv_constr,
130
(const char *)ptr + tag_len, size - tag_len, &tlv_len);
132
case -1: RETURN(RC_FAIL);
133
case 0: RETURN(RC_WMORE);
135
ASN_DEBUG("Advancing %ld in ANY case",
136
(long)(tag_len + len_len));
137
ADVANCE(tag_len + len_len);
139
assert(tagno < td->tags_count); /* At least one loop */
141
for((void)tagno; tagno < td->tags_count; tagno++, step++) {
144
* Fetch and process T from TLV.
146
tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
147
ASN_DEBUG("Fetching tag from {%p,%ld}: "
148
"len %ld, step %d, tagno %d got %s",
150
(long)tag_len, step, tagno,
151
ber_tlv_tag_string(tlv_tag));
153
case -1: RETURN(RC_FAIL);
154
case 0: RETURN(RC_WMORE);
157
tlv_constr = BER_TLV_CONSTRUCTED(ptr);
160
* If {I}, don't check anything.
161
* If {I,B,C}, check B and C unless we're at I.
163
if(tag_mode != 0 && step == 0) {
165
* We don't expect tag to match here.
166
* It's just because we don't know how the tag
167
* is supposed to look like.
170
assert(tagno >= 0); /* Guaranteed by the code above */
171
if(tlv_tag != td->tags[tagno]) {
173
* Unexpected tag. Too bad.
175
ASN_DEBUG("Expected: %s, "
176
"expectation failed (tn=%d, tm=%d)",
177
ber_tlv_tag_string(td->tags[tagno]),
185
* Attention: if there are more tags expected,
186
* ensure that the current tag is presented
187
* in constructed form (it contains other tags!).
188
* If this one is the last one, check that the tag form
189
* matches the one given in descriptor.
191
if(tagno < (td->tags_count - 1)) {
192
if(tlv_constr == 0) {
193
ASN_DEBUG("tlv_constr = %d, expfail",
198
if(last_tag_form != tlv_constr
199
&& last_tag_form != -1) {
200
ASN_DEBUG("last_tag_form %d != %d",
201
last_tag_form, tlv_constr);
207
* Fetch and process L from TLV.
209
len_len = ber_fetch_length(tlv_constr,
210
(const char *)ptr + tag_len, size - tag_len, &tlv_len);
211
ASN_DEBUG("Fetchinig len = %ld", (long)len_len);
213
case -1: RETURN(RC_FAIL);
214
case 0: RETURN(RC_WMORE);
219
* As of today, the chain of tags
220
* must either contain several indefinite length TLVs,
221
* or several definite length ones.
222
* No mixing is allowed.
228
if(limit_len == -1) {
229
expect_00_terminators++;
231
ASN_DEBUG("Unexpected indefinite length "
232
"in a chain of definite lengths");
235
ADVANCE(tag_len + len_len);
238
if(expect_00_terminators) {
239
ASN_DEBUG("Unexpected definite length "
240
"in a chain of indefinite lengths");
246
* Check that multiple TLVs specify ever decreasing length,
247
* which is consistent.
249
if(limit_len == -1) {
250
limit_len = tlv_len + tag_len + len_len;
252
/* Too great tlv_len value? */
255
} else if(limit_len != tlv_len + tag_len + len_len) {
257
* Inner TLV specifies length which is inconsistent
258
* with the outer TLV's length value.
260
ASN_DEBUG("Outer TLV is %ld and inner is %ld",
261
(long)limit_len, (long)tlv_len);
265
ADVANCE(tag_len + len_len);
267
limit_len -= (tag_len + len_len);
268
if((ssize_t)size > limit_len) {
270
* Make sure that we won't consume more bytes
271
* from the parent frame than the inferred limit.
278
*opt_tlv_form = tlv_constr;
279
if(expect_00_terminators)
280
*last_length = -expect_00_terminators;
282
*last_length = tlv_len;