]> git.stg.codes - stg.git/blob - libs/smux/constr_SEQUENCE_oer.c
Use async-radius.
[stg.git] / libs / smux / constr_SEQUENCE_oer.c
1 /*
2  * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3  * All rights reserved.
4  * Redistribution and modifications are permitted subject to BSD license.
5  */
6 #ifndef ASN_DISABLE_OER_SUPPORT
7
8 #include <asn_internal.h>
9 #include <constr_SEQUENCE.h>
10 #include <OPEN_TYPE.h>
11 #include <errno.h>
12
13 /*
14  * This macro "eats" the part of the buffer which is definitely "consumed",
15  * i.e. was correctly converted into local representation or rightfully skipped.
16  */
17 #undef  ADVANCE
18 #define ADVANCE(num_bytes)                   \
19     do {                                     \
20         size_t num = num_bytes;              \
21         ptr = ((const char *)ptr) + num;     \
22         size -= num;                         \
23         consumed_myself += num;              \
24     } while(0)
25
26 /*
27  * Switch to the next phase of parsing.
28  */
29 #undef  NEXT_PHASE
30 #undef PHASE_OUT
31 #define NEXT_PHASE(ctx) \
32     do {                \
33         ctx->phase++;   \
34         ctx->step = 0;  \
35     } while(0)
36
37 /*
38  * Check whether we are inside the extensions group.
39  */
40 #define IN_EXTENSION_GROUP(specs, memb_idx) \
41     ((specs)->first_extension >= 0          \
42      && (unsigned)(specs)->first_extension <= (memb_idx))
43
44 #define IN_ROOT_GROUP_PRED(edx)                            \
45     edx < (specs->first_extension < 0 ? td->elements_count \
46                                       : (size_t)specs->first_extension)
47
48 #define FOR_IN_ROOT_GROUP(edx) for(edx = 0; IN_ROOT_GROUP_PRED(edx); edx++)
49
50 /*
51  * Return a standardized complex structure.
52  */
53 #undef  RETURN
54 #define RETURN(_code)   do {                    \
55                 rval.code = _code;              \
56                 rval.consumed = consumed_myself;\
57                 return rval;                    \
58         } while(0)
59
60 /*
61  * Return pointer to a member.
62  */
63 static void **
64 element_ptrptr(void *struct_ptr, asn_TYPE_member_t *elm, void **tmp_save_ptr) {
65     if(elm->flags & ATF_POINTER) {
66         /* Member is a pointer to another structure */
67         return (void **)((char *)struct_ptr + elm->memb_offset);
68     } else {
69         assert(tmp_save_ptr);
70         *tmp_save_ptr = (void *)((char *)struct_ptr + elm->memb_offset);
71         return tmp_save_ptr;
72     }
73 }
74
75 static const void *
76 element_ptr(const void *struct_ptr, const asn_TYPE_member_t *elm) {
77     if(elm->flags & ATF_POINTER) {
78         /* Member is a pointer to another structure */
79         return *(const void *const *)((const char *)struct_ptr
80                                       + elm->memb_offset);
81     } else {
82         return (const void *)((const char *)struct_ptr + elm->memb_offset);
83     }
84 }
85
86 asn_dec_rval_t
87 SEQUENCE_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
88                     const asn_TYPE_descriptor_t *td,
89                     const asn_oer_constraints_t *constraints, void **struct_ptr,
90                     const void *ptr, size_t size) {
91     const asn_SEQUENCE_specifics_t *specs =
92         (const asn_SEQUENCE_specifics_t *)td->specifics;
93     asn_dec_rval_t rval = {RC_OK, 0};
94     void *st = *struct_ptr; /* Target structure */
95     asn_struct_ctx_t *ctx; /* Decoder context */
96     size_t consumed_myself = 0; /* Consumed bytes from ptr. */
97
98     (void)constraints;
99
100     if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
101         ASN__DECODE_FAILED;
102
103     /*
104      * Create the target structure if it is not present already.
105      */
106     if(st == 0) {
107         st = *struct_ptr = CALLOC(1, specs->struct_size);
108         if(st == 0) {
109             RETURN(RC_FAIL);
110         }
111     }
112
113     /*
114      * Restore parsing context.
115      */
116     ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
117
118     /*
119      * Start to parse where left previously.
120      */
121     switch(ctx->phase) {
122     case 0: {
123         /*
124          * Fetch preamble.
125          */
126         asn_bit_data_t *preamble;
127         int has_extensions_bit = (specs->first_extension >= 0);
128         size_t preamble_bits = (has_extensions_bit + specs->roms_count);
129         size_t preamble_bytes = ((7 + preamble_bits) >> 3);
130
131         ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 0", td->name);
132
133         ASN_DEBUG(
134             "Expecting preamble bits %" ASN_PRI_SIZE " for %s (including %d extension bits)",
135             preamble_bits, td->name, has_extensions_bit);
136
137         if(preamble_bytes > size) {
138             ASN__DECODE_STARVED;
139         }
140
141         preamble = asn_bit_data_new_contiguous(ptr, preamble_bits);
142         if(!preamble) {
143             RETURN(RC_FAIL);
144         }
145         preamble->nboff = has_extensions_bit;
146         ctx->ptr = preamble;
147         ADVANCE(preamble_bytes);
148     }
149         NEXT_PHASE(ctx);
150         /* FALL THROUGH */
151     case 1: {
152         /* Decode components of the extension root */
153         asn_bit_data_t *preamble = ctx->ptr;
154         size_t edx;
155
156         ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 1 (Root)", td->name);
157
158         assert(preamble);
159
160         for(edx = (ctx->step >> 1); IN_ROOT_GROUP_PRED(edx);
161             edx++, ctx->step = (ctx->step & ~1) + 2) {
162             asn_TYPE_member_t *elm = &td->elements[edx];
163
164             ASN_DEBUG("Decoding %s->%s", td->name, elm->name);
165
166             assert(!IN_EXTENSION_GROUP(specs, edx));
167
168             if(ctx->step & 1) {
169                 goto microphase2_decode_continues;
170             }
171
172
173             if(elm->optional) {
174                 int32_t present = asn_get_few_bits(preamble, 1);
175                 if(present < 0) {
176                     ASN_DEBUG("Presence map ended prematurely: %d", present);
177                     RETURN(RC_FAIL);
178                 } else if(present == 0) {
179                     if(elm->default_value_set) {
180                         /* Fill-in DEFAULT */
181                         void *tmp;
182                         if(elm->default_value_set(
183                                element_ptrptr(st, elm, &tmp))) {
184                             RETURN(RC_FAIL);
185                         }
186                     }
187                     /* The member is not present. */
188                     continue;
189                 }
190                 /* Present OPTIONAL or DEFAULT component. */
191             }
192
193             /*
194              * MICROPHASE 2: Invoke the member-specific decoder.
195              */
196             ctx->step |= 1; /* Confirm entering next microphase */
197         microphase2_decode_continues:
198             if(elm->flags & ATF_OPEN_TYPE) {
199                 rval = OPEN_TYPE_oer_get(opt_codec_ctx, td, st, elm, ptr, size);
200             } else {
201                 void *save_memb_ptr; /* Temporary reference. */
202                 void **memb_ptr2;  /* Pointer to a pointer to a memmber */
203
204                 memb_ptr2 = element_ptrptr(st, elm, &save_memb_ptr);
205
206                 rval = elm->type->op->oer_decoder(
207                     opt_codec_ctx, elm->type,
208                     elm->encoding_constraints.oer_constraints, memb_ptr2, ptr,
209                     size);
210             }
211             switch(rval.code) {
212             case RC_OK:
213                 ADVANCE(rval.consumed);
214                 break;
215             case RC_WMORE:
216                 ASN_DEBUG("More bytes needed at element %s \"%s\"", td->name,
217                           elm->name);
218                 ADVANCE(rval.consumed);
219                 RETURN(RC_WMORE);
220             case RC_FAIL:
221                 ASN_DEBUG("Decoding failed at element %s \"%s\"", td->name,
222                           elm->name);
223                 RETURN(RC_FAIL);
224             }
225         } /* for(all root members) */
226
227     }
228         NEXT_PHASE(ctx);
229         /* FALL THROUGH */
230     case 2:
231         assert(ctx->ptr);
232         {
233         /* Cleanup preamble. */
234         asn_bit_data_t *preamble = ctx->ptr;
235         asn_bit_data_t *extadds;
236         int has_extensions_bit = (specs->first_extension >= 0);
237         int extensions_present =
238             has_extensions_bit
239             && (preamble->buffer == NULL
240                 || (((const uint8_t *)preamble->buffer)[0] & 0x80));
241         uint8_t unused_bits;
242         size_t len = 0;
243         ssize_t len_len;
244
245         ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 2", td->name);
246
247         preamble->buffer = 0; /* Will do extensions_present==1 next time. */
248
249         if(!extensions_present) {
250             ctx->phase = 10;
251             RETURN(RC_OK);
252         }
253
254         /*
255          * X.696 (08/2015) #16.1 (c), #16.4
256          * Read in the extension addition presence bitmap.
257          */
258
259         len_len = oer_fetch_length(ptr, size, &len);
260         if(len_len > 0) {
261             ADVANCE(len_len);
262         } else if(len_len < 0) {
263             RETURN(RC_FAIL);
264         } else {
265             RETURN(RC_WMORE);
266         }
267
268         if(len == 0) {
269             /* 16.4.1-2 */
270             RETURN(RC_FAIL);
271         } else if(len > size) {
272             RETURN(RC_WMORE);
273         }
274
275         /* Account for unused bits */
276         unused_bits = 0x7 & *(const uint8_t *)ptr;
277         ADVANCE(1);
278         len--;
279         if(unused_bits && len == 0) {
280             RETURN(RC_FAIL);
281         }
282
283         /* Get the extensions map */
284         extadds = asn_bit_data_new_contiguous(ptr, len * 8 - unused_bits);
285         if(!extadds) {
286             RETURN(RC_FAIL);
287         }
288         FREEMEM(preamble);
289         ctx->ptr = extadds;
290         ADVANCE(len);
291     }
292         NEXT_PHASE(ctx);
293         ctx->step =
294             (specs->first_extension < 0 ? td->elements_count
295                                         : (size_t)specs->first_extension);
296         /* Fall through */
297     case 3:
298         ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 3 (Extensions)", td->name);
299         for(; ctx->step < (signed)td->elements_count; ctx->step++) {
300             asn_bit_data_t *extadds = ctx->ptr;
301             size_t edx = ctx->step;
302             asn_TYPE_member_t *elm = &td->elements[edx];
303             void *tmp_memb_ptr;
304             void **memb_ptr2 = element_ptrptr(st, elm, &tmp_memb_ptr);
305
306             switch(asn_get_few_bits(extadds, 1)) {
307             case -1:
308                 /*
309                  * Not every one of our extensions is known to the remote side.
310                  * Continue filling in their defaults though.
311                  */
312                 /* Fall through */
313             case 0:
314                 /* Fill-in DEFAULT */
315                 if(elm->default_value_set
316                    && elm->default_value_set(memb_ptr2)) {
317                     RETURN(RC_FAIL);
318                 }
319                 continue;
320             case 1: {
321                 /* Read OER open type */
322                 ssize_t ot_size =
323                     oer_open_type_get(opt_codec_ctx, elm->type,
324                                       elm->encoding_constraints.oer_constraints,
325                                       memb_ptr2, ptr, size);
326                 assert(ot_size <= (ssize_t)size);
327                 if(ot_size > 0) {
328                     ADVANCE(ot_size);
329                 } else if(ot_size < 0) {
330                     RETURN(RC_FAIL);
331                 } else {
332                     /* Roll back open type parsing */
333                     asn_get_undo(extadds, 1);
334                     RETURN(RC_WMORE);
335                 }
336                 break;
337             }
338             default:
339                 RETURN(RC_FAIL);
340             }
341         }
342
343         NEXT_PHASE(ctx);
344         /* Fall through */
345     case 4:
346         ASN_DEBUG("OER SEQUENCE %s Decoding PHASE 4", td->name);
347         /* Read in the rest of Open Types while ignoring them */
348         for(;;) {
349             asn_bit_data_t *extadds = ctx->ptr;
350             switch(asn_get_few_bits(extadds, 1)) {
351             case 0:
352                 continue;
353             case 1: {
354                 ssize_t skipped = oer_open_type_skip(ptr, size);
355                 if(skipped > 0) {
356                     ADVANCE(skipped);
357                 } else if(skipped < 0) {
358                     RETURN(RC_FAIL);
359                 } else {
360                     asn_get_undo(extadds, 1);
361                     RETURN(RC_WMORE);
362                 }
363                 continue;
364             }
365             case -1:
366                 /* No more Open Type encoded components */
367                 break;
368             default:
369                 RETURN(RC_FAIL);
370             }
371             break;
372         }
373     }
374
375     RETURN(RC_OK);
376 }
377
378 /*
379  * Encode as Canonical OER.
380  */
381 asn_enc_rval_t
382 SEQUENCE_encode_oer(const asn_TYPE_descriptor_t *td,
383                     const asn_oer_constraints_t *constraints, const void *sptr,
384                     asn_app_consume_bytes_f *cb, void *app_key) {
385     const asn_SEQUENCE_specifics_t *specs = (const asn_SEQUENCE_specifics_t *)td->specifics;
386     size_t computed_size = 0;
387     int has_extensions_bit = (specs->first_extension >= 0);
388     size_t preamble_bits = (has_extensions_bit + specs->roms_count);
389     uint32_t has_extensions = 0;
390     size_t edx;
391     int ret;
392
393     (void)constraints;
394
395     if(preamble_bits) {
396         asn_bit_outp_t preamble;
397
398         memset(&preamble, 0, sizeof(preamble));
399         preamble.output = cb;
400         preamble.op_key = app_key;
401
402         if(has_extensions_bit) {
403             for(edx = specs->first_extension; edx < td->elements_count; edx++) {
404                 asn_TYPE_member_t *elm = &td->elements[edx];
405                 const void *memb_ptr = element_ptr(sptr, elm);
406                 if(memb_ptr) {
407                     if(elm->default_value_cmp
408                        && elm->default_value_cmp(memb_ptr) == 0) {
409                         /* Do not encode default values in extensions */
410                     } else {
411                         has_extensions = 1;
412                         break;
413                     }
414                 }
415             }
416             ret = asn_put_few_bits(&preamble, has_extensions, 1);
417             assert(ret == 0);
418             if(ret < 0) {
419                 ASN__ENCODE_FAILED;
420             }
421         }
422
423         /*
424          * Encode optional components bitmap.
425          */
426         if(specs->roms_count) {
427             FOR_IN_ROOT_GROUP(edx) {
428                 asn_TYPE_member_t *elm = &td->elements[edx];
429
430                 if(IN_EXTENSION_GROUP(specs, edx)) break;
431
432                 if(elm->optional) {
433                     const void *memb_ptr = element_ptr(sptr, elm);
434                     uint32_t has_component = memb_ptr != NULL;
435                     if(has_component && elm->default_value_cmp
436                        && elm->default_value_cmp(memb_ptr) == 0) {
437                         has_component = 0;
438                     }
439                     ret = asn_put_few_bits(&preamble, has_component, 1);
440                     if(ret < 0) {
441                         ASN__ENCODE_FAILED;
442                     }
443                 }
444             }
445         }
446
447         asn_put_aligned_flush(&preamble);
448         computed_size += preamble.flushed_bytes;
449     }   /* if(preamble_bits) */
450
451     /*
452      * Put root components and extensions root.
453      */
454     for(edx = 0; edx < td->elements_count; edx++) {
455         asn_TYPE_member_t *elm = &td->elements[edx];
456         asn_enc_rval_t er;
457         const void *memb_ptr;
458
459         if(IN_EXTENSION_GROUP(specs, edx)) break;
460
461         memb_ptr = element_ptr(sptr, elm);
462         if(memb_ptr) {
463             if(elm->default_value_cmp
464                && elm->default_value_cmp(memb_ptr) == 0) {
465                 /* Skip default values in encoding */
466                 continue;
467             }
468         } else {
469             if(elm->optional) continue;
470             /* Mandatory element is missing */
471             ASN__ENCODE_FAILED;
472         }
473         if(!elm->type->op->oer_encoder) {
474             ASN_DEBUG("OER encoder is not defined for type %s", elm->type->name);
475             ASN__ENCODE_FAILED;
476         }
477         er = elm->type->op->oer_encoder(
478             elm->type, elm->encoding_constraints.oer_constraints, memb_ptr, cb,
479             app_key);
480         if(er.encoded == -1) {
481             ASN_DEBUG("... while encoding %s member \"%s\"\n", td->name,
482                       elm->name);
483             return er;
484         }
485         computed_size += er.encoded;
486     }
487
488     /*
489      * Before encode extensions, encode extensions additions presense bitmap
490      # X.696 (08/2015) #16.4.
491      */
492     if(has_extensions) {
493         asn_bit_outp_t extadds;
494
495         /* Special case allowing us to use exactly one byte for #8.6 */
496         size_t aoms_length_bits = specs->aoms_count;
497         size_t aoms_length_bytes = (7 + aoms_length_bits) >> 3;
498         uint8_t unused_bits = 0x07 & (8 - (aoms_length_bits & 0x07));
499
500         assert(1 + aoms_length_bytes <= 127);
501
502         memset(&extadds, 0, sizeof(extadds));
503         extadds.output = cb;
504         extadds.op_key = app_key;
505
506         /* #8.6 length determinant */
507         ret = asn_put_few_bits(&extadds, (1 + aoms_length_bytes), 8);
508         if(ret < 0) ASN__ENCODE_FAILED;
509
510         /* Number of unused bytes, #16.4.2 */
511         ret = asn_put_few_bits(&extadds, unused_bits, 8);
512         if(ret < 0) ASN__ENCODE_FAILED;
513
514         /* Encode presence bitmap #16.4.3 */
515         for(edx = specs->first_extension; edx < td->elements_count; edx++) {
516             asn_TYPE_member_t *elm = &td->elements[edx];
517             const void *memb_ptr = element_ptr(sptr, elm);
518             if(memb_ptr && elm->default_value_cmp
519                && elm->default_value_cmp(memb_ptr) == 0) {
520                 memb_ptr = 0;   /* Do not encode default value. */
521             }
522             ret |= asn_put_few_bits(&extadds, memb_ptr ? 1 : 0, 1);
523         }
524         if(ret < 0) ASN__ENCODE_FAILED;
525
526         asn_put_aligned_flush(&extadds);
527         computed_size += extadds.flushed_bytes;
528
529         /* Now, encode extensions */
530         for(edx = specs->first_extension; edx < td->elements_count; edx++) {
531             asn_TYPE_member_t *elm = &td->elements[edx];
532             const void *memb_ptr = element_ptr(sptr, elm);
533
534             if(memb_ptr) {
535                 if(elm->default_value_cmp
536                    && elm->default_value_cmp(memb_ptr) == 0) {
537                     /* Do not encode default value. */
538                 } else {
539                     ssize_t wrote = oer_open_type_put(
540                         elm->type, elm->encoding_constraints.oer_constraints,
541                         memb_ptr, cb, app_key);
542                     if(wrote == -1) {
543                         ASN__ENCODE_FAILED;
544                     }
545                     computed_size += wrote;
546                 }
547             } else if(!elm->optional) {
548                 ASN__ENCODE_FAILED;
549             }
550         }
551     }   /* if(has_extensions) */
552
553
554     {
555         asn_enc_rval_t er = {0, 0, 0};
556         er.encoded = computed_size;
557         ASN__ENCODED_OK(er);
558     }
559 }
560
561 #endif  /* ASN_DISABLE_OER_SUPPORT */