// SPDX-License-Identifier: GPL-2.0-only
/*
 * BER and PER decoding library for H.323 conntrack/NAT module.
 *
 * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@users.sourceforge.net>
 *
 * See nf_conntrack_helper_h323_asn1.h for details.
 */

#ifdef __KERNEL__
#include <linux/kernel.h>
#else
#include <stdio.h>
#endif
#include <linux/netfilter/nf_conntrack_h323_asn1.h>

/* Trace Flag */
#ifndef H323_TRACE
#define H323_TRACE 0
#endif

#if H323_TRACE
#define TAB_SIZE 4
#define IFTHEN(cond, act) if(cond){act;}
#ifdef __KERNEL__
#define PRINT printk
#else
#define PRINT printf
#endif
#define FNAME(name) name,
#else
#define IFTHEN(cond, act)
#define PRINT(fmt, args...)
#define FNAME(name)
#endif

/* ASN.1 Types */
#define NUL 0
#define BOOL 1
#define OID 2
#define INT 3
#define ENUM 4
#define BITSTR 5
#define NUMSTR 6
#define NUMDGT 6
#define TBCDSTR 6
#define OCTSTR 7
#define PRTSTR 7
#define IA5STR 7
#define GENSTR 7
#define BMPSTR 8
#define SEQ 9
#define SET 9
#define SEQOF 10
#define SETOF 10
#define CHOICE 11

/* Constraint Types */
#define FIXD 0
/* #define BITS 1-8 */
#define BYTE 9
#define WORD 10
#define CONS 11
#define SEMI 12
#define UNCO 13

/* ASN.1 Type Attributes */
#define SKIP 0
#define STOP 1
#define DECODE 2
#define EXT 4
#define OPEN 8
#define OPT 16


/* ASN.1 Field Structure */
typedef struct field_t {
#if H323_TRACE
	char *name;
#endif
	unsigned char type;
	unsigned char sz;
	unsigned char lb;
	unsigned char ub;
	unsigned short attr;
	unsigned short offset;
	const struct field_t *fields;
} field_t;

/* Bit Stream */
struct bitstr {
	unsigned char *buf;
	unsigned char *beg;
	unsigned char *end;
	unsigned char *cur;
	unsigned int bit;
};

/* Tool Functions */
#define INC_BIT(bs) if((++(bs)->bit)>7){(bs)->cur++;(bs)->bit=0;}
#define INC_BITS(bs,b) if(((bs)->bit+=(b))>7){(bs)->cur+=(bs)->bit>>3;(bs)->bit&=7;}
#define BYTE_ALIGN(bs) if((bs)->bit){(bs)->cur++;(bs)->bit=0;}
static unsigned int get_len(struct bitstr *bs);
static unsigned int get_bit(struct bitstr *bs);
static unsigned int get_bits(struct bitstr *bs, unsigned int b);
static unsigned int get_bitmap(struct bitstr *bs, unsigned int b);
static unsigned int get_uint(struct bitstr *bs, int b);

