added stack control to PER

git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@1022 59561ff5-6e30-0410-9f3c-9617f08c8826
This commit is contained in:
vlm 2005-12-07 05:46:03 +00:00
parent 68a24641e4
commit 4d2ca1270e
16 changed files with 180 additions and 91 deletions

View File

@ -19,6 +19,7 @@
#include <errno.h> /* for errno */ #include <errno.h> /* for errno */
#include <asn_application.h> #include <asn_application.h>
#include <asn_internal.h> /* for _ASN_DEFAULT_STACK_MAX */
extern asn_TYPE_descriptor_t asn_DEF; /* ASN.1 type to be decoded */ extern asn_TYPE_descriptor_t asn_DEF; /* ASN.1 type to be decoded */
#ifdef ASN_PDU_COLLECTION /* Generated by asn1c: -pdu=... */ #ifdef ASN_PDU_COLLECTION /* Generated by asn1c: -pdu=... */
@ -51,11 +52,17 @@ static enum output_format {
OUT_NULL /* -onull: No pretty-printing */ OUT_NULL /* -onull: No pretty-printing */
} oform; /* -o<format> */ } oform; /* -o<format> */
#define DEBUG(fmt, args...) do { \ /* Debug output function */
if(!opt_debug) break; \ static inline void
fprintf(stderr, fmt, ##args); \ DEBUG(const char *fmt, ...) {
fprintf(stderr, "\n"); \ va_list ap;
} while(0) if(!opt_debug) return;
fprintf(stderr, "AD: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
int int
main(int ac, char **av) { main(int ac, char **av) {
@ -131,9 +138,9 @@ main(int ac, char **av) {
break; break;
case 's': case 's':
opt_stack = atoi(optarg); opt_stack = atoi(optarg);
if(opt_stack <= 0) { if(opt_stack < 0) {
fprintf(stderr, fprintf(stderr,
"-s %s: Value greater than 0 expected\n", "-s %s: Non-negative value expected\n",
optarg); optarg);
exit(EX_UNAVAILABLE); exit(EX_UNAVAILABLE);
} }
@ -164,8 +171,8 @@ main(int ac, char **av) {
" -c Check ASN.1 constraints after decoding\n" " -c Check ASN.1 constraints after decoding\n"
" -d Enable debugging (-dd is even better)\n" " -d Enable debugging (-dd is even better)\n"
" -n <num> Process files <num> times\n" " -n <num> Process files <num> times\n"
" -s <size> Set the stack usage limit\n" " -s <size> Set the stack usage limit (default is %d)\n"
, (long)suggested_bufsize); , (long)suggested_bufsize, _ASN_DEFAULT_STACK_MAX);
exit(EX_USAGE); exit(EX_USAGE);
} }
@ -250,11 +257,12 @@ static int write_out(const void *buffer, size_t size, void *key) {
return (fwrite(buffer, 1, size, fp) == size) ? 0 : -1; return (fwrite(buffer, 1, size, fp) == size) ? 0 : -1;
} }
static char *buffer; static char *buffer;
static size_t buf_offset; /* Offset from the start */
static size_t buf_len; /* Length of meaningful contents */ static size_t buf_len; /* Length of meaningful contents */
static size_t buf_size; /* Allocated memory */ static size_t buf_size; /* Allocated memory */
static off_t buf_shifted; /* Number of bytes ever shifted */ static size_t buf_offset; /* Offset from the start */
static off_t buf_shifted; /* Number of bytes ever shifted */
static int buf_nreallocs; /* Number of reallocations */
#define bufptr (buffer + buf_offset) #define bufptr (buffer + buf_offset)
#define bufend (buffer + buf_offset + buf_len) #define bufend (buffer + buf_offset + buf_len)
@ -262,13 +270,13 @@ static off_t buf_shifted; /* Number of bytes ever shifted */
/* /*
* Ensure that the buffer contains at least this amount of free space. * Ensure that the buffer contains at least this amount of free space.
*/ */
static void buf_extend(size_t bySize) { static void buf_extend(const void *data2add, size_t bySize) {
DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }", DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }",
(long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size); (long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size);
if(buf_size >= (buf_offset + buf_len + bySize)) { if(buf_size >= (buf_offset + buf_len + bySize)) {
return; /* Nothing to do */ /* Nothing to do */
} else if(bySize <= buf_offset) { } else if(bySize <= buf_offset) {
DEBUG("\tContents shifted by %ld", (long)buf_offset); DEBUG("\tContents shifted by %ld", (long)buf_offset);
@ -278,17 +286,22 @@ static void buf_extend(size_t bySize) {
buf_offset = 0; buf_offset = 0;
} else { } else {
size_t newsize = (buf_size << 2) + bySize; size_t newsize = (buf_size << 2) + bySize;
void *p = realloc(buffer, newsize); void *p = malloc(newsize);
if(p) { if(!p) {
buffer = (char *)p;
buf_size = newsize;
DEBUG("\tBuffer reallocated to %ld", (long)newsize);
} else {
perror("realloc()"); perror("realloc()");
exit(EX_OSERR); exit(EX_OSERR);
} }
memcpy(p, buffer, buf_len);
free(buffer);
buffer = (char *)p;
buf_size = newsize;
buf_offset = 0;
DEBUG("\tBuffer reallocated to %ld, %d time",
(long)newsize, ++buf_nreallocs);
} }
memcpy(buffer + buf_offset + buf_len, data2add, bySize);
buf_len += bySize;
} }
static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) { static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *fname, ssize_t suggested_bufsize) {
@ -310,7 +323,7 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
DEBUG("Processing file %s", fname); DEBUG("Processing file %s", fname);
fp = fopen(fname, "r"); fp = fopen(fname, "r");
} else { } else {
DEBUG("Processing standard input"); DEBUG("Processing %s", "standard input");
fname = "stdin"; fname = "stdin";
fp = stdin; fp = stdin;
} }
@ -330,8 +343,10 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
fbuf_size = suggested_bufsize; fbuf_size = suggested_bufsize;
} }
buf_nreallocs = 0;
buf_shifted = 0; buf_shifted = 0;
buf_offset = 0; buf_offset = 0;
buf_size = 0;
buf_len = 0; buf_len = 0;
/* Pretend immediate EOF */ /* Pretend immediate EOF */
@ -339,19 +354,15 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
rval.consumed = 0; rval.consumed = 0;
while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) { while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) {
asn_per_data_t pd;
char *i_bptr; char *i_bptr;
size_t i_size; size_t i_size;
/* /*
* Copy the data over, or use the original buffer. * Copy the data over, or use the original buffer.
*/ */
if(buf_len) { if(buf_size) {
/* Append the new data into the intermediate buffer */ /* Append the new data into the intermediate buffer */
buf_extend(rd); buf_extend(fbuf, rd);
memcpy(bufend, fbuf, rd);
buf_len += rd;
i_bptr = bufptr; i_bptr = bufptr;
i_size = buf_len; i_size = buf_len;
} else { } else {
@ -369,36 +380,35 @@ static void *data_decode_from_file(asn_TYPE_descriptor_t *pduType, const char *f
(void **)&structure, i_bptr, i_size); (void **)&structure, i_bptr, i_size);
break; break;
case INP_PER: case INP_PER:
pd.buffer = (uint8_t *)i_bptr; rval = uper_decode(opt_codec_ctx, pduType,
pd.nboff = 0; (void **)&structure, i_bptr, i_size);
pd.nbits = i_size * 8;
rval = pduType->uper_decoder(opt_codec_ctx, pduType, 0,
(void **)&structure, &pd);
break; break;
} }
DEBUG("decode(%ld) consumed %ld, code %d", DEBUG("decode(%ld) consumed %ld (%ld), code %d",
(long)buf_len, (long)rval.consumed, rval.code); (long)buf_len, (long)rval.consumed, (long)i_size,
rval.code);
if(buf_len == 0) { if(buf_size == 0) {
/* /*
* Switch the remainder into the intermediate buffer. * Switch the remainder into the intermediate buffer.
*/ */
if(rval.code != RC_FAIL && rval.consumed < rd) { if(rval.code != RC_FAIL && rval.consumed < rd) {
buf_extend(rd - rval.consumed); buf_extend(fbuf + rval.consumed,
memcpy(bufend, rd - rval.consumed);
fbuf + rval.consumed, rval.consumed = 0;
rd - rval.consumed);
buf_len = rd - rval.consumed;
} }
} }
switch(rval.code) { switch(rval.code) {
case RC_OK: case RC_OK:
DEBUG("RC_OK, finishing up"); DEBUG("RC_OK, finishing up with %ld",
(long)rval.consumed);
if(fp != stdin) fclose(fp); if(fp != stdin) fclose(fp);
return structure; return structure;
case RC_WMORE: case RC_WMORE:
DEBUG("RC_WMORE, continuing..."); DEBUG("RC_WMORE, continuing %ld with %ld..%ld..%ld",
(long)rval.consumed, (long)buf_offset,
(long)buf_len, (long)buf_size);
/* /*
* Adjust position inside the source buffer. * Adjust position inside the source buffer.
*/ */

View File

@ -13,11 +13,13 @@ extern "C" {
struct asn_TYPE_descriptor_s; /* Forward declaration */ struct asn_TYPE_descriptor_s; /* Forward declaration */
/* /*
* This structure defines a context that may be passed to every ASN.1 encoder * This structure defines a set of parameters that may be passed
* or decoder function. * to every ASN.1 encoder or decoder function.
* WARNING: if max_stack_size member is set, and you are calling the * WARNING: if max_stack_size member is set, and you are calling the
* function pointers of the asn_TYPE_descriptor_t directly, * function pointers of the asn_TYPE_descriptor_t directly,
* this structure must be ALLOCATED ON THE STACK! * this structure must be ALLOCATED ON THE STACK!
* If you can't always satisfy this requirement, use ber_decode(),
* xer_decode() and uper_decode() functions instead.
*/ */
typedef struct asn_codec_ctx_s { typedef struct asn_codec_ctx_s {
/* /*

View File

@ -82,6 +82,28 @@ static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; }
if(cb(" ", 4, app_key) < 0) return -1; \ if(cb(" ", 4, app_key) < 0) return -1; \
} while(0) } while(0)
/*
* Check stack against overflow, if limit is set.
*/
#define _ASN_DEFAULT_STACK_MAX (30000)
static inline int
_ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) {
if(ctx && ctx->max_stack_size) {
/* ctx MUST be allocated on the stack */
ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx);
if(usedstack > 0) usedstack = -usedstack; /* grows up! */
/* double negative required to avoid int wrap-around */
if(usedstack < -(ptrdiff_t)ctx->max_stack_size) {
ASN_DEBUG("Stack limit %ld reached",
(long)ctx->max_stack_size);
return -1;
}
}
return 0;
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -33,11 +33,18 @@ ber_decode(asn_codec_ctx_t *opt_codec_ctx,
asn_codec_ctx_t s_codec_ctx; asn_codec_ctx_t s_codec_ctx;
/* /*
* Satisfy the requirement that the codec context * Stack checker requires that the codec context
* must be allocated on the stack. * must be allocated on the stack.
*/ */
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) { if(opt_codec_ctx) {
s_codec_ctx = *opt_codec_ctx; if(opt_codec_ctx->max_stack_size) {
s_codec_ctx = *opt_codec_ctx;
opt_codec_ctx = &s_codec_ctx;
}
} else {
/* If context is not given, be security-conscious anyway */
memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX;
opt_codec_ctx = &s_codec_ctx; opt_codec_ctx = &s_codec_ctx;
} }
@ -73,17 +80,8 @@ ber_check_tags(asn_codec_ctx_t *opt_codec_ctx,
/* /*
* Make sure we didn't exceed the maximum stack size. * Make sure we didn't exceed the maximum stack size.
*/ */
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) { if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
ptrdiff_t usedstack = ((char *)opt_codec_ctx - (char *)&size); RETURN(RC_FAIL);
/* double negative is required to avoid int wrap-around */
if(usedstack > 0) usedstack = -usedstack;
ASN_DEBUG("Current stack size %ld", -(long)usedstack);
if(usedstack < -(ptrdiff_t)opt_codec_ctx->max_stack_size) {
ASN_DEBUG("Stack limit %ld reached",
(long)opt_codec_ctx->max_stack_size);
RETURN(RC_FAIL);
}
}
/* /*
* So what does all this implicit skip stuff mean? * So what does all this implicit skip stuff mean?

View File

@ -46,8 +46,8 @@ typedef asn_dec_rval_t (ber_type_decoder_f)(
* head->last_tag_form is non-zero. * head->last_tag_form is non-zero.
*/ */
asn_dec_rval_t ber_check_tags( asn_dec_rval_t ber_check_tags(
struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */
struct asn_TYPE_descriptor_s *type_dsc, struct asn_TYPE_descriptor_s *type_descriptor,
asn_struct_ctx_t *opt_ctx, /* saved decoding context */ asn_struct_ctx_t *opt_ctx, /* saved decoding context */
const void *ptr, size_t size, const void *ptr, size_t size,
int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */

View File

@ -84,17 +84,8 @@ ber_skip_length(asn_codec_ctx_t *opt_codec_ctx,
/* /*
* Make sure we didn't exceed the maximum stack size. * Make sure we didn't exceed the maximum stack size.
*/ */
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) { if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
ptrdiff_t usedstack = ((char *)opt_codec_ctx - (char *)&size); return -1;
/* double negative is required to avoid int wrap-around */
if(usedstack > 0) usedstack = -usedstack;
ASN_DEBUG("Current stack size %ld", -(long)usedstack);
if(usedstack < -(ptrdiff_t)opt_codec_ctx->max_stack_size) {
ASN_DEBUG("Stack limit %ld reached",
(long)opt_codec_ctx->max_stack_size);
return -1;
}
}
/* /*
* Determine the size of L in TLV. * Determine the size of L in TLV.

View File

@ -31,7 +31,6 @@ ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size,
* RETURN VALUES: * RETURN VALUES:
* Standard {-1,0,>0} convention. * Standard {-1,0,>0} convention.
*/ */
struct asn_codec_ctx_s; /* Forward declaration */
ssize_t ber_skip_length( ssize_t ber_skip_length(
struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */
int _is_constructed, const void *bufptr, size_t size); int _is_constructed, const void *bufptr, size_t size);

View File

@ -827,6 +827,9 @@ CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
void *st = *sptr; void *st = *sptr;
int value; int value;
if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
_ASN_DECODE_FAILED;
/* /*
* Create the target structure if it is not present already. * Create the target structure if it is not present already.
*/ */

View File

@ -703,7 +703,8 @@ SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
} }
tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d", tcv, ctx->phase); ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d [%s]",
tcv, ctx->phase, xml_tag);
/* Skip the extensions section */ /* Skip the extensions section */
if(ctx->phase == 3) { if(ctx->phase == 3) {
@ -829,7 +830,13 @@ SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
break; break;
} }
ASN_DEBUG("Unexpected XML tag in SEQUENCE"); ASN_DEBUG("Unexpected XML tag in SEQUENCE [%c%c%c%c%c%c]",
size>0?((const char *)buf_ptr)[0]:'.',
size>1?((const char *)buf_ptr)[1]:'.',
size>2?((const char *)buf_ptr)[2]:'.',
size>3?((const char *)buf_ptr)[3]:'.',
size>4?((const char *)buf_ptr)[4]:'.',
size>5?((const char *)buf_ptr)[5]:'.');
break; break;
} }
@ -1028,6 +1035,9 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
(void)constraints; (void)constraints;
if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
_ASN_DECODE_FAILED;
if(!st) { if(!st) {
st = *sptr = CALLOC(1, specs->struct_size); st = *sptr = CALLOC(1, specs->struct_size);
if(!st) _ASN_DECODE_FAILED; if(!st) _ASN_DECODE_FAILED;

View File

@ -864,6 +864,9 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
int repeat = 0; int repeat = 0;
ssize_t nelems; ssize_t nelems;
if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
_ASN_DECODE_FAILED;
/* /*
* Create the target structure if it is not present already. * Create the target structure if it is not present already.
*/ */

View File

@ -1,2 +1,38 @@
#include <asn_application.h> #include <asn_application.h>
#include <asn_internal.h>
#include <per_decoder.h> #include <per_decoder.h>
asn_dec_rval_t
uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size) {
asn_codec_ctx_t s_codec_ctx;
asn_per_data_t pd;
/*
* Stack checker requires that the codec context
* must be allocated on the stack.
*/
if(opt_codec_ctx) {
if(opt_codec_ctx->max_stack_size) {
s_codec_ctx = *opt_codec_ctx;
opt_codec_ctx = &s_codec_ctx;
}
} else {
/* If context is not given, be security-conscious anyway */
memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX;
opt_codec_ctx = &s_codec_ctx;
}
/* Fill in the position indicator */
pd.buffer = (const uint8_t *)buffer;
pd.nboff = 0;
pd.nbits = 8 * size; /* 8 is CHAR_BIT from <limits.h> */
/*
* Invoke type-specific decoder.
*/
if(!td->uper_decoder)
_ASN_DECODE_FAILED; /* PER is not compiled in */
return td->uper_decoder(opt_codec_ctx, td, 0, sptr, &pd);
}

View File

@ -12,6 +12,18 @@
extern "C" { extern "C" {
#endif #endif
struct asn_TYPE_descriptor_s; /* Forward declaration */
/*
* Unaligned PER decoder of any ASN.1 type. May be invoked by the application.
*/
asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx,
struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */
void **struct_ptr, /* Pointer to a target structure's pointer */
const void *buffer, /* Data to be decoded */
size_t size /* Size of data buffer */
);
/* /*
* Pre-computed PER constraints. * Pre-computed PER constraints.
@ -23,7 +35,6 @@ extern "C" {
APC_EXTENSIBLE = 0x4 /* May have extension */ APC_EXTENSIBLE = 0x4 /* May have extension */
}; };
typedef struct asn_per_constraint_s { typedef struct asn_per_constraint_s {
enum asn_per_constraint_flags flags; enum asn_per_constraint_flags flags;
int range_bits; /* Full number of bits in the range */ int range_bits; /* Full number of bits in the range */
int effective_bits; /* Effective bits */ int effective_bits; /* Effective bits */
@ -35,9 +46,6 @@ typedef struct asn_per_constraints_s {
asn_per_constraint_t size; asn_per_constraint_t size;
} asn_per_constraints_t; } asn_per_constraints_t;
struct asn_TYPE_descriptor_s; /* Forward declaration */
/* /*
* Type of the type-specific PER decoder function. * Type of the type-specific PER decoder function.
*/ */

View File

@ -12,7 +12,7 @@ int32_t
per_get_few_bits(asn_per_data_t *pd, int nbits) { per_get_few_bits(asn_per_data_t *pd, int nbits) {
size_t off; /* Next after last bit offset */ size_t off; /* Next after last bit offset */
uint32_t accum; uint32_t accum;
uint8_t *buf; const uint8_t *buf;
if(nbits < 0 || pd->nboff + nbits > pd->nbits) if(nbits < 0 || pd->nboff + nbits > pd->nbits)
return -1; return -1;

View File

@ -15,9 +15,9 @@ extern "C" {
* This structure describes a position inside a PER bit stream. * This structure describes a position inside a PER bit stream.
*/ */
typedef struct asn_per_data_s { typedef struct asn_per_data_s {
uint8_t *buffer; /* Pointer to the octet stream */ const uint8_t *buffer; /* Pointer to the octet stream */
size_t nboff; /* Bit offset to the meaningful bit */ size_t nboff; /* Bit offset to the meaningful bit */
size_t nbits; /* Number of bits in the stream */ size_t nbits; /* Number of bits in the stream */
} asn_per_data_t; } asn_per_data_t;
/* /*

View File

@ -16,11 +16,18 @@ xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
asn_codec_ctx_t s_codec_ctx; asn_codec_ctx_t s_codec_ctx;
/* /*
* Satisfy the requirement that the codec context * Stack checker requires that the codec context
* must be allocated on the stack. * must be allocated on the stack.
*/ */
if(opt_codec_ctx && opt_codec_ctx->max_stack_size) { if(opt_codec_ctx) {
s_codec_ctx = *opt_codec_ctx; if(opt_codec_ctx->max_stack_size) {
s_codec_ctx = *opt_codec_ctx;
opt_codec_ctx = &s_codec_ctx;
}
} else {
/* If context is not given, be security-conscious anyway */
memset(&s_codec_ctx, 0, sizeof(s_codec_ctx));
s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX;
opt_codec_ctx = &s_codec_ctx; opt_codec_ctx = &s_codec_ctx;
} }

View File

@ -14,13 +14,13 @@ extern "C" {
struct asn_TYPE_descriptor_s; /* Forward declaration */ struct asn_TYPE_descriptor_s; /* Forward declaration */
/* /*
* The XER decoder of any type. May be invoked by the application. * The XER decoder of any ASN.1 type. May be invoked by the application.
*/ */
asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx,
struct asn_TYPE_descriptor_s *type_descriptor, struct asn_TYPE_descriptor_s *type_descriptor,
void **struct_ptr, /* Pointer to a target structure's pointer */ void **struct_ptr, /* Pointer to a target structure's pointer */
const void *buffer, /* Data to be decoded */ const void *buffer, /* Data to be decoded */
size_t size /* Size of that buffer */ size_t size /* Size of data buffer */
); );
/* /*