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