/* Decoder Functions */
static int decode_nul(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_bool(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_oid(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_int(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_enum(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_bitstr(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_numstr(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_octstr(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_bmpstr(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_seq(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_seqof(struct bitstr *bs, const struct field_t *f, char *base, int level);
static int decode_choice(struct bitstr *bs, const struct field_t *f, char *base, int level);

/* Decoder Functions Vector */
typedef int (*decoder_t)(struct bitstr *, const struct field_t *, char *, int);
static const decoder_t Decoders[] = {
	decode_nul,
	decode_bool,
	decode_oid,
	decode_int,
	decode_enum,
	decode_bitstr,
	decode_numstr,
	decode_octstr,
	decode_bmpstr,
	decode_seq,
	decode_seqof,
	decode_choice,
};

/*
 * H.323 Types
 */
#include "nf_conntrack_h323_types.c"

/*
 * Functions
 */

/* Assume bs is aligned && v < 16384 */
static unsigned int get_len(struct bitstr *bs)
{
	unsigned int v;

	v = *bs->cur++;

	if (v & 0x80) {
		v &= 0x3f;
		v <<= 8;
		v += *bs->cur++;
	}

	return v;
}

static int nf_h323_error_boundary(struct bitstr *bs, size_t bytes, size_t bits)
{
	bits += bs->bit;
	bytes += bits / BITS_PER_BYTE;
	if (bits % BITS_PER_BYTE > 0)
		bytes++;

	if (bs->cur + bytes > bs->end)
		return 1;

	return 0;
}

static unsigned int get_bit(struct bitstr *bs)
{
	unsigned int b = (*bs->cur) & (0x80 >> bs->bit);

	INC_BIT(bs);

	return b;
}

/* Assume b <= 8 */
static unsigned int get_bits(struct bitstr *bs, unsigned int b)
{
	unsigned int v, l;

	v = (*bs->cur) & (0xffU >> bs->bit);
	l = b + bs->bit;

	if (l < 8) {
		v >>= 8 - l;
		bs->bit = l;
	} else if (l == 8) {
		bs->cur++;
		bs->bit = 0;
	} else {		/* l > 8 */

		v <<= 8;
		v += *(++bs->cur);
		v >>= 16 - l;
		bs->bit = l - 8;
	}

	return v;
}

/* Assume b <= 32 */
static unsigned int get_bitmap(struct bitstr *bs, unsigned int b)
{
	unsigned int v, l, shift, bytes;

	if (!b)
		return 0;

	l = bs->bit + b;

	if (l < 8) {
		v = (unsigned int)(*bs->cur) << (bs->bit + 24);
		bs->bit = l;
	} else if (l == 8) {
		v = (unsigned int)(*bs->cur++) << (bs->bit + 24);
		bs->bit = 0;
	} else {
		for (bytes = l >> 3, shift = 24, v = 0; bytes;
		     bytes--, shift -= 8)
			v |= (unsigned int)(*bs->cur++) << shift;

		if (l < 32) {
			v |= (unsigned int)(*bs->cur) << shift;
			v <<= bs->bit;
		} else if (l > 32) {
			v <<= bs->bit;
			v |= (*bs->cur) >> (8 - bs->bit);
		}

		bs->bit = l & 0x7;
	}

	v &= 0xffffffff << (32 - b);

	return v;
}

/*
 * Assume bs is aligned and sizeof(unsigned int) == 4
 */
static unsigned int get_uint(struct bitstr *bs, int b)
{
	unsigned int v = 0;

	switch (b) {
	case 4:
		v |= *bs->cur++;
		v <<= 8;
		fallthrough;
	case 3:
		v |= *bs->cur++;
		v <<= 8;
		fallthrough;
	case 2:
		v |= *bs->cur++;
		v <<= 8;
		fallthrough;
	case 1:
		v |= *bs->cur++;
		break;
	}
	return v;
}

static int decode_nul(struct bitstr *bs, const struct field_t *f,
                      char *base, int level)
{
	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	return H323_ERROR_NONE;
}

static int decode_bool(struct bitstr *bs, const struct field_t *f,
                       char *base, int level)
{
	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	INC_BIT(bs);
	if (nf_h323_error_boundary(bs, 0, 0))
		return H323_ERROR_BOUND;
	return H323_ERROR_NONE;
}

static int decode_oid(struct bitstr *bs, const struct field_t *f,
                      char *base, int level)
{
	int len;

	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	BYTE_ALIGN(bs);
	if (nf_h323_error_boundary(bs, 1, 0))
		return H323_ERROR_BOUND;

	len = *bs->cur++;
	bs->cur += len;
	if (nf_h323_error_boundary(bs, 0, 0))
		return H323_ERROR_BOUND;

	return H323_ERROR_NONE;
}

static int decode_int(struct bitstr *bs, const struct field_t *f,
                      char *base, int level)
{
	unsigned int len;

	PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);

	switch (f->sz) {
	case BYTE:		/* Range == 256 */
		BYTE_ALIGN(bs);
		bs->cur++;
		break;
	case WORD:		/* 257 <= Range <= 64K */
		BYTE_ALIGN(bs);
		bs->cur += 2;
		break;
	case CONS:		/* 64K < Range < 4G */
		if (nf_h323_error_boundary(bs, 0, 2))
			return H323_ERROR_BOUND;
		len = get_bits(bs, 2) + 1;
		BYTE_ALIGN(bs);
		if (base && (f->attr & DECODE)) {	/* timeToLive */
			unsigned int v = get_uint(bs, len) + f->lb;
			PRINT(" = %u", v);
			*((unsigned int *)(base + f->offset)) = v;
		}
		bs->cur += len;
		break;
	case UNCO:
		BYTE_ALIGN(bs);
		if (nf_h323_error_boundary(bs, 2, 0))
			return H323_ERROR_BOUND;
		len = get_len(bs);
		bs->cur += len;
		break;
	default:		/* 2 <= Range <= 255 */
		INC_BITS(bs, f->sz);
		break;
	}

	PRINT("\n");

	if (nf_h323_error_boundary(bs, 0, 0))
		return H323_ERROR_BOUND;
	return H323_ERROR_NONE;
}

static int decode_enum(struct bitstr *bs, const struct field_t *f,
                       char *base, int level)
{
	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	if ((f->attr & EXT) && get_bit(bs)) {
		INC_BITS(bs, 7);
	} else {
		INC_BITS(bs, f->sz);
	}

	if (nf_h323_error_boundary(bs, 0, 0))
		return H323_ERROR_BOUND;
	return H323_ERROR_NONE;
}

static int decode_bitstr(struct bitstr *bs, const struct field_t *f,
                         char *base, int level)
{
	unsigned int len;

	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	BYTE_ALIGN(bs);
	switch (f->sz) {
	case FIXD:		/* fixed length > 16 */
		len = f->lb;
		break;
	case WORD:		/* 2-byte length */
		if (nf_h323_error_boundary(bs, 2, 0))
			return H323_ERROR_BOUND;
		len = (*bs->cur++) << 8;
		len += (*bs->cur++) + f->lb;
		break;
	case SEMI:
		if (nf_h323_error_boundary(bs, 2, 0))
			return H323_ERROR_BOUND;
		len = get_len(bs);
		break;
	default:
		len = 0;
		break;
	}

	bs->cur += len >> 3;
	bs->bit = len & 7;

	if (nf_h323_error_boundary(bs, 0, 0))
		return H323_ERROR_BOUND;
	return H323_ERROR_NONE;
}

static int decode_numstr(struct bitstr *bs, const struct field_t *f,
                         char *base, int level)
{
	unsigned int len;

	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	/* 2 <= Range <= 255 */
	if (nf_h323_error_boundary(bs, 0, f->sz))
		return H323_ERROR_BOUND;
	len = get_bits(bs, f->sz) + f->lb;

	BYTE_ALIGN(bs);
	INC_BITS(bs, (len << 2));

	if (nf_h323_error_boundary(bs, 0, 0))
		return H323_ERROR_BOUND;
	return H323_ERROR_NONE;
}

static int decode_octstr(struct bitstr *bs, const struct field_t *f,
                         char *base, int level)
{
	unsigned int len;

	PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);

	switch (f->sz) {
	case FIXD:		/* Range == 1 */
		if (f->lb > 2) {
			BYTE_ALIGN(bs);
			if (base && (f->attr & DECODE)) {
				/* The IP Address */
				IFTHEN(f->lb == 4,
				       PRINT(" = %d.%d.%d.%d:%d",
					     bs->cur[0], bs->cur[1],
					     bs->cur[2], bs->cur[3],
					     bs->cur[4] * 256 + bs->cur[5]));
				*((unsigned int *)(base + f->offset)) =
				    bs->cur - bs->buf;
			}
		}
		len = f->lb;
		break;
	case BYTE:		/* Range == 256 */
		BYTE_ALIGN(bs);
		if (nf_h323_error_boundary(bs, 1, 0))
			return H323_ERROR_BOUND;
		len = (*bs->cur++) + f->lb;
		break;
	case SEMI:
		BYTE_ALIGN(bs);
		if (nf_h323_error_boundary(bs, 2, 0))
			return H323_ERROR_BOUND;
		len = get_len(bs) + f->lb;
		break;
	default:		/* 2 <= Range <= 255 */
		if (nf_h323_error_boundary(bs, 0, f->sz))
			return H323_ERROR_BOUND;
		len = get_bits(bs, f->sz) + f->lb;
		BYTE_ALIGN(bs);
		break;
	}

	bs->cur += len;

	PRINT("\n");

	if (nf_h323_error_boundary(bs, 0, 0))
		return H323_ERROR_BOUND;
	return H323_ERROR_NONE;
}

static int decode_bmpstr(struct bitstr *bs, const struct field_t *f,
                         char *base, int level)
{
	unsigned int len;

	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	switch (f->sz) {
	case BYTE:		/* Range == 256 */
		BYTE_ALIGN(bs);
		if (nf_h323_error_boundary(bs, 1, 0))
			return H323_ERROR_BOUND;
		len = (*bs->cur++) + f->lb;
		break;
	default:		/* 2 <= Range <= 255 */
		if (nf_h323_error_boundary(bs, 0, f->sz))
			return H323_ERROR_BOUND;
		len = get_bits(bs, f->sz) + f->lb;
		BYTE_ALIGN(bs);
		break;
	}

	bs->cur += len << 1;

	if (nf_h323_error_boundary(bs, 0, 0))
		return H323_ERROR_BOUND;
	return H323_ERROR_NONE;
}

static int decode_seq(struct bitstr *bs, const struct field_t *f,
                      char *base, int level)
{
	unsigned int ext, bmp, i, opt, len = 0, bmp2, bmp2_len;
	int err;
	const struct field_t *son;
	unsigned char *beg = NULL;

	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	/* Decode? */
	base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;

	/* Extensible? */
	if (nf_h323_error_boundary(bs, 0, 1))
		return H323_ERROR_BOUND;
	ext = (f->attr & EXT) ? get_bit(bs) : 0;

	/* Get fields bitmap */
	if (nf_h323_error_boundary(bs, 0, f->sz))
		return H323_ERROR_BOUND;
	if (f->sz > 32)
		return H323_ERROR_RANGE;
	bmp = get_bitmap(bs, f->sz);
	if (base)
		*(unsigned int *)base = bmp;

	/* Decode the root components */
	for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) {
		if (son->attr & STOP) {
			PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
			      son->name);
			return H323_ERROR_STOP;
		}

		if (son->attr & OPT) {	/* Optional component */
			if (!((0x80000000U >> (opt++)) & bmp))	/* Not exist */
				continue;
		}

		/* Decode */
		if (son->attr & OPEN) {	/* Open field */
			if (nf_h323_error_boundary(bs, 2, 0))
				return H323_ERROR_BOUND;
			len = get_len(bs);
			if (nf_h323_error_boundary(bs, len, 0))
				return H323_ERROR_BOUND;
			if (!base || !(son->attr & DECODE)) {
				PRINT("%*.s%s\n", (level + 1) * TAB_SIZE,
				      " ", son->name);
				bs->cur += len;
				continue;
			}
			beg = bs->cur;

			/* Decode */
			if ((err = (Decoders[son->type]) (bs, son, base,
							  level + 1)) <
			    H323_ERROR_NONE)
				return err;

			bs->cur = beg + len;
			bs->bit = 0;
		} else if ((err = (Decoders[son->type]) (bs, son, base,
							 level + 1)) <
			   H323_ERROR_NONE)
			return err;
	}

	/* No extension? */
	if (!ext)
		return H323_ERROR_NONE;

	/* Get the extension bitmap */
	if (nf_h323_error_boundary(bs, 0, 7))
		return H323_ERROR_BOUND;
	bmp2_len = get_bits(bs, 7) + 1;
	if (nf_h323_error_boundary(bs, 0, bmp2_len))
		return H323_ERROR_BOUND;
	if (bmp2_len > 32)
		return H323_ERROR_RANGE;
	bmp2 = get_bitmap(bs, bmp2_len);
	bmp |= bmp2 >> f->sz;
	if (base)
		*(unsigned int *)base = bmp;
	BYTE_ALIGN(bs);

	/* Decode the extension components */
	for (opt = 0; opt < bmp2_len; opt++, i++, son++) {
		/* Check Range */
		if (i >= f->ub) {	/* Newer Version? */
			if (nf_h323_error_boundary(bs, 2, 0))
				return H323_ERROR_BOUND;
			len = get_len(bs);
			if (nf_h323_error_boundary(bs, len, 0))
				return H323_ERROR_BOUND;
			bs->cur += len;
			continue;
		}

		if (son->attr & STOP) {
			PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
			      son->name);
			return H323_ERROR_STOP;
		}

		if (!((0x80000000 >> opt) & bmp2))	/* Not present */
			continue;

		if (nf_h323_error_boundary(bs, 2, 0))
			return H323_ERROR_BOUND;
		len = get_len(bs);
		if (nf_h323_error_boundary(bs, len, 0))
			return H323_ERROR_BOUND;
		if (!base || !(son->attr & DECODE)) {
			PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
			      son->name);
			bs->cur += len;
			continue;
		}
		beg = bs->cur;

		if ((err = (Decoders[son->type]) (bs, son, base,
						  level + 1)) <
		    H323_ERROR_NONE)
			return err;

		bs->cur = beg + len;
		bs->bit = 0;
	}
	return H323_ERROR_NONE;
}

static int decode_seqof(struct bitstr *bs, const struct field_t *f,
                        char *base, int level)
{
	unsigned int count, effective_count = 0, i, len = 0;
	int err;
	const struct field_t *son;
	unsigned char *beg = NULL;

	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	/* Decode? */
	base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;

	/* Decode item count */
	switch (f->sz) {
	case BYTE:
		BYTE_ALIGN(bs);
		if (nf_h323_error_boundary(bs, 1, 0))
			return H323_ERROR_BOUND;
		count = *bs->cur++;
		break;
	case WORD:
		BYTE_ALIGN(bs);
		if (nf_h323_error_boundary(bs, 2, 0))
			return H323_ERROR_BOUND;
		count = *bs->cur++;
		count <<= 8;
		count += *bs->cur++;
		break;
	case SEMI:
		BYTE_ALIGN(bs);
		if (nf_h323_error_boundary(bs, 2, 0))
			return H323_ERROR_BOUND;
		count = get_len(bs);
		break;
	default:
		if (nf_h323_error_boundary(bs, 0, f->sz))
			return H323_ERROR_BOUND;
		count = get_bits(bs, f->sz);
		break;
	}
	count += f->lb;

	/* Write Count */
	if (base) {
		effective_count = count > f->ub ? f->ub : count;
		*(unsigned int *)base = effective_count;
		base += sizeof(unsigned int);
	}

	/* Decode nested field */
	son = f->fields;
	if (base)
		base -= son->offset;
	for (i = 0; i < count; i++) {
		if (son->attr & OPEN) {
			BYTE_ALIGN(bs);
			if (nf_h323_error_boundary(bs, 2, 0))
				return H323_ERROR_BOUND;
			len = get_len(bs);
			if (nf_h323_error_boundary(bs, len, 0))
				return H323_ERROR_BOUND;
			if (!base || !(son->attr & DECODE)) {
				PRINT("%*.s%s\n", (level + 1) * TAB_SIZE,
				      " ", son->name);
				bs->cur += len;
				continue;
			}
			beg = bs->cur;

			if ((err = (Decoders[son->type]) (bs, son,
							  i <
							  effective_count ?
							  base : NULL,
							  level + 1)) <
			    H323_ERROR_NONE)
				return err;

			bs->cur = beg + len;
			bs->bit = 0;
		} else
			if ((err = (Decoders[son->type]) (bs, son,
							  i <
							  effective_count ?
							  base : NULL,
							  level + 1)) <
			    H323_ERROR_NONE)
				return err;

		if (base)
			base += son->offset;
	}

	return H323_ERROR_NONE;
}

static int decode_choice(struct bitstr *bs, const struct field_t *f,
                         char *base, int level)
{
	unsigned int type, ext, len = 0;
	int err;
	const struct field_t *son;
	unsigned char *beg = NULL;

	PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);

	/* Decode? */
	base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;

	/* Decode the choice index number */
	if (nf_h323_error_boundary(bs, 0, 1))
		return H323_ERROR_BOUND;
	if ((f->attr & EXT) && get_bit(bs)) {
		ext = 1;
		if (nf_h323_error_boundary(bs, 0, 7))
			return H323_ERROR_BOUND;
		type = get_bits(bs, 7) + f->lb;
	} else {
		ext = 0;
		if (nf_h323_error_boundary(bs, 0, f->sz))
			return H323_ERROR_BOUND;
		type = get_bits(bs, f->sz);
		if (type >= f->lb)
			return H323_ERROR_RANGE;
	}

	/* Write Type */
	if (base)
		*(unsigned int *)base = type;

	/* Check Range */
	if (type >= f->ub) {	/* Newer version? */
		BYTE_ALIGN(bs);
		if (nf_h323_error_boundary(bs, 2, 0))
			return H323_ERROR_BOUND;
		len = get_len(bs);
		if (nf_h323_error_boundary(bs, len, 0))
			return H323_ERROR_BOUND;
		bs->cur += len;
		return H323_ERROR_NONE;
	}

	/* Transfer to son level */
	son = &f->fields[type];
	if (son->attr & STOP) {
		PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name);
		return H323_ERROR_STOP;
	}

	if (ext || (son->attr & OPEN)) {
		BYTE_ALIGN(bs);
		if (nf_h323_error_boundary(bs, len, 0))
			return H323_ERROR_BOUND;
		len = get_len(bs);
		if (nf_h323_error_boundary(bs, len, 0))
			return H323_ERROR_BOUND;
		if (!base || !(son->attr & DECODE)) {
			PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
			      son->name);
			bs->cur += len;
			return H323_ERROR_NONE;
		}
		beg = bs->cur;

		if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) <
		    H323_ERROR_NONE)
			return err;

		bs->cur = beg + len;
		bs->bit = 0;
	} else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) <
		   H323_ERROR_NONE)
		return err;

	return H323_ERROR_NONE;
}

