24bca93881acf701bfcd6b9f0f67bdf27502bd5f
[ric-plt/resource-status-manager.git] / RSM / 3rdparty / asn1codec / e2ap_engine / ber_decoder.c
1
2 /*-
3  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
4  * Redistribution and modifications are permitted subject to BSD license.
5  */
6 #include <asn_internal.h>
7
8 #undef  ADVANCE
9 #define ADVANCE(num_bytes)      do {                                    \
10                 size_t num = num_bytes;                                 \
11                 ptr = ((const char *)ptr) + num;                        \
12                 size -= num;                                            \
13                 consumed_myself += num;                                 \
14         } while(0)
15 #undef  RETURN
16 #define RETURN(_code)   do {                                            \
17                 asn_dec_rval_t rval;                                    \
18                 rval.code = _code;                                      \
19                 if(opt_ctx) opt_ctx->step = step; /* Save context */    \
20                 if(_code == RC_OK || opt_ctx)                           \
21                         rval.consumed = consumed_myself;                \
22                 else                                                    \
23                         rval.consumed = 0;      /* Context-free */      \
24                 return rval;                                            \
25         } while(0)
26
27 /*
28  * The BER decoder of any type.
29  */
30 asn_dec_rval_t
31 ber_decode(const asn_codec_ctx_t *opt_codec_ctx,
32            const asn_TYPE_descriptor_t *type_descriptor, void **struct_ptr,
33            const void *ptr, size_t size) {
34     asn_codec_ctx_t s_codec_ctx;
35
36         /*
37          * Stack checker requires that the codec context
38          * must be allocated on the stack.
39          */
40         if(opt_codec_ctx) {
41                 if(opt_codec_ctx->max_stack_size) {
42                         s_codec_ctx = *opt_codec_ctx;
43                         opt_codec_ctx = &s_codec_ctx;
44                 }
45         } else {
46                 /* If context is not given, be security-conscious anyway */
47                 memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
48                 s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX;
49                 opt_codec_ctx = &s_codec_ctx;
50         }
51
52         /*
53          * Invoke type-specific decoder.
54          */
55         return type_descriptor->op->ber_decoder(opt_codec_ctx, type_descriptor,
56                 struct_ptr,     /* Pointer to the destination structure */
57                 ptr, size,      /* Buffer and its size */
58                 0               /* Default tag mode is 0 */
59                 );
60 }
61
62 /*
63  * Check the set of <TL<TL<TL...>>> tags matches the definition.
64  */
65 asn_dec_rval_t
66 ber_check_tags(const asn_codec_ctx_t *opt_codec_ctx,
67                const asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx,
68                const void *ptr, size_t size, int tag_mode, int last_tag_form,
69                ber_tlv_len_t *last_length, int *opt_tlv_form) {
70     ssize_t consumed_myself = 0;
71         ssize_t tag_len;
72         ssize_t len_len;
73         ber_tlv_tag_t tlv_tag;
74         ber_tlv_len_t tlv_len;
75         ber_tlv_len_t limit_len = -1;
76         int expect_00_terminators = 0;
77         int tlv_constr = -1;    /* If CHOICE, opt_tlv_form is not given */
78         int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */
79         int tagno;
80
81         /*
82          * Make sure we didn't exceed the maximum stack size.
83          */
84         if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
85                 RETURN(RC_FAIL);
86
87         /*
88          * So what does all this implicit skip stuff mean?
89          * Imagine two types,
90          *      A ::= [5] IMPLICIT      T
91          *      B ::= [2] EXPLICIT      T
92          * Where T is defined as
93          *      T ::= [4] IMPLICIT SEQUENCE { ... }
94          * 
95          * Let's say, we are starting to decode type A, given the
96          * following TLV stream: <5> <0>. What does this mean?
97          * It means that the type A contains type T which is,
98          * in turn, empty.
99          * Remember though, that we are still in A. We cannot
100          * just pass control to the type T decoder. Why? Because
101          * the type T decoder expects <4> <0>, not <5> <0>.
102          * So, we must make sure we are going to receive <5> while
103          * still in A, then pass control to the T decoder, indicating
104          * that the tag <4> was implicitly skipped. The decoder of T
105          * hence will be prepared to treat <4> as valid tag, and decode
106          * it appropriately.
107          */
108
109         tagno = step    /* Continuing where left previously */
110                 + (tag_mode==1?-1:0)
111                 ;
112         ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)",
113                 td->name, (long)size, tag_mode, step, tagno);
114         /* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */
115
116         if(tag_mode == 0 && tagno == (int)td->tags_count) {
117                 /*
118                  * This must be the _untagged_ ANY type,
119                  * which outermost tag isn't known in advance.
120                  * Fetch the tag and length separately.
121                  */
122                 tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
123                 switch(tag_len) {
124                 case -1: RETURN(RC_FAIL);
125                 case 0: RETURN(RC_WMORE);
126                 }
127                 tlv_constr = BER_TLV_CONSTRUCTED(ptr);
128                 len_len = ber_fetch_length(tlv_constr,
129                         (const char *)ptr + tag_len, size - tag_len, &tlv_len);
130                 switch(len_len) {
131                 case -1: RETURN(RC_FAIL);
132                 case 0: RETURN(RC_WMORE);
133                 }
134                 ASN_DEBUG("Advancing %ld in ANY case",
135                         (long)(tag_len + len_len));
136                 ADVANCE(tag_len + len_len);
137         } else {
138                 assert(tagno < (int)td->tags_count);    /* At least one loop */
139         }
140         for((void)tagno; tagno < (int)td->tags_count; tagno++, step++) {
141
142                 /*
143                  * Fetch and process T from TLV.
144                  */
145                 tag_len = ber_fetch_tag(ptr, size, &tlv_tag);
146                         ASN_DEBUG("Fetching tag from {%p,%ld}: "
147                                 "len %ld, step %d, tagno %d got %s",
148                                 ptr, (long)size,
149                                 (long)tag_len, step, tagno,
150                                 ber_tlv_tag_string(tlv_tag));
151                 switch(tag_len) {
152                 case -1: RETURN(RC_FAIL);
153                 case 0: RETURN(RC_WMORE);
154                 }
155
156                 tlv_constr = BER_TLV_CONSTRUCTED(ptr);
157
158                 /*
159                  * If {I}, don't check anything.
160                  * If {I,B,C}, check B and C unless we're at I.
161                  */
162                 if(tag_mode != 0 && step == 0) {
163                         /*
164                          * We don't expect tag to match here.
165                          * It's just because we don't know how the tag
166                          * is supposed to look like.
167                          */
168                 } else {
169                     assert(tagno >= 0); /* Guaranteed by the code above */
170                     if(tlv_tag != td->tags[tagno]) {
171                         /*
172                          * Unexpected tag. Too bad.
173                          */
174                         ASN_DEBUG("Expected: %s, "
175                                 "expectation failed (tn=%d, tm=%d)",
176                                 ber_tlv_tag_string(td->tags[tagno]),
177                                 tagno, tag_mode
178                         );
179                         RETURN(RC_FAIL);
180                     }
181                 }
182
183                 /*
184                  * Attention: if there are more tags expected,
185                  * ensure that the current tag is presented
186                  * in constructed form (it contains other tags!).
187                  * If this one is the last one, check that the tag form
188                  * matches the one given in descriptor.
189                  */
190                 if(tagno < ((int)td->tags_count - 1)) {
191                         if(tlv_constr == 0) {
192                                 ASN_DEBUG("tlv_constr = %d, expfail",
193                                         tlv_constr);
194                                 RETURN(RC_FAIL);
195                         }
196                 } else {
197                         if(last_tag_form != tlv_constr
198                         && last_tag_form != -1) {
199                                 ASN_DEBUG("last_tag_form %d != %d",
200                                         last_tag_form, tlv_constr);
201                                 RETURN(RC_FAIL);
202                         }
203                 }
204
205                 /*
206                  * Fetch and process L from TLV.
207                  */
208                 len_len = ber_fetch_length(tlv_constr,
209                         (const char *)ptr + tag_len, size - tag_len, &tlv_len);
210                 ASN_DEBUG("Fetching len = %ld", (long)len_len);
211                 switch(len_len) {
212                 case -1: RETURN(RC_FAIL);
213                 case 0: RETURN(RC_WMORE);
214                 }
215
216                 /*
217                  * FIXME
218                  * As of today, the chain of tags
219                  * must either contain several indefinite length TLVs,
220                  * or several definite length ones.
221                  * No mixing is allowed.
222                  */
223                 if(tlv_len == -1) {
224                         /*
225                          * Indefinite length.
226                          */
227                         if(limit_len == -1) {
228                                 expect_00_terminators++;
229                         } else {
230                                 ASN_DEBUG("Unexpected indefinite length "
231                                         "in a chain of definite lengths");
232                                 RETURN(RC_FAIL);
233                         }
234                         ADVANCE(tag_len + len_len);
235                         continue;
236                 } else {
237                         if(expect_00_terminators) {
238                                 ASN_DEBUG("Unexpected definite length "
239                                         "in a chain of indefinite lengths");
240                                 RETURN(RC_FAIL);
241                         }
242                 }
243
244                 /*
245                  * Check that multiple TLVs specify ever decreasing length,
246                  * which is consistent.
247                  */
248                 if(limit_len == -1) {
249                         limit_len    = tlv_len + tag_len + len_len;
250                         if(limit_len < 0) {
251                                 /* Too great tlv_len value? */
252                                 RETURN(RC_FAIL);
253                         }
254                 } else if(limit_len != tlv_len + tag_len + len_len) {
255                         /*
256                          * Inner TLV specifies length which is inconsistent
257                          * with the outer TLV's length value.
258                          */
259                         ASN_DEBUG("Outer TLV is %ld and inner is %ld",
260                                 (long)limit_len, (long)tlv_len);
261                         RETURN(RC_FAIL);
262                 }
263
264                 ADVANCE(tag_len + len_len);
265
266                 limit_len -= (tag_len + len_len);
267                 if((ssize_t)size > limit_len) {
268                         /*
269                          * Make sure that we won't consume more bytes
270                          * from the parent frame than the inferred limit.
271                          */
272                         size = limit_len;
273                 }
274         }
275
276         if(opt_tlv_form)
277                 *opt_tlv_form = tlv_constr;
278         if(expect_00_terminators)
279                 *last_length = -expect_00_terminators;
280         else
281                 *last_length = tlv_len;
282
283         RETURN(RC_OK);
284 }