int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage *ras)
{
	static const struct field_t ras_message = {
		FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT,
		0, _RasMessage
	};
	struct bitstr bs;

	bs.buf = bs.beg = bs.cur = buf;
	bs.end = buf + sz;
	bs.bit = 0;

	return decode_choice(&bs, &ras_message, (char *) ras, 0);
}

static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg,
				      size_t sz, H323_UserInformation *uuie)
{
	static const struct field_t h323_userinformation = {
		FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT,
		0, _H323_UserInformation
	};
	struct bitstr bs;

	bs.buf = buf;
	bs.beg = bs.cur = beg;
	bs.end = beg + sz;
	bs.bit = 0;

	return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0);
}

int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
					 MultimediaSystemControlMessage *
					 mscm)
{
	static const struct field_t multimediasystemcontrolmessage = {
		FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4,
		DECODE | EXT, 0, _MultimediaSystemControlMessage
	};
	struct bitstr bs;

	bs.buf = bs.beg = bs.cur = buf;
	bs.end = buf + sz;
	bs.bit = 0;

	return decode_choice(&bs, &multimediasystemcontrolmessage,
			     (char *) mscm, 0);
}

int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931)
{
	unsigned char *p = buf;
	int len;

	if (!p || sz < 1)
		return H323_ERROR_BOUND;

	/* Protocol Discriminator */
	if (*p != 0x08) {
		PRINT("Unknown Protocol Discriminator\n");
		return H323_ERROR_RANGE;
	}
	p++;
	sz--;

	/* CallReferenceValue */
	if (sz < 1)
		return H323_ERROR_BOUND;
	len = *p++;
	sz--;
	if (sz < len)
		return H323_ERROR_BOUND;
	p += len;
	sz -= len;

	/* Message Type */
	if (sz < 2)
		return H323_ERROR_BOUND;
	q931->MessageType = *p++;
	sz--;
	PRINT("MessageType = %02X\n", q931->MessageType);
	if (*p & 0x80) {
		p++;
		sz--;
	}

	/* Decode Information Elements */
	while (sz > 0) {
		if (*p == 0x7e) {	/* UserUserIE */
			if (sz < 3)
				break;
			p++;
			len = *p++ << 8;
			len |= *p++;
			sz -= 3;
			if (sz < len)
				break;
			p++;
			len--;
			return DecodeH323_UserInformation(buf, p, len,
							  &q931->UUIE);
		}
		p++;
		sz--;
		if (sz < 1)
			break;
		len = *p++;
		sz--;
		if (sz < len)
			break;
		p += len;
		sz -= len;
	}

	PRINT("Q.931 UUIE not found\n");

	return H323_ERROR_BOUND;
}
