aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-11-28 02:49:14 +0200
committerNatanael Copa <ncopa@alpinelinux.org>2010-01-14 09:40:34 +0000
commit806ec05e217ad080784c75f9ee4d1b956d4646d2 (patch)
tree4d7cf92c205daf80a26e55a44cb3628c29a40a70
parentfbaaa5aa75bc5139eb5bdfc64c6c86066396b4f8 (diff)
downloadaports-806ec05e217ad080784c75f9ee4d1b956d4646d2.tar.bz2
aports-806ec05e217ad080784c75f9ee4d1b956d4646d2.tar.xz
main/libpri: upgrade to latest svn snapshot
(cherry picked from commit bf4a081b091fc26e782bb24c786ae5ceb0577fb3)
-rw-r--r--main/asterisk/301-libpri-autoconf.patch21
-rw-r--r--main/libpri/APKBUILD17
-rw-r--r--main/libpri/libpri-1.4-r1357.patch39961
-rw-r--r--main/libpri/libpri-1.4.9-i14292.patch5668
4 files changed, 39990 insertions, 5677 deletions
diff --git a/main/asterisk/301-libpri-autoconf.patch b/main/asterisk/301-libpri-autoconf.patch
new file mode 100644
index 0000000000..0893b0323a
--- /dev/null
+++ b/main/asterisk/301-libpri-autoconf.patch
@@ -0,0 +1,21 @@
+Index: configure.ac
+===================================================================
+--- a/configure.ac.orig Fri Nov 27 22:58:39 2009
++++ b/configure.ac Sat Nov 28 00:14:40 2009
+@@ -261,11 +261,11 @@
+ AST_EXT_LIB_SETUP([POPT], [popt], [popt])
+ AST_EXT_LIB_SETUP([PORTAUDIO], [PortAudio], [portaudio])
+ AST_EXT_LIB_SETUP([PRI], [ISDN PRI], [pri])
+-AST_EXT_LIB_SETUP_DEPENDENT([PRI_VERSION], [ISDN PRI get_version], [PRI], [pri])
+-AST_EXT_LIB_SETUP_DEPENDENT([PRI_INBANDDISCONNECT], [ISDN PRI set_inbanddisconnect], [PRI], [pri])
+-AST_EXT_LIB_SETUP_DEPENDENT([PRI_PROG_W_CAUSE], [ISDN progress with cause], [PRI], [pri])
+-AST_EXT_LIB_SETUP_DEPENDENT([PRI_SERVICE_MESSAGES], [ISDN service messages], [PRI], [pri])
+-AST_EXT_LIB_SETUP_DEPENDENT([PRI_REVERSE_CHARGE], [ISDN reverse charge], [PRI], [pri])
++#AST_EXT_LIB_SETUP_DEPENDENT([PRI_VERSION], [ISDN PRI get_version], [PRI], [pri])
++#AST_EXT_LIB_SETUP_DEPENDENT([PRI_INBANDDISCONNECT], [ISDN PRI set_inbanddisconnect], [PRI], [pri])
++#AST_EXT_LIB_SETUP_DEPENDENT([PRI_PROG_W_CAUSE], [ISDN progress with cause], [PRI], [pri])
++#AST_EXT_LIB_SETUP_DEPENDENT([PRI_SERVICE_MESSAGES], [ISDN service messages], [PRI], [pri])
++#AST_EXT_LIB_SETUP_DEPENDENT([PRI_REVERSE_CHARGE], [ISDN reverse charge], [PRI], [pri])
+ AST_EXT_LIB_SETUP([RESAMPLE], [LIBRESAMPLE], [resample])
+ AST_EXT_LIB_SETUP([SPANDSP], [SPANDSP], [spandsp])
+ AST_EXT_LIB_SETUP([SS7], [ISDN SS7], [ss7])
diff --git a/main/libpri/APKBUILD b/main/libpri/APKBUILD
index d4d90a8103..05467c5352 100644
--- a/main/libpri/APKBUILD
+++ b/main/libpri/APKBUILD
@@ -1,8 +1,9 @@
# Contributor: Timo Teras <timo.teras@iki.fi>
# Maintainer: Timo Teras <timo.teras@iki.fi>
pkgname=libpri
-pkgver=1.4.9
-pkgrel=1
+pkgver=1.4.11_alpha1
+_pkgver=1.4.10.2
+pkgrel=0
pkgdesc="Primary Rate ISDN (PRI) library"
url="http://www.asterisk.orig"
license="GPL"
@@ -10,12 +11,11 @@ depends=""
makedepends=""
install=
subpackages="$pkgname-dev"
-source="http://downloads.digium.com/pub/telephony/libpri/releases/$pkgname-$pkgver.tar.gz
- libpri-cflags.patch
- libpri-1.4.9-i14292.patch"
+source="http://downloads.digium.com/pub/telephony/libpri/releases/$pkgname-$_pkgver.tar.gz
+ libpri-1.4-r1357.patch"
build() {
- cd "$srcdir/$pkgname-$pkgver"
+ cd "$srcdir/$pkgname-$_pkgver"
for i in ../*.patch; do
msg "Applying $i"
patch -p1 < $i || return 1;
@@ -28,6 +28,5 @@ build() {
# install -m644 -D "$srcdir"/$pkgname.confd "$pkgdir"/etc/conf.d/$pkgname
}
-md5sums="97332edeaa2de0320d85fda88afb96f9 libpri-1.4.9.tar.gz
-8df2ca48ce7db4f1a8604b0904bc9394 libpri-cflags.patch
-240e4057980c88f2c2576c5c25744c70 libpri-1.4.9-i14292.patch"
+md5sums="dc1523d8ee027cd62f20fc6cc9727489 libpri-1.4.10.2.tar.gz
+61a245689a40e456643ed654441a280d libpri-1.4-r1357.patch"
diff --git a/main/libpri/libpri-1.4-r1357.patch b/main/libpri/libpri-1.4-r1357.patch
new file mode 100644
index 0000000000..be827eebb7
--- /dev/null
+++ b/main/libpri/libpri-1.4-r1357.patch
@@ -0,0 +1,39961 @@
+===================================================================
+--- a/pri_timers.h (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_timers.h (.../branches/1.4) (revision 1357)
+@@ -1,97 +0,0 @@
+-/*
+- * libpri: An implementation of Primary Rate ISDN
+- *
+- * Written by Mark Spencer <markster@digium.com>
+- *
+- * Copyright (C) 2001, Digium, Inc.
+- * All Rights Reserved.
+- */
+-
+-/*
+- * See http://www.asterisk.org for more information about
+- * the Asterisk project. Please do not directly contact
+- * any of the maintainers of this project for assistance;
+- * the project provides a web site, mailing lists and IRC
+- * channels for your use.
+- *
+- * This program is free software, distributed under the terms of
+- * the GNU General Public License Version 2 as published by the
+- * Free Software Foundation. See the LICENSE file included with
+- * this program for more details.
+- *
+- * In addition, when this program is distributed with Asterisk in
+- * any form that would qualify as a 'combined work' or as a
+- * 'derivative work' (but not mere aggregation), you can redistribute
+- * and/or modify the combination under the terms of the license
+- * provided with that copy of Asterisk, instead of the license
+- * terms granted here.
+- */
+-
+-#ifndef _PRI_TIMERS_H
+-#define _PRI_TIMERS_H
+-
+-/* -1 means we dont currently support the timer/counter */
+-#define PRI_TIMERS_DEFAULT { \
+- 3, /* N200 */ \
+- -1, /* N201 */ \
+- 3, /* N202 */ \
+- 7, /* K */ \
+- 1000, /* T200 */ \
+- -1, /* T201 */ \
+- 10000, /* T202 */ \
+- 10000, /* T203 */ \
+- -1, /* T300 */ \
+- -1, /* T301 */ \
+- -1, /* T302 */ \
+- -1, /* T303 */ \
+- -1, /* T304 */ \
+- 30000, /* T305 */ \
+- -1, /* T306 */ \
+- -1, /* T307 */ \
+- 4000, /* T308 */ \
+- -1, /* T309 */ \
+- -1, /* T310 */ \
+- 4000, /* T313 */ \
+- -1, /* T314 */ \
+- -1, /* T316 */ \
+- -1, /* T317 */ \
+- -1, /* T318 */ \
+- -1, /* T319 */ \
+- -1, /* T320 */ \
+- -1, /* T321 */ \
+- -1, /* T322 */ \
+- 2500, /* TM20 - Q.921 Appendix IV */ \
+- 3, /* NM20 - Q.921 Appendix IV */ \
+- }
+-
+-/* XXX Only our default timers are setup now XXX */
+-#define PRI_TIMERS_UNKNOWN PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_NI2 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_DMS100 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_LUCENT5E PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_ATT4ESS PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_EUROISDN_E1 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_EUROISDN_T1 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_NI1 PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_GR303_EOC PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_GR303_TMC PRI_TIMERS_DEFAULT
+-#define PRI_TIMERS_QSIG PRI_TIMERS_DEFAULT
+-#define __PRI_TIMERS_GR303_EOC_INT PRI_TIMERS_DEFAULT
+-#define __PRI_TIMERS_GR303_TMC_INT PRI_TIMERS_DEFAULT
+-
+-#define PRI_TIMERS_ALL { PRI_TIMERS_UNKNOWN, \
+- PRI_TIMERS_NI2, \
+- PRI_TIMERS_DMS100, \
+- PRI_TIMERS_LUCENT5E, \
+- PRI_TIMERS_ATT4ESS, \
+- PRI_TIMERS_EUROISDN_E1, \
+- PRI_TIMERS_EUROISDN_T1, \
+- PRI_TIMERS_NI1, \
+- PRI_TIMERS_QSIG, \
+- PRI_TIMERS_GR303_EOC, \
+- PRI_TIMERS_GR303_TMC, \
+- __PRI_TIMERS_GR303_EOC_INT, \
+- __PRI_TIMERS_GR303_TMC_INT, \
+- }
+-
+-#endif
+Index: .version
+===================================================================
+--- a/.version (.../tags/1.4.10.2) (revision 1357)
++++ b/.version (.../branches/1.4) (revision 1357)
+@@ -1 +1 @@
+-1.4.10.2
++1.4.10.2-r1357
+Index: prisched.c
+===================================================================
+--- a/prisched.c (.../tags/1.4.10.2) (revision 1357)
++++ b/prisched.c (.../branches/1.4) (revision 1357)
+@@ -33,25 +33,43 @@
+ #include "pri_internal.h"
+
+
++/*! \brief The maximum number of timers that were active at once. */
+ static int maxsched = 0;
+
+ /* Scheduler routines */
+-int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data)
++
++/*!
++ * \brief Start a timer to schedule an event.
++ *
++ * \param ctrl D channel controller.
++ * \param ms Number of milliseconds to scheduled event.
++ * \param function Callback function to call when timeout.
++ * \param data Value to give callback function when timeout.
++ *
++ * \retval 0 if scheduler table is full and could not schedule the event.
++ * \retval id Scheduled event id.
++ */
++int pri_schedule_event(struct pri *ctrl, int ms, void (*function)(void *data), void *data)
+ {
+ int x;
+ struct timeval tv;
++
+ /* Scheduling runs on master channels only */
+- while (pri->master)
+- pri = pri->master;
+- for (x=1;x<MAX_SCHED;x++)
+- if (!pri->pri_sched[x].callback)
++ while (ctrl->master) {
++ ctrl = ctrl->master;
++ }
++ for (x = 0; x < MAX_SCHED; ++x) {
++ if (!ctrl->pri_sched[x].callback) {
+ break;
++ }
++ }
+ if (x == MAX_SCHED) {
+- pri_error(pri, "No more room in scheduler\n");
+- return -1;
++ pri_error(ctrl, "No more room in scheduler\n");
++ return 0;
+ }
+- if (x > maxsched)
+- maxsched = x;
++ if (x >= maxsched) {
++ maxsched = x + 1;
++ }
+ gettimeofday(&tv, NULL);
+ tv.tv_sec += ms / 1000;
+ tv.tv_usec += (ms % 1000) * 1000;
+@@ -59,71 +77,110 @@
+ tv.tv_usec -= 1000000;
+ tv.tv_sec += 1;
+ }
+- pri->pri_sched[x].when = tv;
+- pri->pri_sched[x].callback = function;
+- pri->pri_sched[x].data = data;
+- return x;
++ ctrl->pri_sched[x].when = tv;
++ ctrl->pri_sched[x].callback = function;
++ ctrl->pri_sched[x].data = data;
++ return x + 1;
+ }
+
+-struct timeval *pri_schedule_next(struct pri *pri)
++/*!
++ * \brief Determine the time of the next scheduled event to expire.
++ *
++ * \param ctrl D channel controller.
++ *
++ * \return Time of the next scheduled event to expire or NULL if no timers active.
++ */
++struct timeval *pri_schedule_next(struct pri *ctrl)
+ {
+ struct timeval *closest = NULL;
+ int x;
+- /* Check subchannels */
+- if (pri->subchannel)
+- closest = pri_schedule_next(pri->subchannel);
+- for (x=1;x<MAX_SCHED;x++) {
+- if (pri->pri_sched[x].callback &&
+- (!closest || (closest->tv_sec > pri->pri_sched[x].when.tv_sec) ||
+- ((closest->tv_sec == pri->pri_sched[x].when.tv_sec) &&
+- (closest->tv_usec > pri->pri_sched[x].when.tv_usec))))
+- closest = &pri->pri_sched[x].when;
++
++ /* Scheduling runs on master channels only */
++ while (ctrl->master) {
++ ctrl = ctrl->master;
+ }
++ for (x = 0; x < MAX_SCHED; ++x) {
++ if (ctrl->pri_sched[x].callback && (!closest
++ || (closest->tv_sec > ctrl->pri_sched[x].when.tv_sec)
++ || ((closest->tv_sec == ctrl->pri_sched[x].when.tv_sec)
++ && (closest->tv_usec > ctrl->pri_sched[x].when.tv_usec)))) {
++ closest = &ctrl->pri_sched[x].when;
++ }
++ }
+ return closest;
+ }
+
+-static pri_event *__pri_schedule_run(struct pri *pri, struct timeval *tv)
++/*!
++ * \internal
++ * \brief Run all expired timers or return an event generated by an expired timer.
++ *
++ * \param ctrl D channel controller.
++ * \param tv Current time.
++ *
++ * \return Event for upper layer to process or NULL if all expired timers run.
++ */
++static pri_event *__pri_schedule_run(struct pri *ctrl, struct timeval *tv)
+ {
+ int x;
+ void (*callback)(void *);
+ void *data;
+- pri_event *e;
+- if (pri->subchannel) {
+- if ((e = __pri_schedule_run(pri->subchannel, tv))) {
+- return e;
++
++ /* Scheduling runs on master channels only */
++ while (ctrl->master) {
++ ctrl = ctrl->master;
++ }
++ for (x = 0; x < MAX_SCHED; ++x) {
++ if (ctrl->pri_sched[x].callback && ((ctrl->pri_sched[x].when.tv_sec < tv->tv_sec)
++ || ((ctrl->pri_sched[x].when.tv_sec == tv->tv_sec)
++ && (ctrl->pri_sched[x].when.tv_usec <= tv->tv_usec)))) {
++ /* This timer has expired. */
++ ctrl->schedev = 0;
++ callback = ctrl->pri_sched[x].callback;
++ data = ctrl->pri_sched[x].data;
++ ctrl->pri_sched[x].callback = NULL;
++ callback(data);
++ if (ctrl->schedev) {
++ return &ctrl->ev;
++ }
+ }
+ }
+- for (x=1;x<MAX_SCHED;x++) {
+- if (pri->pri_sched[x].callback &&
+- ((pri->pri_sched[x].when.tv_sec < tv->tv_sec) ||
+- ((pri->pri_sched[x].when.tv_sec == tv->tv_sec) &&
+- (pri->pri_sched[x].when.tv_usec <= tv->tv_usec)))) {
+- pri->schedev = 0;
+- callback = pri->pri_sched[x].callback;
+- data = pri->pri_sched[x].data;
+- pri->pri_sched[x].callback = NULL;
+- pri->pri_sched[x].data = NULL;
+- callback(data);
+- if (pri->schedev)
+- return &pri->ev;
+- }
+- }
+ return NULL;
+ }
+
+-pri_event *pri_schedule_run(struct pri *pri)
++/*!
++ * \brief Run all expired timers or return an event generated by an expired timer.
++ *
++ * \param ctrl D channel controller.
++ *
++ * \return Event for upper layer to process or NULL if all expired timers run.
++ */
++pri_event *pri_schedule_run(struct pri *ctrl)
+ {
+ struct timeval tv;
++
+ gettimeofday(&tv, NULL);
+- return __pri_schedule_run(pri, &tv);
++ return __pri_schedule_run(ctrl, &tv);
+ }
+
+-
+-void pri_schedule_del(struct pri *pri,int id)
++/*!
++ * \brief Delete a scheduled event.
++ *
++ * \param ctrl D channel controller.
++ * \param id Scheduled event id to delete.
++ * 0 is a disabled/unscheduled event id that is ignored.
++ * 1 - MAX_SCHED is a valid event id.
++ *
++ * \return Nothing
++ */
++void pri_schedule_del(struct pri *ctrl, int id)
+ {
+- while (pri->master)
+- pri = pri->master;
+- if ((id >= MAX_SCHED) || (id < 0))
+- pri_error(pri, "Asked to delete sched id %d???\n", id);
+- pri->pri_sched[id].callback = NULL;
++ /* Scheduling runs on master channels only */
++ while (ctrl->master) {
++ ctrl = ctrl->master;
++ }
++ if (0 < id && id <= MAX_SCHED) {
++ ctrl->pri_sched[id - 1].callback = NULL;
++ } else if (id) {
++ pri_error(ctrl, "Asked to delete sched id %d???\n", id);
++ }
+ }
+Index: rose_qsig_mwi.c
+===================================================================
+--- a/rose_qsig_mwi.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_qsig_mwi.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,790 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief Q.SIG ROSE SS-MWI-Operations
++ *
++ * SS-MWI-Operations ECMA-242 Annex E Table E.1
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Encode the MsgCentreId type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param msg_centre_id
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_MsgCentreId(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct roseQsigMsgCentreId *msg_centre_id)
++{
++ unsigned char *seq_len;
++
++ switch (msg_centre_id->type) {
++ case 0: /* integer */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ msg_centre_id->u.integer));
++ break;
++ case 1: /* partyNumber */
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &msg_centre_id->u.number));
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++ break;
++ case 2: /* numericString */
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ msg_centre_id->u.str, sizeof(msg_centre_id->u.str) - 1));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown MsgCentreId type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the MWIActivate invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigMWIActivateArg *mwi_activate;
++ unsigned char *seq_len;
++ unsigned char *explicit_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ mwi_activate = &args->qsig.MWIActivate;
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &mwi_activate->served_user_number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ mwi_activate->basic_service));
++ if (mwi_activate->msg_centre_id_present) {
++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end,
++ &mwi_activate->msg_centre_id));
++ }
++ if (mwi_activate->number_of_messages_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ mwi_activate->number_of_messages));
++ }
++ if (mwi_activate->originating_number.length) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &mwi_activate->originating_number));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++ if (mwi_activate->timestamp_present) {
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME,
++ mwi_activate->timestamp, sizeof(mwi_activate->timestamp) - 1));
++ }
++ if (mwi_activate->priority_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5,
++ mwi_activate->priority));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the MWIDeactivate invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigMWIDeactivateArg *mwi_deactivate;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ mwi_deactivate = &args->qsig.MWIDeactivate;
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &mwi_deactivate->served_user_number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ mwi_deactivate->basic_service));
++ if (mwi_deactivate->msg_centre_id_present) {
++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end,
++ &mwi_deactivate->msg_centre_id));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the MWIInterrogate invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigMWIInterrogateArg *mwi_interrogate;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ mwi_interrogate = &args->qsig.MWIInterrogate;
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &mwi_interrogate->served_user_number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ mwi_interrogate->basic_service));
++ if (mwi_interrogate->msg_centre_id_present) {
++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end,
++ &mwi_interrogate->msg_centre_id));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the MWIInterrogateResElt type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param record
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_MWIInterrogateResElt(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseQsigMWIInterrogateResElt *record)
++{
++ unsigned char *seq_len;
++ unsigned char *explicit_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, record->basic_service));
++ if (record->msg_centre_id_present) {
++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end,
++ &record->msg_centre_id));
++ }
++ if (record->number_of_messages_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ record->number_of_messages));
++ }
++ if (record->originating_number.length) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &record->originating_number));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++ if (record->timestamp_present) {
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME,
++ record->timestamp, sizeof(record->timestamp) - 1));
++ }
++ if (record->priority_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5,
++ record->priority));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the MWIInterrogate result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args)
++{
++ unsigned index;
++ unsigned char *seq_len;
++ const struct roseQsigMWIInterrogateRes *mwi_interrogate;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ mwi_interrogate = &args->qsig.MWIInterrogate;
++ for (index = 0; index < mwi_interrogate->num_records; ++index) {
++ ASN1_CALL(pos, rose_enc_qsig_MWIInterrogateResElt(ctrl, pos, end,
++ ASN1_TAG_SEQUENCE, &mwi_interrogate->list[index]));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the MsgCentreId argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param msg_centre_id Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_MsgCentreId(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigMsgCentreId *msg_centre_id)
++{
++ int32_t value;
++ size_t str_len;
++ int length;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s MsgCentreId\n", name);
++ }
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ msg_centre_id->type = 0; /* integer */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "integer", tag, pos, end, &value));
++ msg_centre_id->u.integer = value;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ msg_centre_id->type = 1; /* partyNumber */
++
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, explicit_end,
++ &msg_centre_id->u.number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ msg_centre_id->type = 2; /* numericString */
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "numericString", tag, pos, end,
++ sizeof(msg_centre_id->u.str), msg_centre_id->u.str, &str_len));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG MWIActivate invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ size_t str_len;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigMWIActivateArg *mwi_activate;
++
++ mwi_activate = &args->qsig.MWIActivate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIActivateArg %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &mwi_activate->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ mwi_activate->basic_service = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ mwi_activate->msg_centre_id_present = 0;
++ mwi_activate->number_of_messages_present = 0;
++ mwi_activate->originating_number.length = 0;
++ mwi_activate->timestamp_present = 0;
++ mwi_activate->priority_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos,
++ seq_end, &mwi_activate->msg_centre_id));
++ mwi_activate->msg_centre_id_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "nbOfMessages", tag, pos, seq_end,
++ &value));
++ mwi_activate->number_of_messages = value;
++ mwi_activate->number_of_messages_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ /* Must be constructed but we will not check for it for simplicity. */
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "originatingNr", tag, pos,
++ explicit_end, &mwi_activate->originating_number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_TYPE_GENERALIZED_TIME:
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "timestamp", tag, pos, end,
++ sizeof(mwi_activate->timestamp), mwi_activate->timestamp, &str_len));
++ mwi_activate->timestamp_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "priority", tag, pos, seq_end, &value));
++ mwi_activate->priority = value;
++ mwi_activate->priority_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 6:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG MWIDeactivate invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigMWIDeactivateArg *mwi_deactivate;
++
++ mwi_deactivate = &args->qsig.MWIDeactivate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIDeactivateArg %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &mwi_deactivate->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ mwi_deactivate->basic_service = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ mwi_deactivate->msg_centre_id_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos,
++ seq_end, &mwi_deactivate->msg_centre_id));
++ mwi_deactivate->msg_centre_id_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG MWIInterrogate invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigMWIInterrogateArg *mwi_interrogate;
++
++ mwi_interrogate = &args->qsig.MWIInterrogate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIInterrogateArg %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &mwi_interrogate->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ mwi_interrogate->basic_service = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ mwi_interrogate->msg_centre_id_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos,
++ seq_end, &mwi_interrogate->msg_centre_id));
++ mwi_interrogate->msg_centre_id_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the MWIInterrogateResElt argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param record Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_MWIInterrogateResElt(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigMWIInterrogateResElt *record)
++{
++ int32_t value;
++ size_t str_len;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIInterrogateResElt %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ record->basic_service = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ record->msg_centre_id_present = 0;
++ record->number_of_messages_present = 0;
++ record->originating_number.length = 0;
++ record->timestamp_present = 0;
++ record->priority_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos,
++ seq_end, &record->msg_centre_id));
++ record->msg_centre_id_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "nbOfMessages", tag, pos, seq_end,
++ &value));
++ record->number_of_messages = value;
++ record->number_of_messages_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ /* Must be constructed but we will not check for it for simplicity. */
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "originatingNr", tag, pos,
++ explicit_end, &record->originating_number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_TYPE_GENERALIZED_TIME:
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "timestamp", tag, pos, end,
++ sizeof(record->timestamp), record->timestamp, &str_len));
++ record->timestamp_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "priority", tag, pos, seq_end, &value));
++ record->priority = value;
++ record->priority_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 6:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG MWIInterrogate result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigMWIInterrogateRes *mwi_interrogate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " MWIInterrogateRes %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ mwi_interrogate = &args->qsig.MWIInterrogate;
++
++ mwi_interrogate->num_records = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ if (mwi_interrogate->num_records < ARRAY_LEN(mwi_interrogate->list)) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_qsig_MWIInterrogateResElt(ctrl, "listEntry", tag,
++ pos, seq_end, &mwi_interrogate->list[mwi_interrogate->num_records]));
++ ++mwi_interrogate->num_records;
++ } else {
++ /* Too many records */
++ return NULL;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++
++/* ------------------------------------------------------------------- */
++/* end rose_qsig_mwi.c */
+
+Property changes on: rose_qsig_mwi.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rosetest.c
+===================================================================
+--- a/rosetest.c (.../tags/1.4.10.2) (revision 0)
++++ b/rosetest.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,2473 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief ROSE encode/decode test program
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++
++
++/* ------------------------------------------------------------------- */
++
++
++static const struct fac_extension_header fac_headers[] = {
++/* *INDENT-OFF* */
++ {
++ .nfe_present = 0,
++ },
++ {
++ .nfe_present = 1,
++ .nfe.source_entity = 1,
++ .nfe.destination_entity = 1,
++ },
++ {
++ .nfe_present = 1,
++ .nfe.source_entity = 1,
++ .nfe.source_number.plan = 4,
++ .nfe.source_number.length = 4,
++ .nfe.source_number.str = "9834",
++ .nfe.destination_entity = 1,
++ .nfe.destination_number.plan = 4,
++ .nfe.destination_number.length = 4,
++ .nfe.destination_number.str = "9834",
++ },
++ {
++ .nfe_present = 1,
++ .nfe.source_entity = 1,
++ .nfe.destination_entity = 1,
++ .npp_present = 1,
++ .npp = 19,
++ .interpretation_present = 1,
++ .interpretation = 2,
++ },
++/* *INDENT-ON* */
++};
++
++
++static const struct rose_message rose_etsi_msgs[] = {
++/* *INDENT-OFF* */
++ /* Error messages */
++ {
++ .type = ROSE_COMP_TYPE_ERROR,
++ .component.error.invoke_id = 82,
++ .component.error.code = ROSE_ERROR_Div_SpecialServiceNr,
++ },
++ {
++ .type = ROSE_COMP_TYPE_ERROR,
++ .component.error.invoke_id = 8,
++ .component.error.code = ROSE_ERROR_ECT_LinkIdNotAssignedByNetwork,
++ },
++
++ /* Reject messages */
++ {
++ .type = ROSE_COMP_TYPE_REJECT,
++ .component.reject.code = ROSE_REJECT_Gen_BadlyStructuredComponent,
++ },
++ {
++ .type = ROSE_COMP_TYPE_REJECT,
++ .component.reject.invoke_id_present = 1,
++ .component.reject.invoke_id = 10,
++ .component.reject.code = ROSE_REJECT_Inv_InitiatorReleasing,
++ },
++ {
++ .type = ROSE_COMP_TYPE_REJECT,
++ .component.reject.invoke_id_present = 1,
++ .component.reject.invoke_id = 11,
++ .component.reject.code = ROSE_REJECT_Res_MistypedResult,
++ },
++ {
++ .type = ROSE_COMP_TYPE_REJECT,
++ .component.reject.invoke_id_present = 1,
++ .component.reject.invoke_id = 12,
++ .component.reject.code = ROSE_REJECT_Err_ErrorResponseUnexpected,
++ },
++
++ /* Anonymous result or result without any arguments. */
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_None,
++ .component.result.invoke_id = 9,
++ },
++
++ /* Advice Of Charge (AOC) */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ChargingRequest,
++ .component.invoke.invoke_id = 98,
++ .component.invoke.args.etsi.ChargingRequest.charging_case = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 99,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.special_charging_code = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 100,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.currency = "Dollars",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.currency = 7,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.multiplier = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.charging_type = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.length = 8,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.scale = 4,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 101,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.currency = "Dollars",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.currency = 7,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.multiplier = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.charging_type = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.length = 8,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.scale = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.granularity_present = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.granularity.length = 20,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.granularity.scale = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 102,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 2,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.currency = "Euros",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.currency = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.multiplier = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 103,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 3,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.currency = "Yen",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.amount.currency = 300,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.amount.multiplier = 5,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.unit = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 104,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 2,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 2,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.currency = "Euros",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.currency = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.multiplier = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].currency_type = 3,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.currency = "Yen",
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.amount.currency = 300,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.amount.multiplier = 5,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.unit = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 105,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 4,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ChargingRequest,
++ .component.result.invoke_id = 106,
++ .component.result.args.etsi.ChargingRequest.type = 0,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4,
++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 5,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCSCurrency,
++ .component.invoke.invoke_id = 107,
++ .component.invoke.args.etsi.AOCSCurrency.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCSCurrency,
++ .component.invoke.invoke_id = 108,
++ .component.invoke.args.etsi.AOCSCurrency.type = 1,
++ .component.invoke.args.etsi.AOCSCurrency.currency_info.num_records = 1,
++ .component.invoke.args.etsi.AOCSCurrency.currency_info.list[0].charged_item = 3,
++ .component.invoke.args.etsi.AOCSCurrency.currency_info.list[0].currency_type = 4,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCSSpecialArr,
++ .component.invoke.invoke_id = 109,
++ .component.invoke.args.etsi.AOCSSpecialArr.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCSSpecialArr,
++ .component.invoke.invoke_id = 110,
++ .component.invoke.args.etsi.AOCSSpecialArr.type = 1,
++ .component.invoke.args.etsi.AOCSSpecialArr.special_arrangement = 9,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency,
++ .component.invoke.invoke_id = 111,
++ .component.invoke.args.etsi.AOCDCurrency.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency,
++ .component.invoke.invoke_id = 112,
++ .component.invoke.args.etsi.AOCDCurrency.type = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency,
++ .component.invoke.invoke_id = 113,
++ .component.invoke.args.etsi.AOCDCurrency.type = 2,
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCDCurrency.specific.type_of_charging_info = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency,
++ .component.invoke.invoke_id = 114,
++ .component.invoke.args.etsi.AOCDCurrency.type = 2,
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCDCurrency.specific.type_of_charging_info = 1,
++ .component.invoke.args.etsi.AOCDCurrency.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCDCurrency.specific.billing_id = 2,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 115,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 116,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 117,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 118,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 0,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].number_of_units = 8523,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.billing_id = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 119,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit_present = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit = 13,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 120,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 0,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].number_of_units = 8523,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit_present = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit = 13,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit,
++ .component.invoke.invoke_id = 121,
++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 2,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].not_available = 0,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].number_of_units = 8523,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].type_of_unit_present = 1,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].type_of_unit = 13,
++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 122,
++ .component.invoke.args.etsi.AOCECurrency.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 123,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 124,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.id = -37,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 125,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.number.plan = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.number.length = 7,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.number.str = "5551212",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 126,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 127,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.id = -37,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 128,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCECurrency,
++ .component.invoke.invoke_id = 129,
++ .component.invoke.args.etsi.AOCECurrency.type = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs",
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id = 2,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.id = -37,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 130,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 131,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 132,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id = -37,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 133,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 134,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id = -37,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 135,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit,
++ .component.invoke.invoke_id = 136,
++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id = 2,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0,
++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id = -37,
++ },
++
++ /* Call diversion */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ActivationDiversion,
++ .component.invoke.invoke_id = 67,
++ .component.invoke.linked_id_present = 1,
++ .component.invoke.linked_id = 27,
++ .component.invoke.args.etsi.ActivationDiversion.procedure = 2,
++ .component.invoke.args.etsi.ActivationDiversion.basic_service = 3,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.plan = 4,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.length = 4,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.str = "1803",
++ .component.invoke.args.etsi.ActivationDiversion.served_user_number.plan = 4,
++ .component.invoke.args.etsi.ActivationDiversion.served_user_number.length = 4,
++ .component.invoke.args.etsi.ActivationDiversion.served_user_number.str = "5398",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ActivationDiversion,
++ .component.invoke.invoke_id = 68,
++ .component.invoke.args.etsi.ActivationDiversion.procedure = 1,
++ .component.invoke.args.etsi.ActivationDiversion.basic_service = 5,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.plan = 4,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.length = 4,
++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.str = "1803",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_ActivationDiversion,
++ .component.result.invoke_id = 69,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DeactivationDiversion,
++ .component.invoke.invoke_id = 70,
++ .component.invoke.args.etsi.DeactivationDiversion.procedure = 1,
++ .component.invoke.args.etsi.DeactivationDiversion.basic_service = 5,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_DeactivationDiversion,
++ .component.result.invoke_id = 71,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ActivationStatusNotificationDiv,
++ .component.invoke.invoke_id = 72,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.procedure = 1,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.basic_service = 5,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.forwarded_to.number.plan = 4,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.forwarded_to.number.length = 4,
++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.forwarded_to.number.str = "1803",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DeactivationStatusNotificationDiv,
++ .component.invoke.invoke_id = 73,
++ .component.invoke.args.etsi.DeactivationStatusNotificationDiv.procedure = 1,
++ .component.invoke.args.etsi.DeactivationStatusNotificationDiv.basic_service = 5,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_InterrogationDiversion,
++ .component.invoke.invoke_id = 74,
++ .component.invoke.args.etsi.InterrogationDiversion.procedure = 1,
++ .component.invoke.args.etsi.InterrogationDiversion.basic_service = 5,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_InterrogationDiversion,
++ .component.invoke.invoke_id = 75,
++ .component.invoke.args.etsi.InterrogationDiversion.procedure = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_InterrogationDiversion,
++ .component.result.invoke_id = 76,
++ .component.result.args.etsi.InterrogationDiversion.num_records = 2,
++ .component.result.args.etsi.InterrogationDiversion.list[0].procedure = 2,
++ .component.result.args.etsi.InterrogationDiversion.list[0].basic_service = 5,
++ .component.result.args.etsi.InterrogationDiversion.list[0].forwarded_to.number.plan = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[0].forwarded_to.number.length = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[0].forwarded_to.number.str = "1803",
++ .component.result.args.etsi.InterrogationDiversion.list[1].procedure = 1,
++ .component.result.args.etsi.InterrogationDiversion.list[1].basic_service = 3,
++ .component.result.args.etsi.InterrogationDiversion.list[1].forwarded_to.number.plan = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[1].forwarded_to.number.length = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[1].forwarded_to.number.str = "1903",
++ .component.result.args.etsi.InterrogationDiversion.list[1].served_user_number.plan = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[1].served_user_number.length = 4,
++ .component.result.args.etsi.InterrogationDiversion.list[1].served_user_number.str = "5398",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 77,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 3,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 5,
++ .component.invoke.args.etsi.DiversionInformation.served_user_subaddress.type = 1,
++ .component.invoke.args.etsi.DiversionInformation.served_user_subaddress.length = 4,
++ .component.invoke.args.etsi.DiversionInformation.served_user_subaddress.u.nsap = "6492",
++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 0,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.screening_indicator = 3,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.plan = 4,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.length = 4,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.str = "1803",
++ .component.invoke.args.etsi.DiversionInformation.original_called_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.original_called.presentation = 1,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting.presentation = 2,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting_reason_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting_reason = 3,
++ .component.invoke.args.etsi.DiversionInformation.q931ie.length = 5,
++ .component.invoke.args.etsi.DiversionInformation.q931ie_contents = "79828",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 78,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 3,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 5,
++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 1,
++ .component.invoke.args.etsi.DiversionInformation.original_called_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.original_called.presentation = 2,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.last_diverting.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 79,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 2,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 3,
++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 80,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 3,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 5,
++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1,
++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 3,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.screening_indicator = 2,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.plan = 4,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.length = 4,
++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.str = "1803",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 81,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 2,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 4,
++ .component.invoke.args.etsi.DiversionInformation.q931ie.length = 5,
++ .component.invoke.args.etsi.DiversionInformation.q931ie_contents = "79828",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DiversionInformation,
++ .component.invoke.invoke_id = 82,
++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 2,
++ .component.invoke.args.etsi.DiversionInformation.basic_service = 4,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallDeflection,
++ .component.invoke.invoke_id = 83,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.plan = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.length = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.str = "1803",
++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1,
++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallDeflection,
++ .component.invoke.invoke_id = 84,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.plan = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.length = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.str = "1803",
++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1,
++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallDeflection,
++ .component.invoke.invoke_id = 85,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.plan = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.length = 4,
++ .component.invoke.args.etsi.CallDeflection.deflection.number.str = "1803",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_CallDeflection,
++ .component.result.invoke_id = 86,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallRerouting,
++ .component.invoke.invoke_id = 87,
++ .component.invoke.args.etsi.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.etsi.CallRerouting.rerouting_counter = 2,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.plan = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.length = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.str = "1803",
++ .component.invoke.args.etsi.CallRerouting.q931ie.length = 129,
++ .component.invoke.args.etsi.CallRerouting.q931ie_contents =
++ "YEHAW."
++ " The quick brown fox jumped over the lazy dog test."
++ " Now is the time for all good men to come to the aid of their country.",
++ .component.invoke.args.etsi.CallRerouting.last_rerouting.presentation = 1,
++ .component.invoke.args.etsi.CallRerouting.subscription_option = 2,
++ .component.invoke.args.etsi.CallRerouting.calling_subaddress.type = 1,
++ .component.invoke.args.etsi.CallRerouting.calling_subaddress.length = 4,
++ .component.invoke.args.etsi.CallRerouting.calling_subaddress.u.nsap = "6492",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallRerouting,
++ .component.invoke.invoke_id = 88,
++ .component.invoke.args.etsi.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.etsi.CallRerouting.rerouting_counter = 2,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.plan = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.length = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.str = "1803",
++ .component.invoke.args.etsi.CallRerouting.q931ie.length = 2,
++ .component.invoke.args.etsi.CallRerouting.q931ie_contents = "RT",
++ .component.invoke.args.etsi.CallRerouting.last_rerouting.presentation = 1,
++ .component.invoke.args.etsi.CallRerouting.subscription_option = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_CallRerouting,
++ .component.invoke.invoke_id = 89,
++ .component.invoke.args.etsi.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.etsi.CallRerouting.rerouting_counter = 2,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.plan = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.length = 4,
++ .component.invoke.args.etsi.CallRerouting.called_address.number.str = "1803",
++ .component.invoke.args.etsi.CallRerouting.q931ie.length = 2,
++ .component.invoke.args.etsi.CallRerouting.q931ie_contents = "RT",
++ .component.invoke.args.etsi.CallRerouting.last_rerouting.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_CallRerouting,
++ .component.result.invoke_id = 90,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_InterrogateServedUserNumbers,
++ .component.invoke.invoke_id = 91,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_InterrogateServedUserNumbers,
++ .component.result.invoke_id = 92,
++ .component.result.args.etsi.InterrogateServedUserNumbers.num_records = 2,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[0].plan = 4,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[0].length = 4,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[0].str = "1803",
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[1].plan = 4,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[1].length = 4,
++ .component.result.args.etsi.InterrogateServedUserNumbers.number[1].str = "5786",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation1,
++ .component.invoke.invoke_id = 93,
++ .component.invoke.args.etsi.DivertingLegInformation1.diversion_reason = 4,
++ .component.invoke.args.etsi.DivertingLegInformation1.subscription_option = 1,
++ .component.invoke.args.etsi.DivertingLegInformation1.diverted_to_present = 1,
++ .component.invoke.args.etsi.DivertingLegInformation1.diverted_to.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation1,
++ .component.invoke.invoke_id = 94,
++ .component.invoke.args.etsi.DivertingLegInformation1.diversion_reason = 4,
++ .component.invoke.args.etsi.DivertingLegInformation1.subscription_option = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation2,
++ .component.invoke.invoke_id = 95,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_counter = 3,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_reason = 2,
++ .component.invoke.args.etsi.DivertingLegInformation2.diverting_present = 1,
++ .component.invoke.args.etsi.DivertingLegInformation2.diverting.presentation = 2,
++ .component.invoke.args.etsi.DivertingLegInformation2.original_called_present = 1,
++ .component.invoke.args.etsi.DivertingLegInformation2.original_called.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation2,
++ .component.invoke.invoke_id = 96,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_counter = 3,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_reason = 2,
++ .component.invoke.args.etsi.DivertingLegInformation2.original_called_present = 1,
++ .component.invoke.args.etsi.DivertingLegInformation2.original_called.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation2,
++ .component.invoke.invoke_id = 97,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_counter = 1,
++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_reason = 2,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation3,
++ .component.invoke.invoke_id = 98,
++ .component.invoke.args.etsi.DivertingLegInformation3.presentation_allowed_indicator = 1,
++ },
++
++ /* Explicit Call Transfer (ECT) */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctExecute,
++ .component.invoke.invoke_id = 54,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_ExplicitEctExecute,
++ .component.invoke.invoke_id = 55,
++ .component.invoke.args.etsi.ExplicitEctExecute.link_id = 23,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_RequestSubaddress,
++ .component.invoke.invoke_id = 56,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_SubaddressTransfer,
++ .component.invoke.invoke_id = 57,
++ .component.invoke.args.etsi.SubaddressTransfer.subaddress.type = 1,
++ .component.invoke.args.etsi.SubaddressTransfer.subaddress.length = 4,
++ .component.invoke.args.etsi.SubaddressTransfer.subaddress.u.nsap = "6492",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctLinkIdRequest,
++ .component.invoke.invoke_id = 58,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_EctLinkIdRequest,
++ .component.result.invoke_id = 59,
++ .component.result.args.etsi.EctLinkIdRequest.link_id = 76,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 60,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 1,
++ .component.invoke.args.etsi.EctInform.redirection.presentation = 0,
++ .component.invoke.args.etsi.EctInform.redirection.number.plan = 8,
++ .component.invoke.args.etsi.EctInform.redirection.number.length = 4,
++ .component.invoke.args.etsi.EctInform.redirection.number.str = "6229",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 61,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 1,
++ .component.invoke.args.etsi.EctInform.redirection.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 62,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 1,
++ .component.invoke.args.etsi.EctInform.redirection.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 63,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 1,
++ .component.invoke.args.etsi.EctInform.redirection.presentation = 3,
++ .component.invoke.args.etsi.EctInform.redirection.number.plan = 8,
++ .component.invoke.args.etsi.EctInform.redirection.number.length = 4,
++ .component.invoke.args.etsi.EctInform.redirection.number.str = "3340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctInform,
++ .component.invoke.invoke_id = 64,
++ .component.invoke.args.etsi.EctInform.status = 1,
++ .component.invoke.args.etsi.EctInform.redirection_present = 0,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_ETSI_EctLoopTest,
++ .component.invoke.invoke_id = 65,
++ .component.invoke.args.etsi.EctLoopTest.call_transfer_id = 7,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_ETSI_EctLoopTest,
++ .component.result.invoke_id = 66,
++ .component.result.args.etsi.EctLoopTest.loop_result = 2,
++ },
++/* *INDENT-ON* */
++};
++
++static unsigned char rose_etsi_indefinite_len[] = {
++/* *INDENT-OFF* */
++/*
++ * Context Specific/C [1 0x01] <A1> Len:24 <80>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <44>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <07>
++ * Sequence/C(48 0x30) <30> Len:16 <80>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <01>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <05>
++ * Sequence/C(48 0x30) <30> Len:6 <80>
++ * Context Specific [4 0x04] <84> Len:4 <80>
++ * <31 38 30 33>
++ * 0x00, 0x00,
++ * 0x00, 0x00,
++ * NULL(5 0x05) <05> Len:0 <00>
++ * 0x00, 0x00,
++ * 0x00, 0x00
++ */
++ 0x91,
++ 0xA1, 0x80,
++ 0x02, 0x01,
++ 0x44,
++ 0x02, 0x01,
++ 0x07,
++ 0x30, 0x80,
++ 0x0A, 0x01,
++ 0x01,
++ 0x0A, 0x01,
++ 0x05,
++ 0x30, 0x80,
++ 0x84, 0x80,
++ 0x31, 0x38, 0x30, 0x33,
++ 0x00, 0x00,
++ 0x00, 0x00,
++ 0x05, 0x00,
++ 0x00, 0x00,
++ 0x00, 0x00,
++ 0x00, 0x00
++/* *INDENT-ON* */
++};
++
++static unsigned char rose_etsi_unused_indefinite_len[] = {
++/* *INDENT-OFF* */
++/*
++ * Context Specific/C [1 0x01] <A1> Len:24 <80>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <44>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <06> -- EctExecute
++ * Sequence/C(48 0x30) <30> Len:16 <80>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <01>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <05>
++ * Sequence/C(48 0x30) <30> Len:6 <80>
++ * Context Specific [4 0x04] <84> Len:4 <80>
++ * <31 38 30 33>
++ * 0x00, 0x00,
++ * 0x00, 0x00,
++ * NULL(5 0x05) <05> Len:0 <00>
++ * 0x00, 0x00,
++ * 0x00, 0x00
++ */
++ 0x91,
++ 0xA1, 0x80,
++ 0x02, 0x01,
++ 0x44,
++ 0x02, 0x01,
++ 0x06,
++ 0x30, 0x80,
++ 0x0A, 0x01,
++ 0x01,
++ 0x0A, 0x01,
++ 0x05,
++ 0x30, 0x80,
++ 0x84, 0x80,
++ 0x31, 0x38, 0x30, 0x33,
++ 0x00, 0x00,
++ 0x00, 0x00,
++ 0x05, 0x00,
++ 0x00, 0x00,
++ 0x00, 0x00,
++ 0x00, 0x00
++/* *INDENT-ON* */
++};
++
++static unsigned char rose_etsi_unused[] = {
++/* *INDENT-OFF* */
++/*
++ * Context Specific/C [1 0x01] <A1> Len:24 <18>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <44>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <06> -- EctExecute
++ * Sequence/C(48 0x30) <30> Len:16 <10>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <01>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <05>
++ * Sequence/C(48 0x30) <30> Len:6 <06>
++ * Context Specific [4 0x04] <84> Len:4 <04>
++ * <31 38 30 33>
++ * NULL(5 0x05) <05> Len:0 <00>
++ */
++ 0x91,
++ 0xA1, 0x18,
++ 0x02, 0x01,
++ 0x44,
++ 0x02, 0x01,
++ 0x06,
++ 0x30, 0x10,
++ 0x0A, 0x01,
++ 0x01,
++ 0x0A, 0x01,
++ 0x05,
++ 0x30, 0x06,
++ 0x84, 0x04,
++ 0x31, 0x38, 0x30, 0x33,
++ 0x05, 0x00,
++ 0x00, 0x00
++/* *INDENT-ON* */
++};
++
++static unsigned char rose_etsi_extra[] = {
++/* *INDENT-OFF* */
++/*
++ * Context Specific/C [1 0x01] <A1> Len:24 <18>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <44>
++ * Integer(2 0x02) <02> Len:1 <01>
++ * <07>
++ * Sequence/C(48 0x30) <30> Len:16 <10>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <01>
++ * Enumerated(10 0x0A) <0A> Len:1 <01>
++ * <05>
++ * Sequence/C(48 0x30) <30> Len:6 <06>
++ * Context Specific [4 0x04] <84> Len:4 <04>
++ * <31 38 30 33>
++ * NULL(5 0x05) <05> Len:0 <00>
++ */
++ 0x91,
++ 0xA1, 0x18,
++ 0x02, 0x01,
++ 0x44,
++ 0x02, 0x01,
++ 0x07,
++ 0x30, 0x10,
++ 0x0A, 0x01,
++ 0x01,
++ 0x0A, 0x01,
++ 0x05,
++ 0x30, 0x06,
++ 0x84, 0x04,
++ 0x31, 0x38, 0x30, 0x33,
++ 0x05, 0x00,
++ 0x00, 0x00
++/* *INDENT-ON* */
++};
++
++
++static const struct rose_message rose_qsig_msgs[] = {
++/* *INDENT-OFF* */
++ /* Q.SIG Name-Operations */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 2,
++ .component.invoke.args.qsig.CallingName.name.presentation = 1,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ .component.invoke.args.qsig.CallingName.name.length = 7,
++ .component.invoke.args.qsig.CallingName.name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 3,
++ .component.invoke.args.qsig.CallingName.name.presentation = 1,
++ .component.invoke.args.qsig.CallingName.name.char_set = 3,
++ .component.invoke.args.qsig.CallingName.name.length = 7,
++ .component.invoke.args.qsig.CallingName.name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 4,
++ .component.invoke.args.qsig.CallingName.name.presentation = 2,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ .component.invoke.args.qsig.CallingName.name.length = 7,
++ .component.invoke.args.qsig.CallingName.name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 5,
++ .component.invoke.args.qsig.CallingName.name.presentation = 2,
++ .component.invoke.args.qsig.CallingName.name.char_set = 3,
++ .component.invoke.args.qsig.CallingName.name.length = 7,
++ .component.invoke.args.qsig.CallingName.name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 6,
++ .component.invoke.args.qsig.CallingName.name.presentation = 3,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallingName,
++ .component.invoke.invoke_id = 7,
++ .component.invoke.args.qsig.CallingName.name.presentation = 4,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CalledName,
++ .component.invoke.invoke_id = 8,
++ .component.invoke.args.qsig.CallingName.name.presentation = 4,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ConnectedName,
++ .component.invoke.invoke_id = 9,
++ .component.invoke.args.qsig.CallingName.name.presentation = 4,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_BusyName,
++ .component.invoke.invoke_id = 10,
++ .component.invoke.args.qsig.CallingName.name.presentation = 4,
++ .component.invoke.args.qsig.CallingName.name.char_set = 1,
++ },
++
++ /* Q.SIG SS-AOC-Operations */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ChargeRequest,
++ .component.invoke.invoke_id = 11,
++ .component.invoke.args.qsig.ChargeRequest.num_records = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ChargeRequest,
++ .component.invoke.invoke_id = 12,
++ .component.invoke.args.qsig.ChargeRequest.num_records = 1,
++ .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[0] = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ChargeRequest,
++ .component.invoke.invoke_id = 13,
++ .component.invoke.args.qsig.ChargeRequest.num_records = 2,
++ .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[0] = 4,
++ .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[1] = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_ChargeRequest,
++ .component.result.invoke_id = 14,
++ .component.result.args.qsig.ChargeRequest.advice_mode_combination = 3,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_GetFinalCharge,
++ .component.invoke.invoke_id = 15,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 16,
++ .component.invoke.args.qsig.AocFinal.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 17,
++ .component.invoke.args.qsig.AocFinal.type = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 18,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 19,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocFinal.specific.billing_id_present = 1,
++ .component.invoke.args.qsig.AocFinal.specific.billing_id = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 20,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocFinal.charging_association_present = 1,
++ .component.invoke.args.qsig.AocFinal.charging_association.type = 0,
++ .component.invoke.args.qsig.AocFinal.charging_association.id = 200,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 21,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocFinal.specific.billing_id_present = 1,
++ .component.invoke.args.qsig.AocFinal.specific.billing_id = 2,
++ .component.invoke.args.qsig.AocFinal.charging_association_present = 1,
++ .component.invoke.args.qsig.AocFinal.charging_association.type = 0,
++ .component.invoke.args.qsig.AocFinal.charging_association.id = 200,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocFinal,
++ .component.invoke.invoke_id = 22,
++ .component.invoke.args.qsig.AocFinal.type = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocFinal.charging_association_present = 1,
++ .component.invoke.args.qsig.AocFinal.charging_association.type = 1,
++ .component.invoke.args.qsig.AocFinal.charging_association.number.plan = 4,
++ .component.invoke.args.qsig.AocFinal.charging_association.number.length = 4,
++ .component.invoke.args.qsig.AocFinal.charging_association.number.str = "1802",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocInterim,
++ .component.invoke.invoke_id = 23,
++ .component.invoke.args.qsig.AocInterim.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocInterim,
++ .component.invoke.invoke_id = 24,
++ .component.invoke.args.qsig.AocInterim.type = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocInterim,
++ .component.invoke.invoke_id = 25,
++ .component.invoke.args.qsig.AocInterim.type = 2,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.currency = "Rupies",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocInterim,
++ .component.invoke.invoke_id = 26,
++ .component.invoke.args.qsig.AocInterim.type = 2,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.currency = 800,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.multiplier = 2,
++ .component.invoke.args.qsig.AocInterim.specific.recorded.currency = "Rupies",
++ .component.invoke.args.qsig.AocInterim.specific.billing_id_present = 1,
++ .component.invoke.args.qsig.AocInterim.specific.billing_id = 2,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 27,
++ .component.invoke.args.qsig.AocRate.type = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 28,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 0,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.special_charging_code = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 29,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.currency = "Dollars",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.currency = 7,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.multiplier = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.charging_type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.length = 8,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.scale = 4,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 30,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.currency = "Dollars",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.currency = 7,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.multiplier = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.charging_type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.length = 8,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.scale = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity_present = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity.length = 20,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity.scale = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 31,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 2,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.currency = "Euros",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.currency = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.multiplier = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 32,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 3,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.currency = "Yen",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.amount.currency = 300,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.amount.multiplier = 5,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.unit = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 33,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 2,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 2,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.currency = "Euros",
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.currency = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.multiplier = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].currency_type = 3,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.currency = "Yen",
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.amount.currency = 300,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.amount.multiplier = 5,
++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.unit = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 34,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 4,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 35,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 5,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocRate,
++ .component.invoke.invoke_id = 36,
++ .component.invoke.args.qsig.AocRate.type = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4,
++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 6,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocComplete,
++ .component.invoke.invoke_id = 37,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.plan = 4,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.length = 4,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocComplete,
++ .component.invoke.invoke_id = 38,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.plan = 4,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.length = 4,
++ .component.invoke.args.qsig.AocComplete.charged_user_number.str = "8340",
++ .component.invoke.args.qsig.AocComplete.charging_association_present = 1,
++ .component.invoke.args.qsig.AocComplete.charging_association.type = 0,
++ .component.invoke.args.qsig.AocComplete.charging_association.id = 8298,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_AocComplete,
++ .component.result.invoke_id = 39,
++ .component.result.args.qsig.AocComplete.charging_option = 2,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocDivChargeReq,
++ .component.invoke.invoke_id = 40,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.plan = 4,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.length = 4,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.str = "8340",
++ .component.invoke.args.qsig.AocDivChargeReq.diversion_type = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_AocDivChargeReq,
++ .component.invoke.invoke_id = 41,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.plan = 4,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.length = 4,
++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.str = "8340",
++ .component.invoke.args.qsig.AocDivChargeReq.charging_association_present = 1,
++ .component.invoke.args.qsig.AocDivChargeReq.charging_association.type = 0,
++ .component.invoke.args.qsig.AocDivChargeReq.charging_association.id = 8298,
++ .component.invoke.args.qsig.AocDivChargeReq.diversion_type = 3,
++ },
++
++ /* Q.SIG Call-Transfer-Operations (CT) */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferIdentify,
++ .component.invoke.invoke_id = 42,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CallTransferIdentify,
++ .component.result.invoke_id = 43,
++ .component.result.args.qsig.CallTransferIdentify.call_id = "2345",
++ .component.result.args.qsig.CallTransferIdentify.rerouting_number.plan = 4,
++ .component.result.args.qsig.CallTransferIdentify.rerouting_number.length = 4,
++ .component.result.args.qsig.CallTransferIdentify.rerouting_number.str = "8340",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferAbandon,
++ .component.invoke.invoke_id = 44,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferInitiate,
++ .component.invoke.invoke_id = 45,
++ .component.invoke.args.qsig.CallTransferInitiate.call_id = "2345",
++ .component.invoke.args.qsig.CallTransferInitiate.rerouting_number.plan = 4,
++ .component.invoke.args.qsig.CallTransferInitiate.rerouting_number.length = 4,
++ .component.invoke.args.qsig.CallTransferInitiate.rerouting_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CallTransferInitiate,
++ .component.result.invoke_id = 46,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferSetup,
++ .component.invoke.invoke_id = 47,
++ .component.invoke.args.qsig.CallTransferSetup.call_id = "23",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CallTransferSetup,
++ .component.result.invoke_id = 48,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferActive,
++ .component.invoke.invoke_id = 49,
++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferActive,
++ .component.invoke.invoke_id = 50,
++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferActive.q931ie_contents = "RT",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferActive,
++ .component.invoke.invoke_id = 51,
++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name_present = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.length = 7,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferActive,
++ .component.invoke.invoke_id = 52,
++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferActive.q931ie_contents = "RT",
++ .component.invoke.args.qsig.CallTransferActive.connected_name_present = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.length = 7,
++ .component.invoke.args.qsig.CallTransferActive.connected_name.data = "Alphred",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 53,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 0,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.screening_indicator = 3,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.plan = 4,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.length = 4,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 54,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 55,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 56,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 3,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.screening_indicator = 3,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.plan = 4,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.length = 4,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 57,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferComplete.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferComplete.q931ie_contents = "RT",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 58,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name_present = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.length = 7,
++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 59,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferComplete.call_status = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete,
++ .component.invoke.invoke_id = 60,
++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1,
++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferComplete.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferComplete.q931ie_contents = "RT",
++ .component.invoke.args.qsig.CallTransferComplete.call_status = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate,
++ .component.invoke.invoke_id = 61,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate,
++ .component.invoke.invoke_id = 62,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name_present = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.length = 7,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.data = "Alphred",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate,
++ .component.invoke.invoke_id = 63,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.q931ie_contents = "RT",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate,
++ .component.invoke.invoke_id = 64,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name_present = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.presentation = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.char_set = 1,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.length = 7,
++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.data = "Alphred",
++ .component.invoke.args.qsig.CallTransferUpdate.q931ie.length = 2,
++ .component.invoke.args.qsig.CallTransferUpdate.q931ie_contents = "RT",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_SubaddressTransfer,
++ .component.invoke.invoke_id = 65,
++ .component.invoke.args.qsig.SubaddressTransfer.redirection_subaddress.type = 1,
++ .component.invoke.args.qsig.SubaddressTransfer.redirection_subaddress.length = 4,
++ .component.invoke.args.qsig.SubaddressTransfer.redirection_subaddress.u.nsap = "4356",
++ },
++
++ /* Q.SIG Call-Diversion-Operations */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_ActivateDiversionQ,
++ .component.invoke.invoke_id = 66,
++ .component.invoke.args.qsig.ActivateDiversionQ.procedure = 1,
++ .component.invoke.args.qsig.ActivateDiversionQ.basic_service = 3,
++ .component.invoke.args.qsig.ActivateDiversionQ.diverted_to.number.plan = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.diverted_to.number.length = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.diverted_to.number.str = "8340",
++ .component.invoke.args.qsig.ActivateDiversionQ.served_user_number.plan = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.served_user_number.length = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.served_user_number.str = "8340",
++ .component.invoke.args.qsig.ActivateDiversionQ.activating_user_number.plan = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.activating_user_number.length = 4,
++ .component.invoke.args.qsig.ActivateDiversionQ.activating_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_ActivateDiversionQ,
++ .component.result.invoke_id = 67,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DeactivateDiversionQ,
++ .component.invoke.invoke_id = 68,
++ .component.invoke.args.qsig.DeactivateDiversionQ.procedure = 1,
++ .component.invoke.args.qsig.DeactivateDiversionQ.basic_service = 3,
++ .component.invoke.args.qsig.DeactivateDiversionQ.served_user_number.plan = 4,
++ .component.invoke.args.qsig.DeactivateDiversionQ.served_user_number.length = 4,
++ .component.invoke.args.qsig.DeactivateDiversionQ.served_user_number.str = "8340",
++ .component.invoke.args.qsig.DeactivateDiversionQ.deactivating_user_number.plan = 4,
++ .component.invoke.args.qsig.DeactivateDiversionQ.deactivating_user_number.length = 4,
++ .component.invoke.args.qsig.DeactivateDiversionQ.deactivating_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_DeactivateDiversionQ,
++ .component.result.invoke_id = 69,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.invoke.invoke_id = 70,
++ .component.invoke.args.qsig.InterrogateDiversionQ.procedure = 1,
++ .component.invoke.args.qsig.InterrogateDiversionQ.basic_service = 3,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.plan = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.length = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.str = "8340",
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.plan = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.length = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.invoke.invoke_id = 71,
++ .component.invoke.args.qsig.InterrogateDiversionQ.procedure = 1,
++ .component.invoke.args.qsig.InterrogateDiversionQ.basic_service = 0,/* default */
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.plan = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.length = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.str = "8340",
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.plan = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.length = 4,
++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.result.invoke_id = 72,
++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.result.invoke_id = 73,
++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 1,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].basic_service = 3,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].procedure = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].remote_enabled = 0,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.result.invoke_id = 74,
++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 1,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].basic_service = 3,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].procedure = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].remote_enabled = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ,
++ .component.result.invoke_id = 75,
++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].basic_service = 3,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].procedure = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].served_user_number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].served_user_number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].served_user_number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].basic_service = 3,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].procedure = 2,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].diverted_to.number.plan = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].diverted_to.number.length = 4,
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].diverted_to.number.str = "8340",
++ .component.result.args.qsig.InterrogateDiversionQ.list[1].remote_enabled = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CheckRestriction,
++ .component.invoke.invoke_id = 76,
++ .component.invoke.args.qsig.CheckRestriction.served_user_number.plan = 4,
++ .component.invoke.args.qsig.CheckRestriction.served_user_number.length = 4,
++ .component.invoke.args.qsig.CheckRestriction.served_user_number.str = "8340",
++ .component.invoke.args.qsig.CheckRestriction.basic_service = 3,
++ .component.invoke.args.qsig.CheckRestriction.diverted_to_number.plan = 4,
++ .component.invoke.args.qsig.CheckRestriction.diverted_to_number.length = 4,
++ .component.invoke.args.qsig.CheckRestriction.diverted_to_number.str = "8340",
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CheckRestriction,
++ .component.result.invoke_id = 77,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallRerouting,
++ .component.invoke.invoke_id = 78,
++ .component.invoke.args.qsig.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.qsig.CallRerouting.called.number.plan = 4,
++ .component.invoke.args.qsig.CallRerouting.called.number.length = 4,
++ .component.invoke.args.qsig.CallRerouting.called.number.str = "8340",
++ .component.invoke.args.qsig.CallRerouting.diversion_counter = 5,
++ .component.invoke.args.qsig.CallRerouting.q931ie.length = 2,
++ .component.invoke.args.qsig.CallRerouting.q931ie_contents = "RT",
++ .component.invoke.args.qsig.CallRerouting.last_rerouting.presentation = 1,
++ .component.invoke.args.qsig.CallRerouting.subscription_option = 2,
++ .component.invoke.args.qsig.CallRerouting.calling.presentation = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CallRerouting,
++ .component.invoke.invoke_id = 79,
++ .component.invoke.args.qsig.CallRerouting.rerouting_reason = 3,
++ .component.invoke.args.qsig.CallRerouting.original_rerouting_reason_present = 1,
++ .component.invoke.args.qsig.CallRerouting.original_rerouting_reason = 2,
++ .component.invoke.args.qsig.CallRerouting.called.number.plan = 4,
++ .component.invoke.args.qsig.CallRerouting.called.number.length = 4,
++ .component.invoke.args.qsig.CallRerouting.called.number.str = "8340",
++ .component.invoke.args.qsig.CallRerouting.diversion_counter = 5,
++ .component.invoke.args.qsig.CallRerouting.q931ie.length = 2,
++ .component.invoke.args.qsig.CallRerouting.q931ie_contents = "RT",
++ .component.invoke.args.qsig.CallRerouting.last_rerouting.presentation = 1,
++ .component.invoke.args.qsig.CallRerouting.subscription_option = 2,
++ .component.invoke.args.qsig.CallRerouting.calling_subaddress.type = 1,
++ .component.invoke.args.qsig.CallRerouting.calling_subaddress.length = 4,
++ .component.invoke.args.qsig.CallRerouting.calling_subaddress.u.nsap = "3253",
++ .component.invoke.args.qsig.CallRerouting.calling.presentation = 1,
++ .component.invoke.args.qsig.CallRerouting.calling_name_present = 1,
++ .component.invoke.args.qsig.CallRerouting.calling_name.presentation = 4,
++ .component.invoke.args.qsig.CallRerouting.calling_name.char_set = 1,
++ .component.invoke.args.qsig.CallRerouting.original_called_present = 1,
++ .component.invoke.args.qsig.CallRerouting.original_called.presentation = 2,
++ .component.invoke.args.qsig.CallRerouting.redirecting_name_present = 1,
++ .component.invoke.args.qsig.CallRerouting.redirecting_name.presentation = 4,
++ .component.invoke.args.qsig.CallRerouting.redirecting_name.char_set = 1,
++ .component.invoke.args.qsig.CallRerouting.original_called_name_present = 1,
++ .component.invoke.args.qsig.CallRerouting.original_called_name.presentation = 4,
++ .component.invoke.args.qsig.CallRerouting.original_called_name.char_set = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_CallRerouting,
++ .component.result.invoke_id = 80,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation1,
++ .component.invoke.invoke_id = 81,
++ .component.invoke.args.qsig.DivertingLegInformation1.diversion_reason = 3,
++ .component.invoke.args.qsig.DivertingLegInformation1.subscription_option = 1,
++ .component.invoke.args.qsig.DivertingLegInformation1.nominated_number.plan = 4,
++ .component.invoke.args.qsig.DivertingLegInformation1.nominated_number.length = 4,
++ .component.invoke.args.qsig.DivertingLegInformation1.nominated_number.str = "8340",
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation2,
++ .component.invoke.invoke_id = 82,
++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_counter = 6,
++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_reason = 3,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation2,
++ .component.invoke.invoke_id = 83,
++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_counter = 6,
++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_reason = 3,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_diversion_reason_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_diversion_reason = 2,
++ .component.invoke.args.qsig.DivertingLegInformation2.diverting_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.diverting.presentation = 2,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called.presentation = 2,
++ .component.invoke.args.qsig.DivertingLegInformation2.redirecting_name_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.redirecting_name.presentation = 4,
++ .component.invoke.args.qsig.DivertingLegInformation2.redirecting_name.char_set = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_name_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_name.presentation = 4,
++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_name.char_set = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation3,
++ .component.invoke.invoke_id = 84,
++ .component.invoke.args.qsig.DivertingLegInformation3.presentation_allowed_indicator = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation3,
++ .component.invoke.invoke_id = 85,
++ .component.invoke.args.qsig.DivertingLegInformation3.presentation_allowed_indicator = 1,
++ .component.invoke.args.qsig.DivertingLegInformation3.redirection_name_present = 1,
++ .component.invoke.args.qsig.DivertingLegInformation3.redirection_name.presentation = 4,
++ .component.invoke.args.qsig.DivertingLegInformation3.redirection_name.char_set = 1,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_CfnrDivertedLegFailed,
++ .component.invoke.invoke_id = 86,
++ },
++
++ /* Q.SIG SS-MWI-Operations */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIActivate,
++ .component.invoke.invoke_id = 102,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.basic_service = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIActivate,
++ .component.invoke.invoke_id = 103,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.basic_service = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.type = 0,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.integer = 532,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIActivate,
++ .component.invoke.invoke_id = 104,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.basic_service = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.type = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.number.str = "9838",
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIActivate,
++ .component.invoke.invoke_id = 105,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.basic_service = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.type = 2,
++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.str = "123456",
++ .component.invoke.args.qsig.MWIActivate.number_of_messages_present = 1,
++ .component.invoke.args.qsig.MWIActivate.number_of_messages = 6548,
++ .component.invoke.args.qsig.MWIActivate.originating_number.plan = 4,
++ .component.invoke.args.qsig.MWIActivate.originating_number.length = 4,
++ .component.invoke.args.qsig.MWIActivate.originating_number.str = "9838",
++ .component.invoke.args.qsig.MWIActivate.timestamp_present = 1,
++ .component.invoke.args.qsig.MWIActivate.timestamp = "19970621194530",
++ .component.invoke.args.qsig.MWIActivate.priority_present = 1,
++ .component.invoke.args.qsig.MWIActivate.priority = 7,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_MWIActivate,
++ .component.result.invoke_id = 106,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIDeactivate,
++ .component.invoke.invoke_id = 107,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIDeactivate.basic_service = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIDeactivate,
++ .component.invoke.invoke_id = 108,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIDeactivate.basic_service = 1,
++ .component.invoke.args.qsig.MWIDeactivate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIDeactivate.msg_centre_id.type = 0,
++ .component.invoke.args.qsig.MWIDeactivate.msg_centre_id.u.integer = 532,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_MWIDeactivate,
++ .component.result.invoke_id = 109,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIInterrogate,
++ .component.invoke.invoke_id = 110,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIInterrogate.basic_service = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_QSIG_MWIInterrogate,
++ .component.invoke.invoke_id = 111,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.plan = 4,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.length = 4,
++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.str = "9838",
++ .component.invoke.args.qsig.MWIInterrogate.basic_service = 1,
++ .component.invoke.args.qsig.MWIInterrogate.msg_centre_id_present = 1,
++ .component.invoke.args.qsig.MWIInterrogate.msg_centre_id.type = 0,
++ .component.invoke.args.qsig.MWIInterrogate.msg_centre_id.u.integer = 532,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_MWIInterrogate,
++ .component.result.invoke_id = 112,
++ .component.result.args.qsig.MWIInterrogate.num_records = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].basic_service = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_QSIG_MWIInterrogate,
++ .component.result.invoke_id = 113,
++ .component.result.args.qsig.MWIInterrogate.num_records = 2,
++ .component.result.args.qsig.MWIInterrogate.list[0].basic_service = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].msg_centre_id_present = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].msg_centre_id.type = 0,
++ .component.result.args.qsig.MWIInterrogate.list[0].msg_centre_id.u.integer = 987,
++ .component.result.args.qsig.MWIInterrogate.list[0].number_of_messages_present = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].number_of_messages = 6548,
++ .component.result.args.qsig.MWIInterrogate.list[0].originating_number.plan = 4,
++ .component.result.args.qsig.MWIInterrogate.list[0].originating_number.length = 4,
++ .component.result.args.qsig.MWIInterrogate.list[0].originating_number.str = "9838",
++ .component.result.args.qsig.MWIInterrogate.list[0].timestamp_present = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].timestamp = "19970621194530",
++ .component.result.args.qsig.MWIInterrogate.list[0].priority_present = 1,
++ .component.result.args.qsig.MWIInterrogate.list[0].priority = 7,
++ .component.result.args.qsig.MWIInterrogate.list[1].basic_service = 1,
++ },
++/* *INDENT-ON* */
++};
++
++
++static const struct rose_message rose_dms100_msgs[] = {
++/* *INDENT-OFF* */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_DMS100_RLT_OperationInd,
++ .component.invoke.invoke_id = ROSE_DMS100_RLT_OPERATION_IND,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_DMS100_RLT_OperationInd,
++ .component.result.invoke_id = ROSE_DMS100_RLT_OPERATION_IND,
++ .component.result.args.dms100.RLT_OperationInd.call_id = 130363,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_DMS100_RLT_ThirdParty,
++ .component.invoke.invoke_id = ROSE_DMS100_RLT_THIRD_PARTY,
++ .component.invoke.args.dms100.RLT_ThirdParty.call_id = 120047,
++ .component.invoke.args.dms100.RLT_ThirdParty.reason = 1,
++ },
++ {
++ .type = ROSE_COMP_TYPE_RESULT,
++ .component.result.operation = ROSE_DMS100_RLT_ThirdParty,
++ .component.result.invoke_id = ROSE_DMS100_RLT_THIRD_PARTY,
++ },
++/* *INDENT-ON* */
++};
++
++
++static const struct rose_message rose_ni2_msgs[] = {
++/* *INDENT-OFF* */
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_NI2_InformationFollowing,
++ .component.invoke.invoke_id = 1,
++ .component.invoke.args.ni2.InformationFollowing.value = 7,
++ },
++
++ {
++ .type = ROSE_COMP_TYPE_INVOKE,
++ .component.invoke.operation = ROSE_NI2_InitiateTransfer,
++ .component.invoke.invoke_id = 2,
++ .component.invoke.args.ni2.InitiateTransfer.call_reference = 5,
++ },
++/* *INDENT-ON* */
++};
++
++/* ------------------------------------------------------------------- */
++
++static void rose_pri_message(struct pri *ctrl, char *stuff)
++{
++ fprintf(stdout, "%s", stuff);
++}
++
++static void rose_pri_error(struct pri *ctrl, char *stuff)
++{
++ fprintf(stdout, "%s", stuff);
++ fprintf(stderr, "%s", stuff);
++}
++
++/*!
++ * \internal
++ * \brief Test ROSE encoding and decoding the given message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param index Message number to report.
++ * \param header Facility message header data to encode.
++ * \param encode_msg Message data to encode.
++ *
++ * \return Nothing
++ */
++static void rose_test_msg(struct pri *ctrl, unsigned index,
++ const struct fac_extension_header *header, const struct rose_message *encode_msg)
++{
++ struct fac_extension_header decoded_header;
++ struct rose_message decoded_msg;
++ unsigned char *enc_pos;
++ unsigned char *enc_end;
++ const unsigned char *dec_pos;
++ const unsigned char *dec_end;
++
++ static unsigned char buf[1024];
++
++ pri_message(ctrl, "\n\n");
++ enc_end = buf + sizeof(buf);
++ enc_pos = facility_encode_header(ctrl, buf, enc_end, header);
++ if (!enc_pos) {
++ pri_error(ctrl, "Error: Message:%u failed to encode header\n", index);
++ } else {
++ enc_pos = rose_encode(ctrl, enc_pos, enc_end, encode_msg);
++ if (!enc_pos) {
++ pri_error(ctrl, "Error: Message:%u failed to encode ROSE\n", index);
++ } else {
++ pri_message(ctrl, "Message %u encoded length is %u\n", index,
++ (unsigned) (enc_pos - buf));
++
++ /* Clear the decoded message contents for comparison. */
++ memset(&decoded_header, 0, sizeof(decoded_header));
++ memset(&decoded_msg, 0, sizeof(decoded_msg));
++
++ dec_end = enc_pos;
++ dec_pos = facility_decode_header(ctrl, buf, dec_end, &decoded_header);
++ if (!dec_pos) {
++ pri_error(ctrl, "Error: Message:%u failed to decode header\n", index);
++ } else {
++ dec_pos = rose_decode(ctrl, dec_pos, dec_end, &decoded_msg);
++ if (!dec_pos) {
++ pri_error(ctrl, "Error: Message:%u failed to decode ROSE\n", index);
++ } else {
++ if (header
++ && memcmp(header, &decoded_header, sizeof(decoded_header))) {
++ pri_error(ctrl, "Error: Message:%u Header did not match\n",
++ index);
++ }
++ if (memcmp(encode_msg, &decoded_msg, sizeof(decoded_msg))) {
++ pri_error(ctrl, "Error: Message:%u ROSE did not match\n", index);
++ }
++ }
++ }
++ }
++ }
++ pri_message(ctrl, "\n\n"
++ "************************************************************\n");
++}
++
++/*!
++ * \internal
++ * \brief Test ROSE decoding messages of unusual encodings.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Test name for the encoded message.
++ * \param msg_buf Encoded message to decode.
++ * \param msg_len Length of encoded message buffer.
++ *
++ * \return Nothing
++ */
++static void rose_test_exception(struct pri *ctrl, const char *name,
++ const unsigned char *msg, size_t msg_len)
++{
++ const unsigned char *pos;
++ const unsigned char *end;
++ struct fac_extension_header header;
++ struct rose_message decoded_msg;
++
++ pri_message(ctrl, "\n\n"
++ "%s test: Message encoded length is %u\n", name, (unsigned) msg_len);
++
++ pos = msg;
++ end = msg + msg_len;
++ pos = facility_decode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ pri_error(ctrl, "Error: %s test: Message failed to decode header\n", name);
++ } else {
++ pos = rose_decode(ctrl, pos, end, &decoded_msg);
++ if (!pos) {
++ pri_error(ctrl, "Error: %s test: Message failed to decode ROSE\n", name);
++ }
++ }
++
++ pri_message(ctrl, "\n\n"
++ "************************************************************\n");
++}
++
++/*!
++ * \brief ROSE encode/decode test program.
++ *
++ * \param argc Program argument count.
++ * \param argv Program argument string array.
++ *
++ * \retval 0 on success.
++ * \retval Nonzero on error.
++ */
++int main(int argc, char *argv[])
++{
++ unsigned index;
++ unsigned offset;
++ static struct pri dummy_ctrl;
++
++ pri_set_message(rose_pri_message);
++ pri_set_error(rose_pri_error);
++
++ memset(&dummy_ctrl, 0, sizeof(dummy_ctrl));
++ dummy_ctrl.debug = PRI_DEBUG_APDU;
++
++ offset = 0;
++ pri_message(&dummy_ctrl, "Encode/decode message(s)\n");
++ if (argc <= 1) {
++ dummy_ctrl.switchtype = PRI_SWITCH_EUROISDN_E1;
++ for (index = 0; index < ARRAY_LEN(rose_etsi_msgs); ++index) {
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_etsi_msgs[index]);
++ }
++ offset += ARRAY_LEN(rose_etsi_msgs);
++
++ dummy_ctrl.switchtype = PRI_SWITCH_QSIG;
++ for (index = 0; index < ARRAY_LEN(rose_qsig_msgs); ++index) {
++ rose_test_msg(&dummy_ctrl, index + offset,
++ &fac_headers[index % ARRAY_LEN(fac_headers)], &rose_qsig_msgs[index]);
++ }
++ offset += ARRAY_LEN(rose_qsig_msgs);
++
++ dummy_ctrl.switchtype = PRI_SWITCH_DMS100;
++ for (index = 0; index < ARRAY_LEN(rose_dms100_msgs); ++index) {
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_dms100_msgs[index]);
++ }
++ offset += ARRAY_LEN(rose_dms100_msgs);
++
++ dummy_ctrl.switchtype = PRI_SWITCH_NI2;
++ for (index = 0; index < ARRAY_LEN(rose_ni2_msgs); ++index) {
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_ni2_msgs[index]);
++ }
++ //offset += ARRAY_LEN(rose_ni2_msgs);
++ } else {
++ index = atoi(argv[1]);
++
++ if (index < ARRAY_LEN(rose_etsi_msgs)) {
++ dummy_ctrl.switchtype = PRI_SWITCH_EUROISDN_E1;
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_etsi_msgs[index]);
++ return 0;
++ }
++ offset += ARRAY_LEN(rose_etsi_msgs);
++ index -= ARRAY_LEN(rose_etsi_msgs);
++
++ if (index < ARRAY_LEN(rose_qsig_msgs)) {
++ dummy_ctrl.switchtype = PRI_SWITCH_QSIG;
++ rose_test_msg(&dummy_ctrl, index + offset,
++ &fac_headers[index % ARRAY_LEN(fac_headers)], &rose_qsig_msgs[index]);
++ return 0;
++ }
++ offset += ARRAY_LEN(rose_qsig_msgs);
++ index -= ARRAY_LEN(rose_qsig_msgs);
++
++ if (index < ARRAY_LEN(rose_dms100_msgs)) {
++ dummy_ctrl.switchtype = PRI_SWITCH_DMS100;
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_dms100_msgs[index]);
++ return 0;
++ }
++ offset += ARRAY_LEN(rose_dms100_msgs);
++ index -= ARRAY_LEN(rose_dms100_msgs);
++
++ if (index < ARRAY_LEN(rose_ni2_msgs)) {
++ dummy_ctrl.switchtype = PRI_SWITCH_NI2;
++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0],
++ &rose_ni2_msgs[index]);
++ return 0;
++ }
++ //offset += ARRAY_LEN(rose_ni2_msgs);
++ //index -= ARRAY_LEN(rose_ni2_msgs);
++
++ fprintf(stderr, "Invalid option\n");
++ return 0;
++ }
++
++/* ------------------------------------------------------------------- */
++
++ pri_message(&dummy_ctrl, "\n\n"
++ "Decode unusually encoded messages\n");
++
++ dummy_ctrl.switchtype = PRI_SWITCH_EUROISDN_E1;
++
++ rose_test_exception(&dummy_ctrl, "Extra bytes on end", rose_etsi_extra,
++ sizeof(rose_etsi_extra));
++
++ rose_test_exception(&dummy_ctrl, "Indefinite length", rose_etsi_indefinite_len,
++ sizeof(rose_etsi_indefinite_len) - 2);
++ rose_test_exception(&dummy_ctrl, "Indefinite length (extra)",
++ rose_etsi_indefinite_len, sizeof(rose_etsi_indefinite_len));
++
++ rose_test_exception(&dummy_ctrl, "Unused components (indefinite length)",
++ rose_etsi_unused_indefinite_len, sizeof(rose_etsi_unused_indefinite_len) - 2);
++ rose_test_exception(&dummy_ctrl, "Unused components (indefinite length, extra)",
++ rose_etsi_unused_indefinite_len, sizeof(rose_etsi_unused_indefinite_len));
++
++ rose_test_exception(&dummy_ctrl, "Unused components", rose_etsi_unused,
++ sizeof(rose_etsi_unused) - 2);
++ rose_test_exception(&dummy_ctrl, "Unused components (extra)", rose_etsi_unused,
++ sizeof(rose_etsi_unused));
++
++/* ------------------------------------------------------------------- */
++
++ pri_message(&dummy_ctrl, "\n\n"
++ "List of operation codes:\n");
++ for (index = 0; index < ROSE_Num_Operation_Codes; ++index) {
++ pri_message(&dummy_ctrl, "%d: %s\n", index, rose_operation2str(index));
++ }
++ pri_message(&dummy_ctrl, "\n\n"
++ "************************************************************\n");
++
++/* ------------------------------------------------------------------- */
++
++ pri_message(&dummy_ctrl, "\n\n"
++ "List of error codes:\n");
++ for (index = 0; index < ROSE_ERROR_Num_Codes; ++index) {
++ pri_message(&dummy_ctrl, "%d: %s\n", index, rose_error2str(index));
++ }
++ pri_message(&dummy_ctrl, "\n\n"
++ "************************************************************\n");
++
++/* ------------------------------------------------------------------- */
++
++ pri_message(&dummy_ctrl, "\n\n");
++ pri_message(&dummy_ctrl, "sizeof(struct rose_message) = %u\n",
++ (unsigned) sizeof(struct rose_message));
++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_invoke) = %u\n",
++ (unsigned) sizeof(struct rose_msg_invoke));
++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_result) = %u\n",
++ (unsigned) sizeof(struct rose_msg_result));
++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_error) = %u\n",
++ (unsigned) sizeof(struct rose_msg_error));
++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_reject) = %u\n",
++ (unsigned) sizeof(struct rose_msg_reject));
++ pri_message(&dummy_ctrl, "sizeof(union rose_msg_invoke_args) = %u\n",
++ (unsigned) sizeof(union rose_msg_invoke_args));
++ pri_message(&dummy_ctrl, "sizeof(union rose_msg_result_args) = %u\n",
++ (unsigned) sizeof(union rose_msg_result_args));
++
++ pri_message(&dummy_ctrl, "\n");
++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigForwardingList) = %u\n",
++ (unsigned) sizeof(struct roseQsigForwardingList));
++
++ pri_message(&dummy_ctrl, "\n");
++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigCallRerouting_ARG) = %u\n",
++ (unsigned) sizeof(struct roseQsigCallRerouting_ARG));
++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigAocRateArg_ARG) = %u\n",
++ (unsigned) sizeof(struct roseQsigAocRateArg_ARG));
++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigMWIInterrogateRes) = %u\n",
++ (unsigned) sizeof(struct roseQsigMWIInterrogateRes));
++
++ pri_message(&dummy_ctrl, "\n");
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiForwardingList) = %u\n",
++ (unsigned) sizeof(struct roseEtsiForwardingList));
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiServedUserNumberList) = %u\n",
++ (unsigned) sizeof(struct roseEtsiServedUserNumberList));
++
++ pri_message(&dummy_ctrl, "\n");
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiCallRerouting_ARG) = %u\n",
++ (unsigned) sizeof(struct roseEtsiCallRerouting_ARG));
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiDiversionInformation_ARG) = %u\n",
++ (unsigned) sizeof(struct roseEtsiDiversionInformation_ARG));
++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiAOCSCurrencyInfoList) = %u\n",
++ (unsigned) sizeof(struct roseEtsiAOCSCurrencyInfoList));
++
++/* ------------------------------------------------------------------- */
++
++ return 0;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rosetest.c */
+
+Property changes on: rosetest.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_internal.h
+===================================================================
+--- a/rose_internal.h (.../tags/1.4.10.2) (revision 0)
++++ b/rose_internal.h (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,477 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief Internal definitions and prototypes for ROSE.
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++#ifndef _LIBPRI_ROSE_INTERNAL_H
++#define _LIBPRI_ROSE_INTERNAL_H
++
++#include "rose.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++
++/* ------------------------------------------------------------------- */
++
++
++/* Embedded-Q931-Types */
++unsigned char *rose_enc_Q931ie(struct pri *ctrl, unsigned char *pos, unsigned char *end,
++ unsigned tag, const struct roseQ931ie *q931ie);
++
++const unsigned char *rose_dec_Q931ie(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct roseQ931ie *q931ie,
++ size_t contents_size);
++
++/* Addressing-Data-Elements */
++unsigned char *rose_enc_PartyNumber(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePartyNumber *party_number);
++unsigned char *rose_enc_PartySubaddress(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePartySubaddress *party_subaddress);
++unsigned char *rose_enc_Address(struct pri *ctrl, unsigned char *pos, unsigned char *end,
++ unsigned tag, const struct roseAddress *address);
++unsigned char *rose_enc_PresentedNumberUnscreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePresentedNumberUnscreened *party);
++unsigned char *rose_enc_NumberScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseNumberScreened *screened);
++unsigned char *rose_enc_PresentedNumberScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePresentedNumberScreened *party);
++unsigned char *rose_enc_AddressScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseAddressScreened *screened);
++unsigned char *rose_enc_PresentedAddressScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePresentedAddressScreened *party);
++
++const unsigned char *rose_dec_PartyNumber(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartyNumber *party_number);
++const unsigned char *rose_dec_PartySubaddress(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartySubaddress *party_subaddress);
++const unsigned char *rose_dec_Address(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct roseAddress *address);
++const unsigned char *rose_dec_PresentedNumberUnscreened(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePresentedNumberUnscreened *party);
++const unsigned char *rose_dec_NumberScreened(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseNumberScreened *screened);
++const unsigned char *rose_dec_PresentedNumberScreened(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePresentedNumberScreened *party);
++const unsigned char *rose_dec_AddressScreened(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseAddressScreened *screened);
++const unsigned char *rose_dec_PresentedAddressScreened(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePresentedAddressScreened *party);
++
++/* ETSI Advice-of-Charge (AOC) */
++unsigned char *rose_enc_etsi_ChargingRequest_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_ChargingRequest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_etsi_AOCSCurrency_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCSSpecialArr_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCDCurrency_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCDChargingUnit_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCECurrency_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_AOCEChargingUnit_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_etsi_ChargingRequest_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_ChargingRequest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_etsi_AOCSCurrency_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCSSpecialArr_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCDCurrency_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCDChargingUnit_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCECurrency_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_AOCEChargingUnit_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* ETSI Call Diversion */
++unsigned char *rose_enc_etsi_ActivationDiversion_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_DeactivationDiversion_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_ActivationStatusNotificationDiv_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_DeactivationStatusNotificationDiv_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_InterrogationDiversion_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_InterrogationDiversion_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_etsi_DiversionInformation_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_CallDeflection_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_CallRerouting_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_InterrogateServedUserNumbers_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_etsi_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_etsi_ActivationDiversion_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_DeactivationDiversion_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_ActivationStatusNotificationDiv_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_DeactivationStatusNotificationDiv_ARG(struct pri
++ *ctrl, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_InterrogationDiversion_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_InterrogationDiversion_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_etsi_DiversionInformation_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_CallDeflection_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_CallRerouting_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_InterrogateServedUserNumbers_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_etsi_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* ETSI Explicit Call Transfer (ECT) */
++unsigned char *rose_enc_etsi_ExplicitEctExecute_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_SubaddressTransfer_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_EctLinkIdRequest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_etsi_EctInform_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_EctLoopTest_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_etsi_EctLoopTest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++
++const unsigned char *rose_dec_etsi_ExplicitEctExecute_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_SubaddressTransfer_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_EctLinkIdRequest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_etsi_EctInform_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_EctLoopTest_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_etsi_EctLoopTest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++
++/* Q.SIG Name-Operations */
++unsigned char *rose_enc_qsig_Name(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct roseQsigName *name);
++
++const unsigned char *rose_dec_qsig_Name(struct pri *ctrl, const char *fname,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigName *name);
++
++unsigned char *rose_enc_qsig_CallingName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CalledName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_ConnectedName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_BusyName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_qsig_CallingName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CalledName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_ConnectedName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_BusyName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/*
++ * Q.SIG Dummy invoke/result argument used by:
++ * SS-AOC-Operations,
++ * Call-Transfer-Operations,
++ * Call-Diversion-Operations,
++ * and SS-MWI-Operations.
++ */
++unsigned char *rose_enc_qsig_DummyArg_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DummyRes_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++
++const unsigned char *rose_dec_qsig_DummyArg_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DummyRes_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++
++/* Q.SIG SS-AOC-Operations */
++unsigned char *rose_enc_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_qsig_AocFinal_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_AocInterim_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_AocRate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_AocComplete_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_AocComplete_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_qsig_AocFinal_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_AocInterim_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_AocRate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_AocComplete_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_AocComplete_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* Q.SIG Call-Diversion-Operations */
++unsigned char *rose_enc_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_InterrogateDiversionQ_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* Q.SIG Call-Transfer-Operations (CT) */
++unsigned char *rose_enc_qsig_CallTransferIdentify_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_qsig_CallTransferInitiate_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallTransferSetup_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallTransferActive_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallTransferComplete_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_CallTransferUpdate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_SubaddressTransfer_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_qsig_CallTransferIdentify_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_qsig_CallTransferInitiate_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallTransferSetup_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallTransferActive_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallTransferComplete_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_CallTransferUpdate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_SubaddressTransfer_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* Q.SIG SS-MWI-Operations */
++unsigned char *rose_enc_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++
++const unsigned char *rose_dec_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++
++/* Northern Telecom DMS-100 operations */
++unsigned char *rose_enc_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++unsigned char *rose_enc_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++const unsigned char *rose_dec_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++/* National ISDN 2 (NI2) operations */
++unsigned char *rose_enc_ni2_InformationFollowing_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args);
++unsigned char *rose_enc_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++
++const unsigned char *rose_dec_ni2_InformationFollowing_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++const unsigned char *rose_dec_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++
++
++/* ------------------------------------------------------------------- */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _LIBPRI_ROSE_INTERNAL_H */
++/* ------------------------------------------------------------------- */
++/* end rose_internal.h */
+
+Property changes on: rose_internal.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: pri_q921.h
+===================================================================
+--- a/pri_q921.h (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_q921.h (.../branches/1.4) (revision 1357)
+@@ -192,4 +192,10 @@
+
+ extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr);
+
++extern int q921_transmit_uiframe(struct pri *pri, void *buf, int len);
++
++extern pri_event *q921_dchannel_up(struct pri *pri);
++
++extern pri_event *q921_dchannel_down(struct pri *pri);
++
+ #endif
+Index: pri_facility.c
+===================================================================
+--- a/pri_facility.c (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_facility.c (.../branches/1.4) (revision 1357)
+@@ -33,872 +33,1340 @@
+ #include "pri_q921.h"
+ #include "pri_q931.h"
+ #include "pri_facility.h"
++#include "rose.h"
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <limits.h>
+
+-static char *asn1id2text(int id)
++static short get_invokeid(struct pri *ctrl)
+ {
+- static char data[32];
+- static char *strings[] = {
+- "none",
+- "Boolean",
+- "Integer",
+- "Bit String",
+- "Octet String",
+- "NULL",
+- "Object Identifier",
+- "Object Descriptor",
+- "External Reference",
+- "Real Number",
+- "Enumerated",
+- "Embedded PDV",
+- "UTF-8 String",
+- "Relative Object ID",
+- "Reserved (0e)",
+- "Reserved (0f)",
+- "Sequence",
+- "Set",
+- "Numeric String",
+- "Printable String",
+- "Tele-Text String",
+- "IA-5 String",
+- "UTC Time",
+- "Generalized Time",
+- };
+- if (id > 0 && id <= 0x18) {
+- return strings[id];
+- } else {
+- sprintf(data, "Unknown (%02x)", id);
+- return data;
+- }
++ ctrl = PRI_MASTER(ctrl);
++ return ++ctrl->last_invoke;
+ }
+
+-static int asn1_dumprecursive(struct pri *pri, void *comp_ptr, int len, int level)
++static int redirectingreason_from_q931(struct pri *ctrl, int redirectingreason)
+ {
+- unsigned char *vdata = (unsigned char *)comp_ptr;
+- struct rose_component *comp;
+- int i = 0;
+- int j, k, l;
+- int clen = 0;
++ int value;
+
+- while (len > 0) {
+- GET_COMPONENT(comp, i, vdata, len);
+- pri_message(pri, "%*s%02X %04X", 2 * level, "", comp->type, comp->len);
+- if ((comp->type == 0) && (comp->len == 0))
+- return clen + 2;
+- if ((comp->type & ASN1_PC_MASK) == ASN1_PRIMITIVE) {
+- for (j = 0; j < comp->len; ++j)
+- pri_message(pri, " %02X", comp->data[j]);
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_QSIG:
++ switch (redirectingreason) {
++ case PRI_REDIR_UNKNOWN:
++ value = QSIG_DIVERT_REASON_UNKNOWN;
++ break;
++ case PRI_REDIR_FORWARD_ON_BUSY:
++ value = QSIG_DIVERT_REASON_CFB;
++ break;
++ case PRI_REDIR_FORWARD_ON_NO_REPLY:
++ value = QSIG_DIVERT_REASON_CFNR;
++ break;
++ case PRI_REDIR_UNCONDITIONAL:
++ value = QSIG_DIVERT_REASON_CFU;
++ break;
++ case PRI_REDIR_DEFLECTION:
++ case PRI_REDIR_DTE_OUT_OF_ORDER:
++ case PRI_REDIR_FORWARDED_BY_DTE:
++ pri_message(ctrl,
++ "!! Don't know how to convert Q.931 redirection reason %d to Q.SIG\n",
++ redirectingreason);
++ /* Fall through */
++ default:
++ value = QSIG_DIVERT_REASON_UNKNOWN;
++ break;
+ }
+- if ((comp->type & ASN1_CLAN_MASK) == ASN1_UNIVERSAL) {
+- switch (comp->type & ASN1_TYPE_MASK) {
+- case 0:
+- pri_message(pri, " (none)");
+- break;
+- case ASN1_BOOLEAN:
+- pri_message(pri, " (BOOLEAN: %d)", comp->data[0]);
+- break;
+- case ASN1_INTEGER:
+- for (k = l = 0; k < comp->len; ++k)
+- l = (l << 8) | comp->data[k];
+- pri_message(pri, " (INTEGER: %d)", l);
+- break;
+- case ASN1_BITSTRING:
+- pri_message(pri, " (BITSTRING:");
+- for (k = 0; k < comp->len; ++k)
+- pri_message(pri, " %02x", comp->data[k]);
+- pri_message(pri, ")");
+- break;
+- case ASN1_OCTETSTRING:
+- pri_message(pri, " (OCTETSTRING:");
+- for (k = 0; k < comp->len; ++k)
+- pri_message(pri, " %02x", comp->data[k]);
+- pri_message(pri, ")");
+- break;
+- case ASN1_NULL:
+- pri_message(pri, " (NULL)");
+- break;
+- case ASN1_OBJECTIDENTIFIER:
+- pri_message(pri, " (OBJECTIDENTIFIER:");
+- for (k = 0; k < comp->len; ++k)
+- pri_message(pri, " %02x", comp->data[k]);
+- pri_message(pri, ")");
+- break;
+- case ASN1_ENUMERATED:
+- for (k = l = 0; k < comp->len; ++k)
+- l = (l << 8) | comp->data[k];
+- pri_message(pri, " (ENUMERATED: %d)", l);
+- break;
+- case ASN1_SEQUENCE:
+- pri_message(pri, " (SEQUENCE)");
+- break;
+- default:
+- pri_message(pri, " (component %02x - %s)", comp->type, asn1id2text(comp->type & ASN1_TYPE_MASK));
+- break;
+- }
++ break;
++ default:
++ switch (redirectingreason) {
++ case PRI_REDIR_UNKNOWN:
++ value = Q952_DIVERT_REASON_UNKNOWN;
++ break;
++ case PRI_REDIR_FORWARD_ON_BUSY:
++ value = Q952_DIVERT_REASON_CFB;
++ break;
++ case PRI_REDIR_FORWARD_ON_NO_REPLY:
++ value = Q952_DIVERT_REASON_CFNR;
++ break;
++ case PRI_REDIR_DEFLECTION:
++ value = Q952_DIVERT_REASON_CD;
++ break;
++ case PRI_REDIR_UNCONDITIONAL:
++ value = Q952_DIVERT_REASON_CFU;
++ break;
++ case PRI_REDIR_DTE_OUT_OF_ORDER:
++ case PRI_REDIR_FORWARDED_BY_DTE:
++ pri_message(ctrl,
++ "!! Don't know how to convert Q.931 redirection reason %d to Q.952\n",
++ redirectingreason);
++ /* Fall through */
++ default:
++ value = Q952_DIVERT_REASON_UNKNOWN;
++ break;
+ }
+- else if ((comp->type & ASN1_CLAN_MASK) == ASN1_CONTEXT_SPECIFIC) {
+- pri_message(pri, " (CONTEXT SPECIFIC [%d])", comp->type & ASN1_TYPE_MASK);
++ break;
++ }
++
++ return value;
++}
++
++static int redirectingreason_for_q931(struct pri *ctrl, int redirectingreason)
++{
++ int value;
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_QSIG:
++ switch (redirectingreason) {
++ case QSIG_DIVERT_REASON_UNKNOWN:
++ value = PRI_REDIR_UNKNOWN;
++ break;
++ case QSIG_DIVERT_REASON_CFU:
++ value = PRI_REDIR_UNCONDITIONAL;
++ break;
++ case QSIG_DIVERT_REASON_CFB:
++ value = PRI_REDIR_FORWARD_ON_BUSY;
++ break;
++ case QSIG_DIVERT_REASON_CFNR:
++ value = PRI_REDIR_FORWARD_ON_NO_REPLY;
++ break;
++ default:
++ pri_message(ctrl, "!! Unknown Q.SIG diversion reason %d\n",
++ redirectingreason);
++ value = PRI_REDIR_UNKNOWN;
++ break;
+ }
+- else {
+- pri_message(pri, " (component %02x)", comp->type);
++ break;
++ default:
++ switch (redirectingreason) {
++ case Q952_DIVERT_REASON_UNKNOWN:
++ value = PRI_REDIR_UNKNOWN;
++ break;
++ case Q952_DIVERT_REASON_CFU:
++ value = PRI_REDIR_UNCONDITIONAL;
++ break;
++ case Q952_DIVERT_REASON_CFB:
++ value = PRI_REDIR_FORWARD_ON_BUSY;
++ break;
++ case Q952_DIVERT_REASON_CFNR:
++ value = PRI_REDIR_FORWARD_ON_NO_REPLY;
++ break;
++ case Q952_DIVERT_REASON_CD:
++ value = PRI_REDIR_DEFLECTION;
++ break;
++ case Q952_DIVERT_REASON_IMMEDIATE:
++ pri_message(ctrl,
++ "!! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog\n");
++ value = PRI_REDIR_UNKNOWN; /* ??? */
++ break;
++ default:
++ pri_message(ctrl, "!! Unknown Q.952 diversion reason %d\n",
++ redirectingreason);
++ value = PRI_REDIR_UNKNOWN;
++ break;
+ }
+- pri_message(pri, "\n");
+- if ((comp->type & ASN1_PC_MASK) == ASN1_CONSTRUCTOR)
+- j = asn1_dumprecursive(pri, comp->data, (comp->len ? comp->len : INT_MAX), level+1);
+- else
+- j = comp->len;
+- j += 2;
+- len -= j;
+- vdata += j;
+- clen += j;
++ break;
+ }
+- return clen;
++
++ return value;
+ }
+
+-int asn1_dump(struct pri *pri, void *comp, int len)
++/*!
++ * \brief Convert the Q.931 type-of-number field to facility.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param ton Q.931 ton/plan octet.
++ *
++ * \return PartyNumber enumeration value.
++ */
++static int typeofnumber_from_q931(struct pri *ctrl, int ton)
+ {
+- return asn1_dumprecursive(pri, comp, len, 0);
++ int value;
++
++ switch ((ton >> 4) & 0x03) {
++ default:
++ pri_message(ctrl, "!! Unsupported Q.931 TypeOfNumber value (%d)\n", ton);
++ /* fall through */
++ case PRI_TON_UNKNOWN:
++ value = Q932_TON_UNKNOWN;
++ break;
++ case PRI_TON_INTERNATIONAL:
++ value = Q932_TON_INTERNATIONAL;
++ break;
++ case PRI_TON_NATIONAL:
++ value = Q932_TON_NATIONAL;
++ break;
++ case PRI_TON_NET_SPECIFIC:
++ value = Q932_TON_NET_SPECIFIC;
++ break;
++ case PRI_TON_SUBSCRIBER:
++ value = Q932_TON_SUBSCRIBER;
++ break;
++ case PRI_TON_ABBREVIATED:
++ value = Q932_TON_ABBREVIATED;
++ break;
++ }
++
++ return value;
+ }
+
+-static unsigned char get_invokeid(struct pri *pri)
++static int typeofnumber_for_q931(struct pri *ctrl, int ton)
+ {
+- return ++pri->last_invoke;
++ int value;
++
++ switch (ton) {
++ default:
++ pri_message(ctrl, "!! Invalid TypeOfNumber %d\n", ton);
++ /* fall through */
++ case Q932_TON_UNKNOWN:
++ value = PRI_TON_UNKNOWN;
++ break;
++ case Q932_TON_INTERNATIONAL:
++ value = PRI_TON_INTERNATIONAL;
++ break;
++ case Q932_TON_NATIONAL:
++ value = PRI_TON_NATIONAL;
++ break;
++ case Q932_TON_NET_SPECIFIC:
++ value = PRI_TON_NET_SPECIFIC;
++ break;
++ case Q932_TON_SUBSCRIBER:
++ value = PRI_TON_SUBSCRIBER;
++ break;
++ case Q932_TON_ABBREVIATED:
++ value = PRI_TON_ABBREVIATED;
++ break;
++ }
++
++ return value << 4;
+ }
+
+-struct addressingdataelements_presentednumberunscreened {
+- char partyaddress[21];
+- char partysubaddress[21];
+- int npi; /* Numbering Plan Indicator */
+- int ton; /* Type Of Number */
+- int pres; /* Presentation */
+-};
++/*!
++ * \internal
++ * \brief Convert the Q.931 numbering plan field to facility.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param plan Q.931 ton/plan octet.
++ *
++ * \return PartyNumber enumeration value.
++ */
++static int numbering_plan_from_q931(struct pri *ctrl, int plan)
++{
++ int value;
+
+-struct addressingdataelements_presentednumberscreened {
+- char partyaddress[21];
+- char partysubaddress[21];
+- int npi; /* Numbering Plan Indicator */
+- int ton; /* Type Of Number */
+- int pres; /* Presentation */
+- int scrind; /* Screening Indicator */
+-};
++ switch (plan & 0x0F) {
++ default:
++ pri_message(ctrl, "!! Unsupported Q.931 numbering plan value (%d)\n", plan);
++ /* fall through */
++ case PRI_NPI_UNKNOWN:
++ value = 0; /* unknown */
++ break;
++ case PRI_NPI_E163_E164:
++ value = 1; /* public */
++ break;
++ case PRI_NPI_X121:
++ value = 3; /* data */
++ break;
++ case PRI_NPI_F69:
++ value = 4; /* telex */
++ break;
++ case PRI_NPI_NATIONAL:
++ value = 8; /* nationalStandard */
++ break;
++ case PRI_NPI_PRIVATE:
++ value = 5; /* private */
++ break;
++ }
+
+-#define PRI_CHECKOVERFLOW(size) \
+- if (msgptr - message + (size) >= sizeof(message)) { \
+- *msgptr = '\0'; \
+- pri_message(pri, "%s", message); \
+- msgptr = message; \
+- }
++ return value;
++}
+
+-static void dump_apdu(struct pri *pri, unsigned char *c, int len)
++/*!
++ * \internal
++ * \brief Convert the PartyNumber numbering plan to Q.931 plan field value.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param plan PartyNumber enumeration value.
++ *
++ * \return Q.931 plan field value.
++ */
++static int numbering_plan_for_q931(struct pri *ctrl, int plan)
+ {
+- #define MAX_APDU_LENGTH 255
+- static char hexs[16] = "0123456789ABCDEF";
+- int i;
+- char message[(2 + MAX_APDU_LENGTH * 3 + 6 + MAX_APDU_LENGTH + 3)] = ""; /* please adjust here, if you make changes below! */
+- char *msgptr;
+-
+- msgptr = message;
+- *msgptr++ = ' ';
+- *msgptr++ = '[';
+- for (i=0; i<len; i++) {
+- PRI_CHECKOVERFLOW(3);
+- *msgptr++ = ' ';
+- *msgptr++ = hexs[(c[i] >> 4) & 0x0f];
+- *msgptr++ = hexs[(c[i]) & 0x0f];
++ int value;
++
++ switch (plan) {
++ default:
++ pri_message(ctrl,
++ "!! Unsupported PartyNumber to Q.931 numbering plan value (%d)\n", plan);
++ /* fall through */
++ case 0: /* unknown */
++ value = PRI_NPI_UNKNOWN;
++ break;
++ case 1: /* public */
++ value = PRI_NPI_E163_E164;
++ break;
++ case 3: /* data */
++ value = PRI_NPI_X121;
++ break;
++ case 4: /* telex */
++ value = PRI_NPI_F69;
++ break;
++ case 5: /* private */
++ value = PRI_NPI_PRIVATE;
++ break;
++ case 8: /* nationalStandard */
++ value = PRI_NPI_NATIONAL;
++ break;
+ }
+- PRI_CHECKOVERFLOW(6);
+- strcpy(msgptr, " ] - [");
+- msgptr += strlen(msgptr);
+- for (i=0; i<len; i++) {
+- PRI_CHECKOVERFLOW(1);
+- *msgptr++ = ((c[i] < ' ') || (c[i] > '~')) ? '.' : c[i];
++
++ return value;
++}
++
++/*!
++ * \internal
++ * \brief Convert the Q.931 number presentation field to facility.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Q.931 presentation/screening octet.
++ * \param number_present Non-zero if the number is available.
++ *
++ * \return Presented<Number/Address><Screened/Unscreened> enumeration value.
++ */
++static int presentation_from_q931(struct pri *ctrl, int presentation, int number_present)
++{
++ int value;
++
++ switch (presentation & PRI_PRES_RESTRICTION) {
++ case PRI_PRES_ALLOWED:
++ value = 0; /* presentationAllowed<Number/Address> */
++ break;
++ default:
++ pri_message(ctrl, "!! Unsupported Q.931 number presentation value (%d)\n",
++ presentation);
++ /* fall through */
++ case PRI_PRES_RESTRICTED:
++ if (number_present) {
++ value = 3; /* presentationRestricted<Number/Address> */
++ } else {
++ value = 1; /* presentationRestricted */
++ }
++ break;
++ case PRI_PRES_UNAVAILABLE:
++ value = 2; /* numberNotAvailableDueToInterworking */
++ break;
+ }
+- PRI_CHECKOVERFLOW(2);
+- *msgptr++ = ']';
+- *msgptr++ = '\n';
+- *msgptr = '\0';
+- pri_message(pri, "%s", message);
++
++ return value;
+ }
+-#undef PRI_CHECKOVERFLOW
+
+-int redirectingreason_from_q931(struct pri *pri, int redirectingreason)
++/*!
++ * \internal
++ * \brief Convert the Presented<Number/Address><Screened/Unscreened> presentation
++ * to Q.931 presentation field value.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Presented<Number/Address><Screened/Unscreened> value.
++ *
++ * \return Q.931 presentation field value.
++ */
++static int presentation_for_q931(struct pri *ctrl, int presentation)
+ {
+- switch(pri->switchtype) {
+- case PRI_SWITCH_QSIG:
+- switch(redirectingreason) {
+- case PRI_REDIR_UNKNOWN:
+- return QSIG_DIVERT_REASON_UNKNOWN;
+- case PRI_REDIR_FORWARD_ON_BUSY:
+- return QSIG_DIVERT_REASON_CFB;
+- case PRI_REDIR_FORWARD_ON_NO_REPLY:
+- return QSIG_DIVERT_REASON_CFNR;
+- case PRI_REDIR_UNCONDITIONAL:
+- return QSIG_DIVERT_REASON_CFU;
+- case PRI_REDIR_DEFLECTION:
+- case PRI_REDIR_DTE_OUT_OF_ORDER:
+- case PRI_REDIR_FORWARDED_BY_DTE:
+- pri_message(pri, "!! Don't know how to convert Q.931 redirection reason %d to Q.SIG\n", redirectingreason);
+- /* Fall through */
+- default:
+- return QSIG_DIVERT_REASON_UNKNOWN;
+- }
+- default:
+- switch(redirectingreason) {
+- case PRI_REDIR_UNKNOWN:
+- return Q952_DIVERT_REASON_UNKNOWN;
+- case PRI_REDIR_FORWARD_ON_BUSY:
+- return Q952_DIVERT_REASON_CFB;
+- case PRI_REDIR_FORWARD_ON_NO_REPLY:
+- return Q952_DIVERT_REASON_CFNR;
+- case PRI_REDIR_DEFLECTION:
+- return Q952_DIVERT_REASON_CD;
+- case PRI_REDIR_UNCONDITIONAL:
+- return Q952_DIVERT_REASON_CFU;
+- case PRI_REDIR_DTE_OUT_OF_ORDER:
+- case PRI_REDIR_FORWARDED_BY_DTE:
+- pri_message(pri, "!! Don't know how to convert Q.931 redirection reason %d to Q.952\n", redirectingreason);
+- /* Fall through */
+- default:
+- return Q952_DIVERT_REASON_UNKNOWN;
+- }
++ int value;
++
++ switch (presentation) {
++ case 0: /* presentationAllowed<Number/Address> */
++ value = PRI_PRES_ALLOWED;
++ break;
++ default:
++ pri_message(ctrl,
++ "!! Unsupported Presented<Number/Address><Screened/Unscreened> to Q.931 value (%d)\n",
++ presentation);
++ /* fall through */
++ case 1: /* presentationRestricted */
++ case 3: /* presentationRestricted<Number/Address> */
++ value = PRI_PRES_RESTRICTED;
++ break;
++ case 2: /* numberNotAvailableDueToInterworking */
++ value = PRI_PRES_UNAVAILABLE;
++ break;
+ }
++
++ return value;
+ }
+
+-static int redirectingreason_for_q931(struct pri *pri, int redirectingreason)
++/*!
++ * \internal
++ * \brief Convert the Q.931 number presentation field to Q.SIG name presentation.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Q.931 presentation/screening octet.
++ * \param name_present Non-zero if the name is available.
++ *
++ * \return Name presentation enumeration value.
++ */
++static int qsig_name_presentation_from_q931(struct pri *ctrl, int presentation, int name_present)
+ {
+- switch(pri->switchtype) {
+- case PRI_SWITCH_QSIG:
+- switch(redirectingreason) {
+- case QSIG_DIVERT_REASON_UNKNOWN:
+- return PRI_REDIR_UNKNOWN;
+- case QSIG_DIVERT_REASON_CFU:
+- return PRI_REDIR_UNCONDITIONAL;
+- case QSIG_DIVERT_REASON_CFB:
+- return PRI_REDIR_FORWARD_ON_BUSY;
+- case QSIG_DIVERT_REASON_CFNR:
+- return PRI_REDIR_FORWARD_ON_NO_REPLY;
+- default:
+- pri_message(pri, "!! Unknown Q.SIG diversion reason %d\n", redirectingreason);
+- return PRI_REDIR_UNKNOWN;
+- }
+- default:
+- switch(redirectingreason) {
+- case Q952_DIVERT_REASON_UNKNOWN:
+- return PRI_REDIR_UNKNOWN;
+- case Q952_DIVERT_REASON_CFU:
+- return PRI_REDIR_UNCONDITIONAL;
+- case Q952_DIVERT_REASON_CFB:
+- return PRI_REDIR_FORWARD_ON_BUSY;
+- case Q952_DIVERT_REASON_CFNR:
+- return PRI_REDIR_FORWARD_ON_NO_REPLY;
+- case Q952_DIVERT_REASON_CD:
+- return PRI_REDIR_DEFLECTION;
+- case Q952_DIVERT_REASON_IMMEDIATE:
+- pri_message(pri, "!! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog\n");
+- return PRI_REDIR_UNKNOWN; /* ??? */
+- default:
+- pri_message(pri, "!! Unknown Q.952 diversion reason %d\n", redirectingreason);
+- return PRI_REDIR_UNKNOWN;
+- }
++ int value;
++
++ switch (presentation & PRI_PRES_RESTRICTION) {
++ case PRI_PRES_ALLOWED:
++ if (name_present) {
++ value = 1; /* presentation_allowed */
++ } else {
++ value = 4; /* name_not_available */
++ }
++ break;
++ default:
++ pri_message(ctrl, "!! Unsupported Q.931 number presentation value (%d)\n",
++ presentation);
++ /* fall through */
++ case PRI_PRES_RESTRICTED:
++ if (name_present) {
++ value = 2; /* presentation_restricted */
++ } else {
++ value = 3; /* presentation_restricted_null */
++ }
++ break;
++ case PRI_PRES_UNAVAILABLE:
++ value = 4; /* name_not_available */
++ break;
+ }
++
++ return value;
+ }
+
+-int typeofnumber_from_q931(struct pri *pri, int ton)
++/*!
++ * \internal
++ * \brief Convert the Q.SIG name presentation to Q.931 presentation field value.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Q.SIG name presentation value.
++ *
++ * \return Q.931 presentation field value.
++ */
++static int qsig_name_presentation_for_q931(struct pri *ctrl, int presentation)
+ {
+- switch(ton) {
+- case PRI_TON_INTERNATIONAL:
+- return Q932_TON_INTERNATIONAL;
+- case PRI_TON_NATIONAL:
+- return Q932_TON_NATIONAL;
+- case PRI_TON_NET_SPECIFIC:
+- return Q932_TON_NET_SPECIFIC;
+- case PRI_TON_SUBSCRIBER:
+- return Q932_TON_SUBSCRIBER;
+- case PRI_TON_ABBREVIATED:
+- return Q932_TON_ABBREVIATED;
+- case PRI_TON_RESERVED:
+- default:
+- pri_message(pri, "!! Unsupported Q.931 TypeOfNumber value (%d)\n", ton);
+- /* fall through */
+- case PRI_TON_UNKNOWN:
+- return Q932_TON_UNKNOWN;
++ int value;
++
++ switch (presentation) {
++ case 1: /* presentation_allowed */
++ value = PRI_PRES_ALLOWED;
++ break;
++ default:
++ pri_message(ctrl,
++ "!! Unsupported Q.SIG name presentation to Q.931 value (%d)\n",
++ presentation);
++ /* fall through */
++ case 2: /* presentation_restricted */
++ case 3: /* presentation_restricted_null */
++ value = PRI_PRES_RESTRICTED;
++ break;
++ case 0: /* optional_name_not_present */
++ case 4: /* name_not_available */
++ value = PRI_PRES_UNAVAILABLE;
++ break;
+ }
++
++ return value;
+ }
+
+-static int typeofnumber_for_q931(struct pri *pri, int ton)
++/*!
++ * \internal
++ * \brief Convert number presentation to Q.SIG diversion subscription notification.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param presentation Number presentation value.
++ *
++ * \return Q.SIG diversion subscription notification value.
++ */
++static int presentation_to_subscription(struct pri *ctrl, int presentation)
+ {
+- switch (ton) {
+- case Q932_TON_UNKNOWN:
+- return PRI_TON_UNKNOWN;
+- case Q932_TON_INTERNATIONAL:
+- return PRI_TON_INTERNATIONAL;
+- case Q932_TON_NATIONAL:
+- return PRI_TON_NATIONAL;
+- case Q932_TON_NET_SPECIFIC:
+- return PRI_TON_NET_SPECIFIC;
+- case Q932_TON_SUBSCRIBER:
+- return PRI_TON_SUBSCRIBER;
+- case Q932_TON_ABBREVIATED:
+- return PRI_TON_ABBREVIATED;
+- default:
+- pri_message(pri, "!! Invalid Q.932 TypeOfNumber %d\n", ton);
+- return PRI_TON_UNKNOWN;
++ /* derive subscription value from presentation value */
++
++ switch (presentation & PRI_PRES_RESTRICTION) {
++ case PRI_PRES_ALLOWED:
++ return QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR;
++ case PRI_PRES_RESTRICTED:
++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR;
++ case PRI_PRES_UNAVAILABLE: /* Number not available due to interworking */
++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR; /* ?? QSIG_NO_NOTIFICATION */
++ default:
++ pri_message(ctrl, "!! Unknown Q.SIG presentationIndicator 0x%02x\n",
++ presentation);
++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR;
+ }
+ }
+
+-int asn1_name_decode(void * data, int len, char *namebuf, int buflen)
++/*!
++ * \internal
++ * \brief Copy the given rose party number to the q931_party_number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_number Q.931 party number structure
++ * \param rose_number ROSE party number structure
++ *
++ * \note It is assumed that the q931_number has been initialized before calling.
++ *
++ * \return Nothing
++ */
++static void rose_copy_number_to_q931(struct pri *ctrl,
++ struct q931_party_number *q931_number, const struct rosePartyNumber *rose_number)
+ {
+- struct rose_component *comp = (struct rose_component*)data;
+- int datalen = 0, res = 0;
++ //q931_party_number_init(q931_number);
++ libpri_copy_string(q931_number->str, (char *) rose_number->str,
++ sizeof(q931_number->str));
++ q931_number->plan = numbering_plan_for_q931(ctrl, rose_number->plan)
++ | typeofnumber_for_q931(ctrl, rose_number->ton);
++ q931_number->valid = 1;
++}
+
+- if (comp->len == ASN1_LEN_INDEF) {
+- datalen = strlen((char *)comp->data);
+- res = datalen + 2;
+- } else
+- datalen = res = comp->len;
++/*!
++ * \internal
++ * \brief Copy the given rose subaddress to the q931_party_subaddress.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_subaddress Q.931 party subaddress structure
++ * \param rose_subaddress ROSE subaddress structure
++ *
++ * \note It is assumed that the q931_subaddress has been initialized before calling.
++ *
++ * \return Nothing
++ */
++static void rose_copy_subaddress_to_q931(struct pri *ctrl,
++ struct q931_party_subaddress *q931_subaddress,
++ const struct rosePartySubaddress *rose_subaddress)
++{
++ //q931_party_subaddress_init(q931_subaddress);
++ if (!rose_subaddress->length) {
++ /* Subaddress is not present. */
++ return;
++ }
+
+- if (datalen > buflen) {
+- /* Truncate */
+- datalen = buflen;
++ switch (rose_subaddress->type) {
++ case 0:/* UserSpecified */
++ q931_subaddress->type = 2;/* user_specified */
++ q931_subaddress->valid = 1;
++ q931_subaddress->length = rose_subaddress->length;
++ if (sizeof(q931_subaddress->data) <= q931_subaddress->length) {
++ q931_subaddress->length = sizeof(q931_subaddress->data) - 1;
++ }
++ memcpy(q931_subaddress->data, rose_subaddress->u.user_specified.information,
++ q931_subaddress->length);
++ q931_subaddress->data[q931_subaddress->length] = '\0';
++ if (rose_subaddress->u.user_specified.odd_count_present) {
++ q931_subaddress->odd_even_indicator =
++ rose_subaddress->u.user_specified.odd_count;
++ }
++ break;
++ case 1:/* NSAP */
++ q931_subaddress->type = 0;/* nsap */
++ q931_subaddress->valid = 1;
++ libpri_copy_string((char *) q931_subaddress->data,
++ (char *) rose_subaddress->u.nsap, sizeof(q931_subaddress->data));
++ q931_subaddress->length = strlen((char *) q931_subaddress->data);
++ break;
++ default:
++ /* Don't know how to encode so assume it is not present. */
++ break;
+ }
+- memcpy(namebuf, comp->data, datalen);
+- return res + 2;
+ }
+
+-int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len)
++/*!
++ * \internal
++ * \brief Copy the given rose address to the q931_party_id address.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_address Q.931 party id structure to fill address
++ * \param rose_address ROSE address structure
++ *
++ * \note It is assumed that the q931_address has been initialized before calling.
++ *
++ * \return Nothing
++ */
++static void rose_copy_address_to_q931(struct pri *ctrl,
++ struct q931_party_id *q931_address, const struct roseAddress *rose_address)
+ {
+- struct rose_component *comp = NULL;
+-
+- if (len < 2 + src_len)
+- return -1;
++ rose_copy_number_to_q931(ctrl, &q931_address->number, &rose_address->number);
++ rose_copy_subaddress_to_q931(ctrl, &q931_address->subaddress,
++ &rose_address->subaddress);
++}
+
+- if (max_len && (src_len > max_len))
+- src_len = max_len;
++/*!
++ * \internal
++ * \brief Copy the given rose presented screened party number to the q931_party_number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_number Q.931 party number structure
++ * \param rose_presented ROSE presented screened party number structure
++ *
++ * \return Nothing
++ */
++static void rose_copy_presented_number_screened_to_q931(struct pri *ctrl,
++ struct q931_party_number *q931_number,
++ const struct rosePresentedNumberScreened *rose_presented)
++{
++ q931_party_number_init(q931_number);
++ q931_number->valid = 1;
++ q931_number->presentation = presentation_for_q931(ctrl, rose_presented->presentation);
++ switch (rose_presented->presentation) {
++ case 0: /* presentationAllowedNumber */
++ case 3: /* presentationRestrictedNumber */
++ q931_number->presentation |=
++ (rose_presented->screened.screening_indicator & PRI_PRES_NUMBER_TYPE);
++ rose_copy_number_to_q931(ctrl, q931_number,
++ &rose_presented->screened.number);
++ break;
++ default:
++ q931_number->presentation |= PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ }
++}
+
+- comp = (struct rose_component *)data;
+- comp->type = asn1_type;
+- comp->len = src_len;
+- memcpy(comp->data, src, src_len);
+-
+- return 2 + src_len;
++/*!
++ * \internal
++ * \brief Copy the given rose presented unscreened party number to the q931_party_number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_number Q.931 party number structure
++ * \param rose_presented ROSE presented unscreened party number structure
++ *
++ * \return Nothing
++ */
++static void rose_copy_presented_number_unscreened_to_q931(struct pri *ctrl,
++ struct q931_party_number *q931_number,
++ const struct rosePresentedNumberUnscreened *rose_presented)
++{
++ q931_party_number_init(q931_number);
++ q931_number->valid = 1;
++ q931_number->presentation = presentation_for_q931(ctrl,
++ rose_presented->presentation) | PRI_PRES_USER_NUMBER_UNSCREENED;
++ switch (rose_presented->presentation) {
++ case 0: /* presentationAllowedNumber */
++ case 3: /* presentationRestrictedNumber */
++ rose_copy_number_to_q931(ctrl, q931_number, &rose_presented->number);
++ break;
++ default:
++ break;
++ }
+ }
+
+-int asn1_copy_string(char * buf, int buflen, struct rose_component *comp)
++/*!
++ * \internal
++ * \brief Copy the given rose presented screened party address to the q931_party_number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param q931_address Q.931 party id structure to fill the address
++ * \param rose_presented ROSE presented screened party address structure
++ *
++ * \return Nothing
++ */
++static void rose_copy_presented_address_screened_to_q931(struct pri *ctrl,
++ struct q931_party_id *q931_address,
++ const struct rosePresentedAddressScreened *rose_presented)
+ {
+- int res;
+- int datalen;
++ q931_party_number_init(&q931_address->number);
++ q931_party_subaddress_init(&q931_address->subaddress);
++ q931_address->number.valid = 1;
++ q931_address->number.presentation = presentation_for_q931(ctrl,
++ rose_presented->presentation);
++ switch (rose_presented->presentation) {
++ case 0: /* presentationAllowedAddress */
++ case 3: /* presentationRestrictedAddress */
++ q931_address->number.presentation |=
++ (rose_presented->screened.screening_indicator & PRI_PRES_NUMBER_TYPE);
++ rose_copy_number_to_q931(ctrl, &q931_address->number,
++ &rose_presented->screened.number);
++ rose_copy_subaddress_to_q931(ctrl, &q931_address->subaddress,
++ &rose_presented->screened.subaddress);
++ break;
++ default:
++ q931_address->number.presentation |= PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ }
++}
+
+- if ((comp->len > buflen) && (comp->len != ASN1_LEN_INDEF))
+- return -1;
++/*!
++ * \internal
++ * \brief Copy the given rose party name to the q931_party_name
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param qsig_name Q.SIG party name structure
++ * \param rose_name Q.SIG ROSE party name structure
++ *
++ * \return Nothing
++ */
++static void rose_copy_name_to_q931(struct pri *ctrl,
++ struct q931_party_name *qsig_name, const struct roseQsigName *rose_name)
++{
++ //q931_party_name_init(qsig_name);
++ qsig_name->valid = 1;
++ qsig_name->presentation = qsig_name_presentation_for_q931(ctrl,
++ rose_name->presentation);
++ qsig_name->char_set = rose_name->char_set;
++ libpri_copy_string(qsig_name->str, (char *) rose_name->data, sizeof(qsig_name->str));
++}
+
+- if (comp->len == ASN1_LEN_INDEF) {
+- datalen = strlen((char*)comp->data);
+- res = datalen + 2;
+- } else
+- res = datalen = comp->len;
++/*!
++ * \internal
++ * \brief Copy the given q931_party_number to the rose party number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_number ROSE party number structure
++ * \param q931_number Q.931 party number structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_number_to_rose(struct pri *ctrl,
++ struct rosePartyNumber *rose_number, const struct q931_party_number *q931_number)
++{
++ rose_number->plan = numbering_plan_from_q931(ctrl, q931_number->plan);
++ rose_number->ton = typeofnumber_from_q931(ctrl, q931_number->plan);
++ /* Truncate the q931_number->str if necessary. */
++ libpri_copy_string((char *) rose_number->str, q931_number->str,
++ sizeof(rose_number->str));
++ rose_number->length = strlen((char *) rose_number->str);
++}
+
+- memcpy(buf, comp->data, datalen);
+- buf[datalen] = 0;
++/*!
++ * \internal
++ * \brief Copy the given q931_party_subaddress to the rose subaddress.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_subaddress ROSE subaddress structure
++ * \param q931_subaddress Q.931 party subaddress structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_subaddress_to_rose(struct pri *ctrl,
++ struct rosePartySubaddress *rose_subaddress,
++ const struct q931_party_subaddress *q931_subaddress)
++{
++ if (!q931_subaddress->valid) {
++ /* Subaddress is not present. */
++ rose_subaddress->length = 0;
++ return;
++ }
+
+- return res;
++ switch (q931_subaddress->type) {
++ case 0: /* NSAP */
++ rose_subaddress->type = 1;/* NSAP */
++ libpri_copy_string((char *) rose_subaddress->u.nsap,
++ (char *) q931_subaddress->data, sizeof(rose_subaddress->u.nsap));
++ rose_subaddress->length = strlen((char *) rose_subaddress->u.nsap);
++ break;
++ case 2: /* user_specified */
++ rose_subaddress->type = 0;/* UserSpecified */
++ rose_subaddress->length = q931_subaddress->length;
++ if (sizeof(rose_subaddress->u.user_specified.information)
++ <= rose_subaddress->length) {
++ rose_subaddress->length =
++ sizeof(rose_subaddress->u.user_specified.information) - 1;
++ } else {
++ if (q931_subaddress->odd_even_indicator) {
++ rose_subaddress->u.user_specified.odd_count_present = 1;
++ rose_subaddress->u.user_specified.odd_count = 1;
++ }
++ }
++ memcpy(rose_subaddress->u.user_specified.information, q931_subaddress->data,
++ rose_subaddress->length);
++ rose_subaddress->u.user_specified.information[rose_subaddress->length] = '\0';
++ break;
++ default:
++ /* Don't know how to encode so assume it is not present. */
++ rose_subaddress->length = 0;
++ break;
++ }
+ }
+
+-static int rose_number_digits_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \internal
++ * \brief Copy the given q931_party_id address to the rose address.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_address ROSE address structure
++ * \param q931_address Q.931 party id structure to give address
++ *
++ * \return Nothing
++ */
++static void q931_copy_address_to_rose(struct pri *ctrl, struct roseAddress *rose_address,
++ const struct q931_party_id *q931_address)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
+- int datalen = 0;
+- int res = 0;
++ q931_copy_number_to_rose(ctrl, &rose_address->number, &q931_address->number);
++ q931_copy_subaddress_to_rose(ctrl, &rose_address->subaddress,
++ &q931_address->subaddress);
++}
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_NUMERICSTRING, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n");
+- if(comp->len > 20 && comp->len != ASN1_LEN_INDEF) {
+- pri_message(pri, "!! Oversized NumberDigits component (%d)\n", comp->len);
+- return -1;
+- }
+- if (comp->len == ASN1_LEN_INDEF) {
+- datalen = strlen((char *)comp->data);
+- res = datalen + 2;
+- } else
+- res = datalen = comp->len;
+-
+- memcpy(value->partyaddress, comp->data, datalen);
+- value->partyaddress[datalen] = '\0';
++/*!
++ * \internal
++ * \brief Copy the given q931_party_number to the rose presented screened party number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_presented ROSE presented screened party number structure
++ * \param q931_number Q.931 party number structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_presented_number_screened_to_rose(struct pri *ctrl,
++ struct rosePresentedNumberScreened *rose_presented,
++ const struct q931_party_number *q931_number)
++{
++ if (q931_number->valid) {
++ rose_presented->presentation =
++ presentation_from_q931(ctrl, q931_number->presentation, q931_number->str[0]);
++ rose_presented->screened.screening_indicator =
++ q931_number->presentation & PRI_PRES_NUMBER_TYPE;
++ q931_copy_number_to_rose(ctrl, &rose_presented->screened.number, q931_number);
++ } else {
++ rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */
++ }
++}
+
+- return res + 2;
++/*!
++ * \internal
++ * \brief Copy the given q931_party_number to the rose presented unscreened party number
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_presented ROSE presented unscreened party number structure
++ * \param q931_number Q.931 party number structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_presented_number_unscreened_to_rose(struct pri *ctrl,
++ struct rosePresentedNumberUnscreened *rose_presented,
++ const struct q931_party_number *q931_number)
++{
++ if (q931_number->valid) {
++ rose_presented->presentation =
++ presentation_from_q931(ctrl, q931_number->presentation, q931_number->str[0]);
++ q931_copy_number_to_rose(ctrl, &rose_presented->number, q931_number);
++ } else {
++ rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */
+ }
+- while(0);
+-
+- return -1;
+ }
+
+-static int rose_public_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++#if 0 /* In case it is needed in the future */
++/*!
++ * \internal
++ * \brief Copy the given q931_party_number to the rose presented screened party address
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_presented ROSE presented screened party address structure
++ * \param q931_address Q.931 party id structure to get the address
++ *
++ * \return Nothing
++ */
++static void q931_copy_presented_address_screened_to_rose(struct pri *ctrl,
++ struct rosePresentedAddressScreened *rose_presented,
++ const struct q931_party_id *q931_address)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
+- int ton;
+- int res = 0;
++ if (q931_address->number.valid) {
++ rose_presented->presentation =
++ presentation_from_q931(ctrl, q931_address->number.presentation,
++ q931_address->number.str[0]);
++ rose_presented->screened.screening_indicator =
++ q931_address->number.presentation & PRI_PRES_NUMBER_TYPE;
++ q931_copy_number_to_rose(ctrl, &rose_presented->screened.number,
++ &q931_address->number);
++ q931_copy_subaddress_to_rose(ctrl, &rose_presented->screened.subaddress,
++ &q931_address->subaddress);
++ } else {
++ rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */
++ }
++}
++#endif /* In case it is needed in the future */
+
+- if (len < 2)
+- return -1;
++/*!
++ * \internal
++ * \brief Copy the given q931_party_name to the rose party name
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param rose_name Q.SIG ROSE party name structure
++ * \param qsig_name Q.SIG party name structure
++ *
++ * \return Nothing
++ */
++static void q931_copy_name_to_rose(struct pri *ctrl,
++ struct roseQsigName *rose_name, const struct q931_party_name *qsig_name)
++{
++ if (qsig_name->valid) {
++ rose_name->presentation = qsig_name_presentation_from_q931(ctrl,
++ qsig_name->presentation, qsig_name->str[0]);
++ rose_name->char_set = qsig_name->char_set;
++ /* Truncate the qsig_name->str if necessary. */
++ libpri_copy_string((char *) rose_name->data, qsig_name->str, sizeof(rose_name->data));
++ rose_name->length = strlen((char *) rose_name->data);
++ } else {
++ rose_name->presentation = 4;/* name_not_available */
++ }
++}
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n");
+- ASN1_GET_INTEGER(comp, ton);
+- NEXT_COMPONENT(comp, i);
+- ton = typeofnumber_for_q931(pri, ton);
++/*!
++ * \internal
++ * \brief Encode the Q.SIG DivertingLegInformation1 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode diversion leg 1.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_diverting_leg_information1(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value);
+- if (res < 0)
+- return -1;
+- value->ton = ton;
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
+- return res + 3;
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_DivertingLegInformation1;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.qsig.DivertingLegInformation1.diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.reason);
+
+- } while(0);
+- return -1;
++ /* subscriptionOption is the redirecting.to.number.presentation */
++ msg.args.qsig.DivertingLegInformation1.subscription_option =
++ presentation_to_subscription(ctrl, call->redirecting.to.number.presentation);
++
++ /* nominatedNr is the redirecting.to.number */
++ q931_copy_number_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation1.nominated_number,
++ &call->redirecting.to.number);
++
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+
+-static int rose_private_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \internal
++ * \brief Encode the ETSI DivertingLegInformation1 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode diversion leg 1.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_diverting_leg_information1(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
+- int ton;
+- int res = 0;
++ struct rose_msg_invoke msg;
+
+- if (len < 2)
+- return -1;
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PrivatePartyNumber ROSE component type 0x%x\n");
+- ASN1_GET_INTEGER(comp, ton);
+- NEXT_COMPONENT(comp, i);
+- ton = typeofnumber_for_q931(pri, ton);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_DivertingLegInformation1;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.etsi.DivertingLegInformation1.diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.reason);
+
+- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value);
+- if (res < 0)
+- return -1;
+- value->ton = ton;
++ if (call->redirecting.to.number.valid) {
++ msg.args.etsi.DivertingLegInformation1.subscription_option = 2;
+
+- return res + 3;
++ /* divertedToNumber is the redirecting.to.number */
++ msg.args.etsi.DivertingLegInformation1.diverted_to_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.DivertingLegInformation1.diverted_to,
++ &call->redirecting.to.number);
++ } else {
++ msg.args.etsi.DivertingLegInformation1.subscription_option = 1;
++ }
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- } while(0);
+- return -1;
++ return pos;
+ }
+
+-static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \brief Encode and queue the DivertingLegInformation1 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode diversion leg 1.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rose_diverting_leg_information1_encode(struct pri *ctrl, q931_call *call)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
+- int res = 0;
++ unsigned char buffer[256];
++ unsigned char *end;
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end = enc_etsi_diverting_leg_information1(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ case PRI_SWITCH_QSIG:
++ end = enc_qsig_diverting_leg_information1(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ default:
++ return -1;
++ }
++ if (!end) {
++ return -1;
++ }
+
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] unknownPartyNumber */
+- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_UNKNOWN;
+- value->ton = PRI_TON_UNKNOWN;
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] unknownPartyNumber */
+- res = asn1_copy_string(value->partyaddress, sizeof(value->partyaddress), comp);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_UNKNOWN;
+- value->ton = PRI_TON_UNKNOWN;
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] publicPartyNumber */
+- res = rose_public_party_number_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_E163_E164;
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* [2] nsapEncodedNumber */
+- pri_message(pri, "!! NsapEncodedNumber isn't handled\n");
+- return -1;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] dataPartyNumber */
+- if(rose_number_digits_decode(pri, call, comp->data, comp->len, value))
+- return -1;
+- value->npi = PRI_NPI_X121 /* ??? */;
+- value->ton = PRI_TON_UNKNOWN /* ??? */;
+- pri_message(pri, "!! dataPartyNumber isn't handled\n");
+- return -1;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] telexPartyNumber */
+- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_F69 /* ??? */;
+- value->ton = PRI_TON_UNKNOWN /* ??? */;
+- pri_message(pri, "!! telexPartyNumber isn't handled\n");
+- return -1;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] priavePartyNumber */
+- res = rose_private_party_number_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_PRIVATE;
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] nationalStandardPartyNumber */
+- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (res < 0)
+- return -1;
+- value->npi = PRI_NPI_NATIONAL;
+- value->ton = PRI_TON_NATIONAL;
+- break;
+- default:
+- pri_message(pri, "!! Unknown Party number component received 0x%X\n", comp->type);
+- return -1;
++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
++}
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG DivertingLegInformation2 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode diversion leg 2.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_diverting_leg_information2(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
++
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
++
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_DivertingLegInformation2;
++ msg.invoke_id = get_invokeid(ctrl);
++
++ /* diversionCounter is the redirecting.count */
++ msg.args.qsig.DivertingLegInformation2.diversion_counter = call->redirecting.count;
++
++ msg.args.qsig.DivertingLegInformation2.diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.reason);
++
++ /* divertingNr is the redirecting.from.number */
++ msg.args.qsig.DivertingLegInformation2.diverting_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation2.diverting,
++ &call->redirecting.from.number);
++
++ /* redirectingName is the redirecting.from.name */
++ if (call->redirecting.from.name.valid) {
++ msg.args.qsig.DivertingLegInformation2.redirecting_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation2.redirecting_name,
++ &call->redirecting.from.name);
++ }
++
++ if (1 < call->redirecting.count) {
++ /* originalCalledNr is the redirecting.orig_called.number */
++ msg.args.qsig.DivertingLegInformation2.original_called_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation2.original_called,
++ &call->redirecting.orig_called.number);
++
++ msg.args.qsig.DivertingLegInformation2.original_diversion_reason_present = 1;
++ if (call->redirecting.orig_called.number.valid) {
++ msg.args.qsig.DivertingLegInformation2.original_diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.orig_reason);
++ } else {
++ msg.args.qsig.DivertingLegInformation2.original_diversion_reason =
++ QSIG_DIVERT_REASON_UNKNOWN;
+ }
+- ASN1_FIXUP_LEN(comp, res);
+- NEXT_COMPONENT(comp, i);
+- if(i < len)
+- pri_message(pri, "!! not all information is handled from Address component\n");
+- return res + 2;
++
++ /* originalCalledName is the redirecting.orig_called.name */
++ if (call->redirecting.orig_called.name.valid) {
++ msg.args.qsig.DivertingLegInformation2.original_called_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation2.original_called_name,
++ &call->redirecting.orig_called.name);
++ }
+ }
+- while (0);
+
+- return -1;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+
+-static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \internal
++ * \brief Encode the ETSI DivertingLegInformation2 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode diversion leg 2.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_diverting_leg_information2(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
+ {
+- int i = 0;
+- int size = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
++ struct rose_msg_invoke msg;
+
+- /* Fill in default values */
+- value->ton = PRI_TON_UNKNOWN;
+- value->npi = PRI_NPI_E163_E164;
+- value->pres = -1; /* Data is not available */
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_DivertingLegInformation2;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] presentationAllowedNumber */
+- value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+- size = rose_address_decode(pri, call, comp->data, comp->len, value);
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
+- if (comp->len != 0) { /* must be NULL */
+- pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
+- return -1;
+- }
+- value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+- return 2;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */
+- if (comp->len != 0) { /* must be NULL */
+- pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
+- return -1;
+- }
+- value->pres = PRES_NUMBER_NOT_AVAILABLE;
+- return 2;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] presentationRestrictedNumber */
+- value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
+- size = rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
+- default:
+- pri_message(pri, "Invalid PresentedNumberUnscreened component 0x%X\n", comp->type);
+- }
+- return -1;
++ /* diversionCounter is the redirecting.count */
++ msg.args.etsi.DivertingLegInformation2.diversion_counter = call->redirecting.count;
++
++ msg.args.etsi.DivertingLegInformation2.diversion_reason =
++ redirectingreason_from_q931(ctrl, call->redirecting.reason);
++
++ /* divertingNr is the redirecting.from.number */
++ msg.args.etsi.DivertingLegInformation2.diverting_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.DivertingLegInformation2.diverting,
++ &call->redirecting.from.number);
++
++ if (1 < call->redirecting.count) {
++ /* originalCalledNr is the redirecting.orig_called.number */
++ msg.args.etsi.DivertingLegInformation2.original_called_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.DivertingLegInformation2.original_called,
++ &call->redirecting.orig_called.number);
+ }
+- while (0);
+
+- return -1;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+
+-static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
++/*!
++ * \internal
++ * \brief Encode and queue the DivertingLegInformation2 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode diversion leg 2.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_diverting_leg_information2_encode(struct pri *ctrl, q931_call *call)
+ {
+- int i = 0;
+- int diversion_counter;
+- int diversion_reason;
+- char origcalledname[50] = "", redirectingname[50] = "";
+- struct addressingdataelements_presentednumberunscreened divertingnr;
+- struct addressingdataelements_presentednumberunscreened originalcallednr;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = sequence->data;
+- int res = 0;
+- memset(&divertingnr, 0, sizeof(divertingnr));
+- memset(&originalcallednr, 0, sizeof(originalcallednr));
++ unsigned char buffer[256];
++ unsigned char *end;
+
+- /* Data checks */
+- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
+- pri_message(pri, "Invalid DivertingLegInformation2Type argument\n");
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end = enc_etsi_diverting_leg_information2(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ case PRI_SWITCH_QSIG:
++ end = enc_qsig_diverting_leg_information2(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ default:
+ return -1;
+ }
++ if (!end) {
++ return -1;
++ }
+
+- if (sequence->len == ASN1_LEN_INDEF) {
+- len -= 4; /* For the 2 extra characters at the end
+- * and two characters of header */
+- } else
+- len -= 2;
++ return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
++}
+
+- do {
+- /* diversionCounter stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do it diversionCounter is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, diversion_counter);
+- NEXT_COMPONENT(comp, i);
++/*!
++ * \internal
++ * \brief Encode the Q.SIG DivertingLegInformation3 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode diversion leg 3.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_diverting_leg_information3(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- /* diversionReason stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid diversionReason type 0x%X of ROSE divertingLegInformation2 component received\n");
+- ASN1_GET_INTEGER(comp, diversion_reason);
+- NEXT_COMPONENT(comp, i);
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
+- diversion_reason = redirectingreason_for_q931(pri, diversion_reason);
+-
+- if(pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter);
+- pri_message(NULL, "Length of message is %d\n", len);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_DivertingLegInformation3;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- for(; i < len; NEXT_COMPONENT(comp, i)) {
+- GET_COMPONENT(comp, i, vdata, len);
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0):
+- call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received reason for original redirection %d\n", call->origredirectingreason);
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1):
+- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr);
+- /* TODO: Fix indefinite length form hacks */
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- if (res < 0)
+- return -1;
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, " Received divertingNr '%s'\n", divertingnr.partyaddress);
+- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi);
+- }
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2):
+- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, " Received originalcallednr '%s'\n", originalcallednr.partyaddress);
+- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi);
+- }
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3):
+- res = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname));
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received RedirectingName '%s'\n", redirectingname);
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4):
+- res = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname));
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received Originally Called Name '%s'\n", origcalledname);
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5):
+- pri_message(pri, "!! Ignoring DivertingLegInformation2 component 0x%X\n", comp->type);
+- break;
+- default:
+- if (comp->type == 0 && comp->len == 0) {
+- break; /* Found termination characters */
+- }
+- pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type);
+- return -1;
+- }
+- }
++ /* redirecting.to.number.presentation also indicates if name presentation is allowed */
++ if ((call->redirecting.to.number.presentation & PRI_PRES_RESTRICTION) == PRI_PRES_ALLOWED) {
++ msg.args.qsig.DivertingLegInformation3.presentation_allowed_indicator = 1; /* TRUE */
+
+- if (divertingnr.pres >= 0) {
+- call->redirectingplan = divertingnr.npi;
+- call->redirectingpres = divertingnr.pres;
+- call->redirectingreason = diversion_reason;
+- libpri_copy_string(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum));
+- pri_message(pri, " Received redirectingnum '%s' (%d)\n", call->redirectingnum, (int)call->redirectingnum[0]);
++ /* redirectionName is the redirecting.to.name */
++ if (call->redirecting.to.name.valid) {
++ msg.args.qsig.DivertingLegInformation3.redirection_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.DivertingLegInformation3.redirection_name,
++ &call->redirecting.to.name);
+ }
+- if (originalcallednr.pres >= 0) {
+- call->origcalledplan = originalcallednr.npi;
+- call->origcalledpres = originalcallednr.pres;
+- libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum));
+- pri_message(pri, " Received origcallednum '%s' (%d)\n", call->origcallednum, (int)call->origcallednum[0]);
+- }
+- libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname));
+- libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname));
+- return 0;
+ }
+- while (0);
+
+- return -1;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+-
+-static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *call)
++
++/*!
++ * \internal
++ * \brief Encode the ETSI DivertingLegInformation3 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode diversion leg 3.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_diverting_leg_information3(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call)
+ {
+- int i = 0, j, compsp = 0;
+- struct rose_component *comp, *compstk[10];
+- unsigned char buffer[256];
+- int len = 253;
+-
+-#if 0 /* This is not required by specifications */
+- if (!strlen(call->callername)) {
+- return -1;
++ struct rose_msg_invoke msg;
++
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
+ }
+-#endif
+
+- buffer[i] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- i++;
+- /* Interpretation component */
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0x00 /* Discard unrecognized invokes */);
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+-
+- ASN1_PUSH(compstk, compsp, comp);
+- /* Invoke component contents */
+- /* Invoke ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
+- /* Operation Tag */
+-
+- /* ROSE operationId component */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION2);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_DivertingLegInformation3;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- /* ROSE ARGUMENT component */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* ROSE DivertingLegInformation2.diversionCounter component */
+- /* Always is 1 because other isn't available in the current design */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1);
+-
+- /* ROSE DivertingLegInformation2.diversionReason component */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->redirectingreason));
+-
+- /* ROSE DivertingLegInformation2.divertingNr component */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+-
+- ASN1_PUSH(compstk, compsp, comp);
+- /* Redirecting information always not screened */
+-
+- switch(call->redirectingpres) {
+- case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
+- case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
+- if (call->redirectingnum && strlen(call->redirectingnum)) {
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* NPI of redirected number is not supported in the current design */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
+- if (j < 0)
+- return -1;
+-
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- break;
+- }
+- /* fall through */
+- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
+- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
+- break;
+- /* Don't know how to handle this */
+- case PRES_ALLOWED_NETWORK_NUMBER:
+- case PRES_PROHIB_NETWORK_NUMBER:
+- case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
+- case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
+- break;
+- default:
+- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
+- case PRES_NUMBER_NOT_AVAILABLE:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i);
+- break;
++ if ((call->redirecting.to.number.presentation & PRI_PRES_RESTRICTION) == PRI_PRES_ALLOWED) {
++ msg.args.etsi.DivertingLegInformation3.presentation_allowed_indicator = 1; /* TRUE */
+ }
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+
+- /* ROSE DivertingLegInformation2.originalCalledNr component */
+- /* This information isn't supported by current design - duplicate divertingNr */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* Redirecting information always not screened */
+- switch(call->redirectingpres) {
+- case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
+- case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
+- if (call->redirectingnum && strlen(call->redirectingnum)) {
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
+-
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
+- if (j < 0)
+- return -1;
+-
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- break;
+- }
+- /* fall through */
+- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
+- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
+- break;
+- /* Don't know how to handle this */
+- case PRES_ALLOWED_NETWORK_NUMBER:
+- case PRES_PROHIB_NETWORK_NUMBER:
+- case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
+- case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
+- break;
+- default:
+- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
+- case PRES_NUMBER_NOT_AVAILABLE:
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i);
+- break;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode and queue the DivertingLegInformation3 invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode diversion leg 3.
++ * \param messagetype Q.931 message type to add facility ie to.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rose_diverting_leg_information3_encode(struct pri *ctrl, q931_call *call,
++ int messagetype)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end = enc_etsi_diverting_leg_information3(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ case PRI_SWITCH_QSIG:
++ end = enc_qsig_diverting_leg_information3(ctrl, buffer, buffer + sizeof(buffer),
++ call);
++ break;
++ default:
++ return -1;
+ }
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- /* Fix length of stacked components */
+- while(compsp > 0) {
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ if (!end) {
++ return -1;
+ }
+-
+- if (pri_call_apdu_queue(call, Q931_SETUP, buffer, i, NULL, NULL))
+- return -1;
+-
+- return 0;
++
++ return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
+ }
+
+-/* Send the rltThirdParty: Invoke */
+-int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
++/*!
++ * \internal
++ * \brief Encode the rltThirdParty invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param callwithid Call-ID information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_dms100_rlt_initiate_transfer(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const q931_call *callwithid)
+ {
+- int i = 0;
++ struct rose_msg_invoke msg;
++
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
++
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_DMS100_RLT_ThirdParty;
++ msg.invoke_id = ROSE_DMS100_RLT_THIRD_PARTY;
++ msg.args.dms100.RLT_ThirdParty.call_id = callwithid->rlt_call_id & 0xFFFFFF;
++ msg.args.dms100.RLT_ThirdParty.reason = 0; /* unused, set to 129 */
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \brief Send the rltThirdParty: Invoke.
++ *
++ * \note For PRI_SWITCH_DMS100 only.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param c1 Q.931 call leg 1
++ * \param c2 Q.931 call leg 2
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rlt_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
++{
+ unsigned char buffer[256];
+- struct rose_component *comp = NULL, *compstk[10];
+- const unsigned char rlt_3rd_pty = RLT_THIRD_PARTY;
+- q931_call *callwithid = NULL, *apdubearer = NULL;
+- int compsp = 0;
++ unsigned char *end;
++ q931_call *apdubearer;
++ q931_call *callwithid;
+
+ if (c2->transferable) {
+ apdubearer = c1;
+@@ -906,279 +1374,415 @@
+ } else if (c1->transferable) {
+ apdubearer = c2;
+ callwithid = c1;
+- } else
++ } else {
+ return -1;
++ }
+
+- buffer[i++] = (Q932_PROTOCOL_ROSE);
+- buffer[i++] = (0x80 | RLT_SERVICE_ID); /* Service Identifier octet */
++ end =
++ enc_dms100_rlt_initiate_transfer(ctrl, buffer, buffer + sizeof(buffer),
++ callwithid);
++ if (!end) {
++ return -1;
++ }
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- /* Invoke ID is set to the operation ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_3rd_pty);
+-
+- /* Operation Tag */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_3rd_pty);
+-
+- /* Additional RLT invoke info - Octet 12 */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- ASN1_ADD_WORDCOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, callwithid->rlt_call_id & 0xFFFFFF); /* Length is 3 octets */
+- /* Reason for redirect - unused, set to 129 */
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, i, NULL, NULL))
++ if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, end - buffer, NULL)) {
+ return -1;
++ }
+
+ if (q931_facility(apdubearer->pri, apdubearer)) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", apdubearer->cr);
++ pri_message(ctrl, "Could not schedule facility message for call %d\n",
++ apdubearer->cr);
+ return -1;
+ }
+ return 0;
+ }
+
+-static int add_dms100_transfer_ability_apdu(struct pri *pri, q931_call *c)
++/*!
++ * \internal
++ * \brief Encode the rltOperationInd invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_dms100_rlt_transfer_ability(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end)
+ {
+- int i = 0;
+- unsigned char buffer[256];
+- struct rose_component *comp = NULL, *compstk[10];
+- const unsigned char rlt_op_ind = RLT_OPERATION_IND;
+- int compsp = 0;
++ struct rose_msg_invoke msg;
+
+- buffer[i++] = (Q932_PROTOCOL_ROSE); /* Note to self: DON'T set the EXT bit */
+- buffer[i++] = (0x80 | RLT_SERVICE_ID); /* Service Identifier octet */
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_DMS100_RLT_OperationInd;
++ msg.invoke_id = ROSE_DMS100_RLT_OPERATION_IND;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- /* Invoke ID is set to the operation ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_op_ind);
+-
+- /* Operation Tag - basically the same as the invoke ID tag */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_op_ind);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL))
+- return -1;
+- else
+- return 0;
++ return pos;
+ }
+
+-/* Sending callername information functions */
+-static int add_callername_facility_ies(struct pri *pri, q931_call *c, int cpe)
++/*!
++ * \internal
++ * \brief Send the rltOperationInd: Invoke.
++ *
++ * \note For PRI_SWITCH_DMS100 only.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Q.931 call leg
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int add_dms100_transfer_ability_apdu(struct pri *ctrl, q931_call *call)
+ {
+- int res = 0;
+- int i = 0;
+ unsigned char buffer[256];
+- unsigned char namelen = 0;
+- struct rose_component *comp = NULL, *compstk[10];
+- int compsp = 0;
+- int mymessage = 0;
+- static unsigned char op_tag[] = {
+- 0x2a, /* informationFollowing 42 */
+- 0x86,
+- 0x48,
+- 0xce,
+- 0x15,
+- 0x00,
+- 0x04
+- };
+-
+- if (!strlen(c->callername)) {
++ unsigned char *end;
++
++ end = enc_dms100_rlt_transfer_ability(ctrl, buffer, buffer + sizeof(buffer));
++ if (!end) {
+ return -1;
+ }
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- /* Interpretation component */
++ return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
++}
+
+- if (pri->switchtype == PRI_SWITCH_QSIG) {
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++/*!
++ * \internal
++ * \brief Encode the NI2 InformationFollowing invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_ni2_information_following(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
++
++ memset(&header, 0, sizeof(header));
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
+ }
+
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_NI2_InformationFollowing;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.ni2.InformationFollowing.value = 0;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* Invoke ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ return pos;
++}
+
+- /* Operation Tag */
+- res = asn1_string_encode(ASN1_OBJECTIDENTIFIER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
+- return -1;
+- i += res;
++/*!
++ * \internal
++ * \brief Encode the Q.SIG CallingName invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param name Name data which to encode name.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_calling_name(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct q931_party_name *name)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- if (!cpe) {
+- if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL))
+- return -1;
++ memset(&header, 0, sizeof(header));
++ if (ctrl->switchtype == PRI_SWITCH_QSIG) {
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
+ }
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_CallingName;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- /* Now the APDU that contains the information that needs sent.
+- * We can reuse the buffer since the queue function doesn't
+- * need it. */
++ /* CallingName */
++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.CallingName.name, name);
+
+- i = 0;
+- namelen = strlen(c->callername);
+- if (namelen > 50) {
+- namelen = 50; /* truncate the name */
+- }
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- /* Interpretation component */
++ return pos;
++}
+
+- if (pri->switchtype == PRI_SWITCH_QSIG) {
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++/*!
++ * \internal
++ * \brief Send caller name information.
++ *
++ * \note For PRI_SWITCH_NI2 and PRI_SWITCH_QSIG.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode name.
++ * \param cpe TRUE if we are the CPE side.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int add_callername_facility_ies(struct pri *ctrl, q931_call *call, int cpe)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++ int mymessage;
++
++ if (!call->local_id.name.valid) {
++ return 0;
+ }
+
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
++ if (ctrl->switchtype == PRI_SWITCH_NI2 && !cpe) {
++ end = enc_ni2_information_following(ctrl, buffer, buffer + sizeof(buffer));
++ if (!end) {
++ return -1;
++ }
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ if (pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL)) {
++ return -1;
++ }
+
+- /* Invoke ID */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ /*
++ * We can reuse the buffer since the queue function doesn't
++ * need it.
++ */
++ }
+
+- /* Operation ID: Calling name */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, SS_CNID_CALLINGNAME);
+-
+- res = asn1_string_encode((ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, 50, c->callername, namelen);
+- if (res < 0)
++ /* CallingName is the local_id.name */
++ end = enc_qsig_calling_name(ctrl, buffer, buffer + sizeof(buffer),
++ &call->local_id.name);
++ if (!end) {
+ return -1;
+- i += res;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ }
+
+- if (cpe)
++ if (cpe) {
+ mymessage = Q931_SETUP;
+- else
++ } else {
+ mymessage = Q931_FACILITY;
++ }
+
+- if (pri_call_apdu_queue(c, mymessage, buffer, i, NULL, NULL))
+- return -1;
+-
+- return 0;
++ return pri_call_apdu_queue(call, mymessage, buffer, end - buffer, NULL);
+ }
+ /* End Callername */
+
+ /* MWI related encode and decode functions */
+-static void mwi_activate_encode_cb(void *data)
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG MWIActivate invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param req Served user setup request information.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_mwi_activate_message(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, struct pri_sr *req)
+ {
+- return;
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
++
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
++
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_MWIActivate;
++ msg.invoke_id = get_invokeid(ctrl);
++
++ /* The called.number is the served user */
++ q931_copy_number_to_rose(ctrl, &msg.args.qsig.MWIActivate.served_user_number,
++ &req->called.number);
++ /*
++ * For now, we will just force the numbering plan to unknown to preserve
++ * the original behaviour.
++ */
++ msg.args.qsig.MWIActivate.served_user_number.plan = 0; /* unknown */
++
++ msg.args.qsig.MWIActivate.basic_service = 1; /* speech */
++
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+
+-int mwi_message_send(struct pri* pri, q931_call *call, struct pri_sr *req, int activate)
++/*!
++ * \internal
++ * \brief Encode the Q.SIG MWIDeactivate invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param req Served user setup request information.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_mwi_deactivate_message(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, struct pri_sr *req)
+ {
+- int i = 0;
+- unsigned char buffer[255] = "";
+- int destlen = strlen(req->called);
+- struct rose_component *comp = NULL, *compstk[10];
+- int compsp = 0;
+- int res;
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- if (destlen <= 0) {
+- return -1;
+- } else if (destlen > 20)
+- destlen = 20; /* Destination number cannot be greater then 20 digits */
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- /* Interpretation component */
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_MWIDeactivate;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ /* The called.number is the served user */
++ q931_copy_number_to_rose(ctrl, &msg.args.qsig.MWIDeactivate.served_user_number,
++ &req->called.number);
++ /*
++ * For now, we will just force the numbering plan to unknown to preserve
++ * the original behaviour.
++ */
++ msg.args.qsig.MWIDeactivate.served_user_number.plan = 0; /* unknown */
+
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0);
++ msg.args.qsig.MWIDeactivate.basic_service = 1; /* speech */
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ return pos;
++}
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, (activate) ? SS_MWI_ACTIVATE : SS_MWI_DEACTIVATE);
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* PartyNumber */
+- res = asn1_string_encode((ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, destlen, req->called, destlen);
+-
+- if (res < 0)
++/*!
++ * \brief Encode and queue the Q.SIG MWIActivate/MWIDeactivate invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg to queue message.
++ * \param req Served user setup request information.
++ * \param activate Nonzero to do the activate message.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int mwi_message_send(struct pri *ctrl, q931_call *call, struct pri_sr *req, int activate)
++{
++ unsigned char buffer[255];
++ unsigned char *end;
++
++ if (!req->called.number.valid || !req->called.number.str[0]) {
+ return -1;
+- i += res;
++ }
+
+- /* Enumeration: basicService */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1 /* contents: Voice */);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ if (activate) {
++ end = enc_qsig_mwi_activate_message(ctrl, buffer, buffer + sizeof(buffer), req);
++ } else {
++ end =
++ enc_qsig_mwi_deactivate_message(ctrl, buffer, buffer + sizeof(buffer), req);
++ }
++ if (!end) {
++ return -1;
++ }
+
+- return pri_call_apdu_queue(call, Q931_SETUP, buffer, i, mwi_activate_encode_cb, NULL);
++ return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL);
+ }
+ /* End MWI */
+
+ /* EECT functions */
+-int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
++/*!
++ * \internal
++ * \brief Encode the NI2 InitiateTransfer invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode transfer information.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_ni2_initiate_transfer(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call)
+ {
+- int i = 0;
+- int res = 0;
+- unsigned char buffer[255] = "";
+- short call_reference = c2->cr ^ 0x8000; /* Let's do the trickery to make sure the flag is correct */
+- struct rose_component *comp = NULL, *compstk[10];
+- int compsp = 0;
+- static unsigned char op_tag[] = {
+- 0x2A,
+- 0x86,
+- 0x48,
+- 0xCE,
+- 0x15,
+- 0x00,
+- 0x08,
+- };
++ struct rose_msg_invoke msg;
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_NI2_InitiateTransfer;
++ msg.invoke_id = get_invokeid(ctrl);
++ /* Let's do the trickery to make sure the flag is correct */
++ msg.args.ni2.InitiateTransfer.call_reference = call->cr ^ 0x8000;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ return pos;
++}
+
+- res = asn1_string_encode(ASN1_OBJECTIDENTIFIER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
++/*!
++ * \brief Start a 2BCT
++ *
++ * \note Called for PRI_SWITCH_NI2, PRI_SWITCH_LUCENT5E, and PRI_SWITCH_ATT4ESS
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param c1 Q.931 call leg 1
++ * \param c2 Q.931 call leg 2
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int eect_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
++{
++ unsigned char buffer[255];
++ unsigned char *end;
++
++ end = enc_ni2_initiate_transfer(ctrl, buffer, buffer + sizeof(buffer), c2);
++ if (!end) {
+ return -1;
+- i += res;
++ }
+
+- ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer, i, call_reference);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, i, NULL, NULL);
+- if (res) {
+- pri_message(pri, "Could not queue APDU in facility message\n");
++ if (pri_call_apdu_queue(c1, Q931_FACILITY, buffer, end - buffer, NULL)) {
++ pri_message(ctrl, "Could not queue APDU in facility message\n");
+ return -1;
+ }
+
+ /* Remember that if we queue a facility IE for a facility message we
+ * have to explicitly send the facility message ourselves */
+
+- res = q931_facility(c1->pri, c1);
+- if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr);
++ if (q931_facility(c1->pri, c1)) {
++ pri_message(ctrl, "Could not schedule facility message for call %d\n", c1->cr);
+ return -1;
+ }
+
+@@ -1187,1494 +1791,2316 @@
+ /* End EECT */
+
+ /* QSIG CF CallRerouting */
+-int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason)
++/*!
++ * \internal
++ * \brief Encode the Q.SIG CallRerouting invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Q.931 call leg.
++ * \param calling Call rerouting/deflecting updated caller data.
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_call_rerouting(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, const struct q931_party_id *calling,
++ const struct q931_party_redirecting *deflection, int subscription_option)
+ {
+-/*CallRerouting ::= OPERATION
+- -- Sent from the Served User PINX to the Rerouting PINX
+- ARGUMENT SEQUENCE
+- { reroutingReason DiversionReason,
+- originalReroutingReason [0] IMPLICIT DiversionReason OPTIONAL,
+- calledAddress Address,
+- diversionCounter INTEGER (1..15),
+- pSS1InfoElement PSS1InformationElement,
+- -- The basic call information elements Bearer capability, High layer compatibility, Low
+- -- layer compatibity, Progress indicator and Party category can be embedded in the
+- -- pSS1InfoElement in accordance with 6.5.3.1.5
+- lastReroutingNr [1] PresentedNumberUnscreened,
+- subscriptionOption [2] IMPLICIT SubscriptionOption,
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
++ unsigned char *q931ie_pos;
+
+- callingPartySubaddress [3] PartySubaddress OPTIONAL,
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 2; /* rejectAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
+- callingNumber [4] PresentedNumberScreened,
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_CallRerouting;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- callingName [5] Name OPTIONAL,
+- originalCalledNr [6] PresentedNumberUnscreened OPTIONAL,
+- redirectingName [7] Name OPTIONAL,
+- originalCalledName [8] Name OPTIONAL,
+- extension CHOICE {
+- [9] IMPLICIT Extension ,
+- [10] IMPLICIT SEQUENCE OF Extension } OPTIONAL }
+-*/
++ msg.args.qsig.CallRerouting.rerouting_reason =
++ redirectingreason_from_q931(ctrl, deflection->reason);
+
+- int i = 0, j;
+- int res = 0;
+- unsigned char buffer[255] = "";
+- int len = 253;
+- struct rose_component *comp = NULL, *compstk[10];
+- int compsp = 0;
+- static unsigned char op_tag[] = {
+- 0x13,
+- };
++ /* calledAddress is the passed in deflection->to address */
++ q931_copy_address_to_rose(ctrl, &msg.args.qsig.CallRerouting.called, &deflection->to);
+
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+- /* Interpretation component */
++ msg.args.qsig.CallRerouting.diversion_counter = deflection->count;
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ /* pSS1InfoElement */
++ q931ie_pos = msg.args.qsig.CallRerouting.q931ie_contents;
++ *q931ie_pos++ = 0x04; /* Bearer Capability IE */
++ *q931ie_pos++ = 0x03; /* len */
++ *q931ie_pos++ = 0x80 | call->transcapability; /* Rxed transfer capability. */
++ *q931ie_pos++ = 0x90; /* circuit mode, 64kbit/s */
++ *q931ie_pos++ = 0xa3; /* level1 protocol, a-law */
++ *q931ie_pos++ = 0x95; /* locking shift to codeset 5 (national use) */
++ *q931ie_pos++ = 0x32; /* Unknown ie */
++ *q931ie_pos++ = 0x01; /* Unknown ie len */
++ *q931ie_pos++ = 0x81; /* Unknown ie body */
++ msg.args.qsig.CallRerouting.q931ie.length = q931ie_pos
++ - msg.args.qsig.CallRerouting.q931ie_contents;
+
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */
++ /* lastReroutingNr is the passed in deflection->from.number */
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.qsig.CallRerouting.last_rerouting, &deflection->from.number);
+
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ msg.args.qsig.CallRerouting.subscription_option = subscription_option;
+
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
++ /* callingNumber is the passed in calling->number */
++ q931_copy_presented_number_screened_to_rose(ctrl,
++ &msg.args.qsig.CallRerouting.calling, &calling->number);
+
+- res = asn1_string_encode(ASN1_INTEGER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
+- return -1;
+- i += res;
++ /* callingPartySubaddress is the passed in calling->subaddress if valid */
++ q931_copy_subaddress_to_rose(ctrl, &msg.args.qsig.CallRerouting.calling_subaddress,
++ &calling->subaddress);
+
+- /* call rerouting argument */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ /* callingName is the passed in calling->name if valid */
++ if (calling->name.valid) {
++ msg.args.qsig.CallRerouting.calling_name_present = 1;
++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.CallRerouting.calling_name,
++ &calling->name);
++ }
+
+- /* reroutingReason DiversionReason */
++ if (1 < deflection->count) {
++ /* originalCalledNr is the deflection->orig_called.number */
++ msg.args.qsig.CallRerouting.original_called_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.qsig.CallRerouting.original_called,
++ &deflection->orig_called.number);
+
+- if (reason) {
+- if (!strcasecmp(reason, "cfu"))
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1); /* cfu */
+- else if (!strcasecmp(reason, "cfb"))
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 2); /* cfb */
+- else if (!strcasecmp(reason, "cfnr"))
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 3); /* cfnr */
+- } else {
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); /* unknown */
++ msg.args.qsig.CallRerouting.original_rerouting_reason_present = 1;
++ if (deflection->orig_called.number.valid) {
++ msg.args.qsig.CallRerouting.original_rerouting_reason =
++ redirectingreason_from_q931(ctrl, deflection->orig_reason);
++ } else {
++ msg.args.qsig.CallRerouting.original_rerouting_reason =
++ QSIG_DIVERT_REASON_UNKNOWN;
++ }
++
++ /* originalCalledName is the deflection->orig_called.name */
++ if (deflection->orig_called.name.valid) {
++ msg.args.qsig.CallRerouting.original_called_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.CallRerouting.original_called_name,
++ &deflection->orig_called.name);
++ }
+ }
+
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- /* calledAddress Address */
+- /* explicit sequence tag for Address */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* implicit choice public party number tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* type of public party number = unknown */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
+- /* NumberDigits of public party number */
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, (char*)dest, strlen(dest));
+- if (j < 0)
+- return -1;
++ return pos;
++}
+
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++/*!
++ * \internal
++ * \brief Encode the ETSI CallRerouting invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Q.931 call leg.
++ * \param calling Call rerouting/deflecting updated caller data.
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_call_rerouting(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, const struct q931_party_id *calling,
++ const struct q931_party_redirecting *deflection, int subscription_option)
++{
++ struct rose_msg_invoke msg;
++ unsigned char *q931ie_pos;
+
+- /* diversionCounter INTEGER (1..15) */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- /* pSS1InfoElement */
+- ASN1_ADD_SIMPLE(comp, (ASN1_APPLICATION | ASN1_TAG_0 ), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- buffer[i++] = (0x04); /* Bearer Capability IE */
+- buffer[i++] = (0x03); /* len */
+- buffer[i++] = (0x80); /* ETSI Standard, Speech */
+- buffer[i++] = (0x90); /* circuit mode, 64kbit/s */
+- buffer[i++] = (0xa3); /* level1 protocol, a-law */
+- buffer[i++] = (0x95); /* locking shift to codeset 5 (national use) */
+- buffer[i++] = (0x32); /* Unknown ie */
+- buffer[i++] = (0x01); /* Unknown ie len */
+- buffer[i++] = (0x81); /* Unknown ie body */
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_CallRerouting;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- /* lastReroutingNr [1]*/
+- /* implicit optional lastReroutingNr tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ msg.args.etsi.CallRerouting.rerouting_reason =
++ redirectingreason_from_q931(ctrl, deflection->reason);
+
+- /* implicit choice presented number unscreened tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ /* calledAddress is the passed in deflection->to address */
++ q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallRerouting.called_address,
++ &deflection->to);
+
+- /* implicit choice public party number tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* type of public party number = unknown */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0);
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, original?(char*)original:c->callednum, original?strlen(original):strlen(c->callednum));
+- if (j < 0)
+- return -1;
++ msg.args.etsi.CallRerouting.rerouting_counter = deflection->count;
+
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ /* q931InfoElement */
++ q931ie_pos = msg.args.etsi.CallRerouting.q931ie_contents;
++ *q931ie_pos++ = 0x04; /* Bearer Capability IE */
++ *q931ie_pos++ = 0x03; /* len */
++ *q931ie_pos++ = 0x80 | call->transcapability; /* Rxed transfer capability. */
++ *q931ie_pos++ = 0x90; /* circuit mode, 64kbit/s */
++ *q931ie_pos++ = 0xa3; /* level1 protocol, a-law */
++ msg.args.etsi.CallRerouting.q931ie.length = q931ie_pos
++ - msg.args.etsi.CallRerouting.q931ie_contents;
+
+- /* subscriptionOption [2]*/
+- /* implicit optional lastReroutingNr tag */
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* noNotification */
++ /* lastReroutingNr is the passed in deflection->from.number */
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.CallRerouting.last_rerouting, &deflection->from.number);
+
+- /* callingNumber [4]*/
+- /* implicit optional callingNumber tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ msg.args.etsi.CallRerouting.subscription_option = subscription_option;
+
+- /* implicit choice presented number screened tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ /* callingPartySubaddress is the passed in calling->subaddress if valid */
++ q931_copy_subaddress_to_rose(ctrl, &msg.args.etsi.CallRerouting.calling_subaddress,
++ &calling->subaddress);
+
+- /* implicit choice presentationAllowedAddress tag */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- /* type of public party number = subscriber number */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 4);
+- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, c->callernum, strlen(c->callernum));
+- if (j < 0)
+- return -1;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- i += j;
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ return pos;
++}
+
+- /* Screeening Indicator network provided */
+- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 3);
++/*!
++ * \internal
++ * \brief Encode the ETSI CallDeflection invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Q.931 call leg.
++ * \param deflection Call deflection address.
++ *
++ * \note
++ * deflection is the new called number and must always be present.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_call_deflection(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, const struct q931_party_id *deflection)
++{
++ struct rose_msg_invoke msg;
+
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- /**/
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_CallDeflection;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
++ /* deflectionAddress is the passed in deflection->to address */
++ q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallDeflection.deflection,
++ deflection);
+
+- res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL);
+- if (res) {
+- pri_message(pri, "Could not queue ADPU in facility message\n");
++ msg.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1;
++ switch (deflection->number.presentation & PRI_PRES_RESTRICTION) {
++ case PRI_PRES_ALLOWED:
++ msg.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user = 1;
++ break;
++ default:
++ case PRI_PRES_UNAVAILABLE:
++ case PRI_PRES_RESTRICTED:
++ break;
++ }
++
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode and queue the CallRerouting/CallDeflection message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ * \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.)
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_reroute_request_encode(struct pri *ctrl, q931_call *call,
++ const struct q931_party_id *caller, const struct q931_party_redirecting *deflection,
++ int subscription_option)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++
++ if (!caller) {
++ /*
++ * We are deflecting an incoming call back to the network.
++ * Therefore, the Caller-ID is the remote party.
++ */
++ caller = &call->remote_id;
++ }
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (q931_is_ptmp(ctrl)) {
++ end =
++ enc_etsi_call_deflection(ctrl, buffer, buffer + sizeof(buffer), call,
++ &deflection->to);
++ } else {
++ end =
++ enc_etsi_call_rerouting(ctrl, buffer, buffer + sizeof(buffer), call,
++ caller, deflection, subscription_option);
++ }
++ break;
++ case PRI_SWITCH_QSIG:
++ end =
++ enc_qsig_call_rerouting(ctrl, buffer, buffer + sizeof(buffer), call, caller,
++ deflection, subscription_option);
++ break;
++ default:
+ return -1;
+ }
++ if (!end) {
++ return -1;
++ }
+
+- /* Remember that if we queue a facility IE for a facility message we
+- * have to explicitly send the facility message ourselves */
++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
++}
+
+- res = q931_facility(c->pri, c);
+- if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c->cr);
++/*!
++ * \brief Send the CallRerouting/CallDeflection message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ * \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.)
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int send_reroute_request(struct pri *ctrl, q931_call *call,
++ const struct q931_party_id *caller, const struct q931_party_redirecting *deflection,
++ int subscription_option)
++{
++ if (!deflection->to.number.str[0]) {
++ /* Must have a deflect to number. That is the point of deflection. */
+ return -1;
+ }
++ if (rose_reroute_request_encode(ctrl, call, caller, deflection, subscription_option)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for CallRerouting/CallDeflection message.\n");
++ return -1;
++ }
+
+ return 0;
+ }
++
++/*!
++ * \brief Send the Q.SIG CallRerouting invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Q.931 call leg.
++ * \param dest Destination number.
++ * \param original Original called number.
++ * \param reason Rerouting reason: cfu, cfb, cfnr
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int qsig_cf_callrerouting(struct pri *ctrl, q931_call *call, const char *dest,
++ const char *original, const char *reason)
++{
++ struct q931_party_redirecting reroute;
++
++ q931_party_redirecting_init(&reroute);
++
++ /* Rerouting to the dest number. */
++ reroute.to.number.valid = 1;
++ reroute.to.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
++ reroute.to.number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ libpri_copy_string(reroute.to.number.str, dest, sizeof(reroute.to.number.str));
++
++ /* Rerouting from the original number. */
++ if (original) {
++ reroute.from.number.valid = 1;
++ reroute.from.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
++ libpri_copy_string(reroute.from.number.str, original, sizeof(reroute.from.number.str));
++ } else {
++ q931_party_address_to_id(&reroute.from, &call->called);
++ }
++ reroute.from.number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++
++ /* Decode the rerouting reason. */
++ reroute.reason = PRI_REDIR_UNKNOWN;
++ if (!reason) {
++ /* No reason for rerouting given. */
++ } else if (!strcasecmp(reason, "cfu")) {
++ reroute.reason = PRI_REDIR_UNCONDITIONAL;
++ } else if (!strcasecmp(reason, "cfb")) {
++ reroute.reason = PRI_REDIR_FORWARD_ON_BUSY;
++ } else if (!strcasecmp(reason, "cfnr")) {
++ reroute.reason = PRI_REDIR_FORWARD_ON_NO_REPLY;
++ }
++
++ reroute.count = (call->redirecting.count < PRI_MAX_REDIRECTS)
++ ? call->redirecting.count + 1 : PRI_MAX_REDIRECTS;
++
++ if (!call->redirecting.orig_called.number.valid) {
++ /*
++ * Since we do not already have an originally called party, we
++ * must either be the first redirected to party or this call
++ * has not been redirected before.
++ *
++ * Preserve who redirected to us as the originally called party.
++ */
++ reroute.orig_called = call->redirecting.from;
++ reroute.orig_reason = call->redirecting.reason;
++ } else {
++ reroute.orig_called = call->redirecting.orig_called;
++ reroute.orig_reason = call->redirecting.orig_reason;
++ }
++
++ return send_reroute_request(ctrl, call, NULL, &reroute, 0 /* noNotification */);
++}
+ /* End QSIG CC-CallRerouting */
+
+-static int anfpr_pathreplacement_respond(struct pri *pri, q931_call *call, q931_ie *ie)
++/*
++ * From Mantis issue 7778 description: (ETS 300 258, ISO 13863)
++ * After both legs of the call are setup and Asterisk has a successful "tromboned" or bridged call ...
++ * Asterisk sees both 'B' channels (from trombone) are on same PRI/technology and initiates "Path Replacement" events
++ * a. Asterisk sends "Transfer Complete" messages to both call legs
++ * b. QSIG Switch sends "PathReplacement" message on one of the legs (random 1-10sec timer expires - 1st leg to send is it!)
++ * c. Asterisk rebroadcasts "PathReplacement" message to other call leg
++ * d. QSIG Switch sends "Disconnect" message on one of the legs (same random timer sequence as above)
++ * e. Asterisk rebroadcasts "Disconnect" message to other call leg
++ * f. QSIG Switch disconnects Asterisk call legs - callers are now within QSIG switch
++ *
++ * Just need to resend the message to the other tromboned leg of the call.
++ */
++static int anfpr_pathreplacement_respond(struct pri *ctrl, q931_call *call, q931_ie *ie)
+ {
+ int res;
+-
+- res = pri_call_apdu_queue_cleanup(call->bridged_call);
+- if (res) {
+- pri_message(pri, "Could not Clear queue ADPU\n");
+- return -1;
+- }
+-
++
++ pri_call_apdu_queue_cleanup(call->bridged_call);
++
+ /* Send message */
+- res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len, NULL, NULL);
++ res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len, NULL);
+ if (res) {
+- pri_message(pri, "Could not queue ADPU in facility message\n");
+- return -1;
++ pri_message(ctrl, "Could not queue ADPU in facility message\n");
++ return -1;
+ }
+-
++
+ /* Remember that if we queue a facility IE for a facility message we
+ * have to explicitly send the facility message ourselves */
+-
++
+ res = q931_facility(call->bridged_call->pri, call->bridged_call);
+ if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", call->bridged_call->cr);
++ pri_message(ctrl, "Could not schedule facility message for call %d\n",
++ call->bridged_call->cr);
+ return -1;
+ }
+
+ return 0;
+ }
++
+ /* AFN-PR */
+-int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2)
++/*!
++ * \brief Start a Q.SIG path replacement.
++ *
++ * \note Called for PRI_SWITCH_QSIG
++ *
++ * \note Did all the tests to see if we're on the same PRI and
++ * are on a compatible switchtype.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param c1 Q.931 call leg 1
++ * \param c2 Q.931 call leg 2
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int anfpr_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2)
+ {
+- /* Did all the tests to see if we're on the same PRI and
+- * are on a compatible switchtype */
+- /* TODO */
+- int i = 0;
+- int res = 0;
+- unsigned char buffer[255] = "";
+- unsigned short call_reference = c2->cr;
+- struct rose_component *comp = NULL, *compstk[10];
+- unsigned char buffer2[255] = "";
+- int compsp = 0;
+- static unsigned char op_tag[] = {
+- 0x0C,
+- };
+-
+- /* Channel 1 */
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- /* Interpretation component */
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
+-
+- res = asn1_string_encode(ASN1_INTEGER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
++ unsigned char buffer[255];
++ unsigned char *pos;
++ unsigned char *end;
++ int res;
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
++
++ end = buffer + sizeof(buffer);
++
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 2; /* rejectAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, buffer, end, &header);
++ if (!pos) {
+ return -1;
+- i += res;
+-
+- ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- buffer[i++] = (0x0a);/* Enumeration endDesignation */
+- buffer[i++] = (0x01);/* Len */
+- buffer[i++] = (0x00);/* primaryEnd */
+- buffer[i++] = (0x81);/* redirectionNumber = presentationRestricted */
+- buffer[i++] = (0x00);/* Len */
+- buffer[i++] = (0x0a);/* Enumeration callStatus */
+- buffer[i++] = (0x01);/* Len */
+- buffer[i++] = (0x01);/* alerting */
++ }
+
+- /*
+- * Where does this element come from? It is not in Q.SIG ECMA-178.
+- * We send this but we will not accept it.
+- * This seems to be a cut and paste error from eect_initiate_transfer().
+- */
+- ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer, i, call_reference);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_CallTransferComplete;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.qsig.CallTransferComplete.end_designation = 0; /* primaryEnd */
++ msg.args.qsig.CallTransferComplete.redirection.presentation = 1; /* presentationRestricted */
++ msg.args.qsig.CallTransferComplete.call_status = 1; /* alerting */
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++ if (!pos) {
++ return -1;
++ }
+
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, i, NULL, NULL);
++ res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, pos - buffer, NULL);
+ if (res) {
+- pri_message(pri, "Could not queue ADPU in facility message\n");
++ pri_message(ctrl, "Could not queue ADPU in facility message\n");
+ return -1;
+ }
+-
++
+ /* Remember that if we queue a facility IE for a facility message we
+ * have to explicitly send the facility message ourselves */
+-
++
+ res = q931_facility(c1->pri, c1);
+ if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr);
++ pri_message(ctrl, "Could not schedule facility message for call %d\n", c1->cr);
+ return -1;
+ }
+-
+- /* Channel 2 */
+- i = 0;
+- res = 0;
+- compsp = 0;
+-
+- buffer2[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer2, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer2, i, 0);
+- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer2, i, 0);
+- ASN1_FIXUP(compstk, compsp, buffer2, i);
+-
+- /* Interpretation component */
+- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer2, i, 2); /* reject */
+-
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer2, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer2, i, get_invokeid(pri));
+-
+- res = asn1_string_encode(ASN1_INTEGER, &buffer2[i], sizeof(buffer2)-i, sizeof(op_tag), op_tag, sizeof(op_tag));
+- if (res < 0)
++
++ /* Reuse the previous message header */
++ pos = facility_encode_header(ctrl, buffer, end, &header);
++ if (!pos) {
+ return -1;
+- i += res;
+-
+- ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer2, i);
+- ASN1_PUSH(compstk, compsp, comp);
+- buffer2[i++] = (0x0a);/* Enumeration endDesignation */
+- buffer2[i++] = (0x01);/* Len */
+- buffer2[i++] = (0x01);/* secondaryEnd */
+- buffer2[i++] = (0x81);/* redirectionNumber = presentationRestricted */
+- buffer2[i++] = (0x00);/* Len */
+- buffer2[i++] = (0x0a);/* Enumeration callStatus */
+- buffer2[i++] = (0x01);/* Len */
+- buffer2[i++] = (0x01);/* alerting */
++ }
+
+- /*
+- * Where does this element come from? It is not in Q.SIG ECMA-178.
+- * We send this but we will not accept it.
+- * This seems to be a cut and paste error from eect_initiate_transfer().
+- */
+- ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer2, i, call_reference);
++ /* Update the previous message */
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.qsig.CallTransferComplete.end_designation = 1; /* secondaryEnd */
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++ if (!pos) {
++ return -1;
++ }
+
+- ASN1_FIXUP(compstk, compsp, buffer2, i);
+- ASN1_FIXUP(compstk, compsp, buffer2, i);
+-
+-
+- res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer2, i, NULL, NULL);
++ res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer, pos - buffer, NULL);
+ if (res) {
+- pri_message(pri, "Could not queue ADPU in facility message\n");
++ pri_message(ctrl, "Could not queue ADPU in facility message\n");
+ return -1;
+ }
+-
++
+ /* Remember that if we queue a facility IE for a facility message we
+ * have to explicitly send the facility message ourselves */
+-
++
+ res = q931_facility(c2->pri, c2);
+ if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr);
++ pri_message(ctrl, "Could not schedule facility message for call %d\n", c2->cr);
+ return -1;
+ }
+-
++
+ return 0;
+ }
+ /* End AFN-PR */
+
+ /* AOC */
+-static int aoc_aoce_charging_request_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
++/*!
++ * \internal
++ * \brief Encode the ETSI AOCEChargingUnit invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param chargedunits Number of units charged to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_aoce_charging_unit(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, long chargedunits)
+ {
+- int chargingcase = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL;
+- int pos1 = 0;
++ struct rose_msg_invoke msg;
+
+- if (pri->debug & PRI_DEBUG_AOC)
+- dump_apdu (pri, data, len);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
+- do {
+- GET_COMPONENT(comp, pos1, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "!! Invalid AOC Charging Request argument. Expected Enumerated (0x0A) but Received 0x%02X\n");
+- ASN1_GET_INTEGER(comp, chargingcase);
+- if (chargingcase >= 0 && chargingcase <= 2) {
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Channel %d/%d, Call %d - received AOC charging request - charging case: %i\n",
+- call->ds1no, call->channelno, call->cr, chargingcase);
+- } else {
+- pri_message(pri, "!! unkown AOC ChargingCase: 0x%02X", chargingcase);
+- chargingcase = -1;
+- }
+- NEXT_COMPONENT(comp, pos1);
+- } while (pos1 < len);
+- if (pos1 < len) {
+- pri_message(pri, "!! Only reached position %i in %i bytes long AOC-E structure:", pos1, len );
+- dump_apdu (pri, data, len);
+- return -1; /* Aborted before */
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_AOCEChargingUnit;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.etsi.AOCEChargingUnit.type = 1; /* charging_unit */
++ if (chargedunits <= 0) {
++ msg.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1;
++ } else {
++ msg.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1;
++ msg.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].
++ number_of_units = chargedunits;
+ }
+- return 0;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+-
+
+-static int aoc_aoce_charging_unit_decode(struct pri *pri, q931_call *call, unsigned char *data, int len)
++/*!
++ * \internal
++ * \brief Send the ETSI AOCEChargingUnit invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode AOC.
++ * \param chargedunits Number of units charged to encode.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int aoc_aoce_charging_unit_encode(struct pri *ctrl, q931_call *call,
++ long chargedunits)
+ {
+- long chargingunits = 0, chargetype = -1, temp, chargeIdentifier = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp1 = NULL, *comp2 = NULL, *comp3 = NULL;
+- int pos1 = 0, pos2, pos3, sublen2, sublen3;
+- struct addressingdataelements_presentednumberunscreened chargednr;
++ unsigned char buffer[255];
++ unsigned char *end;
+
+- if (pri->debug & PRI_DEBUG_AOC)
+- dump_apdu (pri, data, len);
++ /* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */
+
+- do {
+- GET_COMPONENT(comp1, pos1, vdata, len); /* AOCEChargingUnitInfo */
+- CHECK_COMPONENT(comp1, ASN1_SEQUENCE, "!! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but Received 0x%02X\n");
+- SUB_COMPONENT(comp1, pos1);
+- GET_COMPONENT(comp1, pos1, vdata, len);
+- switch (comp1->type) {
+- case (ASN1_SEQUENCE | ASN1_CONSTRUCTOR): /* specificChargingUnits */
+- sublen2 = comp1->len;
+- pos2 = pos1;
+- comp2 = comp1;
+- SUB_COMPONENT(comp2, pos2);
+- do {
+- GET_COMPONENT(comp2, pos2, vdata, len);
+- switch (comp2->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* RecordedUnitsList (0xA1) */
+- SUB_COMPONENT(comp2, pos2);
+- GET_COMPONENT(comp2, pos2, vdata, len);
+- CHECK_COMPONENT(comp2, ASN1_SEQUENCE, "!! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but received 0x02%X\n"); /* RecordedUnits */
+- sublen3 = pos2 + comp2->len;
+- pos3 = pos2;
+- comp3 = comp2;
+- SUB_COMPONENT(comp3, pos3);
+- do {
+- GET_COMPONENT(comp3, pos3, vdata, len);
+- switch (comp3->type) {
+- case ASN1_INTEGER: /* numberOfUnits */
+- ASN1_GET_INTEGER(comp3, temp);
+- chargingunits += temp;
+- case ASN1_NULL: /* notAvailable */
+- break;
+- default:
+- pri_message(pri, "!! Don't know how to handle 0x%02X in AOC-E RecordedUnits\n", comp3->type);
+- }
+- NEXT_COMPONENT(comp3, pos3);
+- } while (pos3 < sublen3);
+- if (pri->debug & PRI_DEBUG_AOC)
+- pri_message(pri, "Channel %d/%d, Call %d - received AOC-E charging: %i unit%s\n",
+- call->ds1no, call->channelno, call->cr, chargingunits, (chargingunits == 1) ? "" : "s");
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* AOCEBillingID (0xA2) */
+- SUB_COMPONENT(comp2, pos2);
+- GET_COMPONENT(comp2, pos2, vdata, len);
+- ASN1_GET_INTEGER(comp2, chargetype);
+- pri_message(pri, "!! not handled: Channel %d/%d, Call %d - received AOC-E billing ID: %i\n",
+- call->ds1no, call->channelno, call->cr, chargetype);
+- break;
+- default:
+- pri_message(pri, "!! Don't know how to handle 0x%02X in AOC-E RecordedUnitsList\n", comp2->type);
+- }
+- NEXT_COMPONENT(comp2, pos2);
+- } while (pos2 < sublen2);
+- break;
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* freeOfCharge (0x81) */
+- if (pri->debug & PRI_DEBUG_AOC)
+- pri_message(pri, "Channel %d/%d, Call %d - received AOC-E free of charge\n", call->ds1no, call->channelno, call->cr);
+- chargingunits = 0;
+- break;
+- default:
+- pri_message(pri, "!! Invalid AOC-E specificChargingUnits. Expected Sequence (0x30) or Object Identifier (0x81/0x01) but received 0x%02X\n", comp1->type);
+- }
+- NEXT_COMPONENT(comp1, pos1);
+- GET_COMPONENT(comp1, pos1, vdata, len); /* get optional chargingAssociation. will 'break' when reached end of structure */
+- switch (comp1->type) {
+- /* TODO: charged number is untested - please report! */
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* chargedNumber (0xA0) */
+- if(rose_presented_number_unscreened_decode(pri, call, comp1->data, comp1->len, &chargednr) != 0)
+- return -1;
+- pri_message(pri, "!! not handled: Received ChargedNr '%s' \n", chargednr.partyaddress);
+- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", chargednr.ton, chargednr.pres, chargednr.npi);
+- break;
+- case ASN1_INTEGER:
+- ASN1_GET_INTEGER(comp1, chargeIdentifier);
+- break;
+- default:
+- pri_message(pri, "!! Invalid AOC-E chargingAssociation. Expected Object Identifier (0xA0) or Integer (0x02) but received 0x%02X\n", comp1->type);
+- }
+- NEXT_COMPONENT(comp1, pos1);
+- } while (pos1 < len);
++ end =
++ enc_etsi_aoce_charging_unit(ctrl, buffer, buffer + sizeof(buffer), chargedunits);
++ if (!end) {
++ return -1;
++ }
+
+- if (pos1 < len) {
+- pri_message(pri, "!! Only reached position %i in %i bytes long AOC-E structure:", pos1, len );
+- dump_apdu (pri, data, len);
+- return -1; /* oops - aborted before */
++ /* Remember that if we queue a facility IE for a facility message we
++ * have to explicitly send the facility message ourselves */
++ if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL)
++ || q931_facility(call->pri, call)) {
++ pri_message(ctrl, "Could not schedule facility message for call %d\n", call->cr);
++ return -1;
+ }
+- call->aoc_units = chargingunits;
+-
++
+ return 0;
+ }
++/* End AOC */
+
+-static int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long chargedunits)
++/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG CallTransferComplete invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode call transfer.
++ * \param call_status TRUE if call is alerting.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_call_transfer_complete(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, q931_call *call, int call_status)
+ {
+- /* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */
+- int i = 0, res = 0, compsp = 0;
+- unsigned char buffer[255] = "";
+- struct rose_component *comp = NULL, *compstk[10];
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- /* ROSE protocol (0x91)*/
+- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE);
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
+- /* ROSE Component (0xA1,len)*/
+- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_CallTransferComplete;
++ msg.invoke_id = get_invokeid(ctrl);
++ msg.args.qsig.CallTransferComplete.end_designation = 0; /* primaryEnd */
+
+- /* ROSE invokeId component (0x02,len,id)*/
+- ASN1_ADD_WORDCOMP(comp, INVOKE_IDENTIFIER, buffer, i, ++pri->last_invoke);
++ /* redirectionNumber is the local_id.number */
++ q931_copy_presented_number_screened_to_rose(ctrl,
++ &msg.args.qsig.CallTransferComplete.redirection, &call->local_id.number);
+
+- /* ROSE operationId component (0x02,0x01,0x24)*/
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_AOC_AOCE_CHARGING_UNIT);
++ /* redirectionName is the local_id.name */
++ if (call->local_id.name.valid) {
++ msg.args.qsig.CallTransferComplete.redirection_name_present = 1;
++ q931_copy_name_to_rose(ctrl,
++ &msg.args.qsig.CallTransferComplete.redirection_name,
++ &call->local_id.name);
++ }
+
+- /* AOCEChargingUnitInfo (0x30,len) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ if (call_status) {
++ msg.args.qsig.CallTransferComplete.call_status = 1; /* alerting */
++ }
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- if (chargedunits > 0) {
+- /* SpecificChargingUnits (0x30,len) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
++ return pos;
++}
+
+- /* RecordedUnitsList (0xA1,len) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- /* RecordedUnits (0x30,len) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
+- ASN1_PUSH(compstk, compsp, comp);
+-
+- /* NumberOfUnits (0x02,len,charge) */
+- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, chargedunits);
++/*!
++ * \internal
++ * \brief Encode the ETSI EctInform invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode inform message.
++ * \param call_status TRUE if call is alerting.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_ect_inform(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int call_status)
++{
++ struct rose_msg_invoke msg;
+
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- } else {
+- /* freeOfCharge (0x81,0) */
+- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
+ }
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+- ASN1_FIXUP(compstk, compsp, buffer, i);
+-
+- if (pri->debug & PRI_DEBUG_AOC)
+- dump_apdu (pri, buffer, i);
+-
+- /* code below is untested */
+- res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL);
+- if (res) {
+- pri_message(pri, "Could not queue APDU in facility message\n");
+- return -1;
++
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_ETSI_EctInform;
++ msg.invoke_id = get_invokeid(ctrl);
++
++ if (!call_status) {
++ msg.args.etsi.EctInform.status = 1;/* active */
++
++ /*
++ * EctInform(active) contains the redirectionNumber
++ * redirectionNumber is the local_id.number
++ */
++ msg.args.etsi.EctInform.redirection_present = 1;
++ q931_copy_presented_number_unscreened_to_rose(ctrl,
++ &msg.args.etsi.EctInform.redirection, &call->local_id.number);
+ }
+
+- /* Remember that if we queue a facility IE for a facility message we
+- * have to explicitly send the facility message ourselves */
+- res = q931_facility(c->pri, c);
+- if (res) {
+- pri_message(pri, "Could not schedule facility message for call %d\n", c->cr);
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode and queue the CallTransferComplete/EctInform invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode call transfer.
++ * \param call_status TRUE if call is alerting.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_call_transfer_complete_encode(struct pri *ctrl, q931_call *call,
++ int call_status)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end =
++ enc_etsi_ect_inform(ctrl, buffer, buffer + sizeof(buffer), call, call_status);
++ break;
++ case PRI_SWITCH_QSIG:
++ end =
++ enc_qsig_call_transfer_complete(ctrl, buffer, buffer + sizeof(buffer), call,
++ call_status);
++ break;
++ default:
+ return -1;
+ }
++ if (!end) {
++ return -1;
++ }
+
+- return 0;
++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
+ }
+-/* End AOC */
+
+-static int rose_calling_name_decode(struct pri *pri, q931_call *call, struct rose_component *choice, int len)
++/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG CalledName invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param name Name data which to encode name.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_called_name(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct q931_party_name *name)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = choice->data;
+- int characterSet = 1;
+- switch (choice->type) {
+- case ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE:
+- memcpy(call->callername, choice->data, choice->len);
+- call->callername[choice->len] = 0;
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received simple calling name '%s'\n", call->callername);
+- return 0;
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- case ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED:
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if nameData is of type 0x%x\n");
+- memcpy(call->callername, comp->data, comp->len);
+- call->callername[comp->len] = 0;
+- NEXT_COMPONENT(comp, i);
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if CharacterSet is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, characterSet);
+- }
+- while (0);
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_CalledName;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Received extended calling name '%s', characterset %d\n", call->callername, characterSet);
+- return 0;
+- case ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE:
+- case ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED:
+- case ROSE_NAME_PRESENTATION_RESTRICTED_NULL:
+- case ROSE_NAME_NOT_AVAIL:
+- default:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Do not handle argument of type 0x%X\n", choice->type);
+- return -1;
+- }
++ /* CalledName */
++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.CalledName.name, name);
++
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
++
++ return pos;
+ }
+-/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */
+
+-static int rose_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
++/*!
++ * \internal
++ * \brief Encode and queue the Q.SIG CalledName invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode name.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rose_called_name_encode(struct pri *ctrl, q931_call *call, int messagetype)
+ {
+- int i = 0;
+- int size = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
++ unsigned char buffer[256];
++ unsigned char *end;
+
++ /* CalledName is the local_id.name */
++ end = enc_qsig_called_name(ctrl, buffer, buffer + sizeof(buffer),
++ &call->local_id.name);
++ if (!end) {
++ return -1;
++ }
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
++ return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
++}
+
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT NumberDigits -- default: unknownPartyNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PartyNumber: UnknownPartyNumber len=%d\n", len);
+- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_UNKNOWN;
+- value->ton = PRI_TON_UNKNOWN;
+- break;
++/*!
++ * \internal
++ * \brief Encode the Q.SIG ConnectedName invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param name Name data which to encode name.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_connected_name(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct q931_party_name *name)
++{
++ struct fac_extension_header header;
++ struct rose_msg_invoke msg;
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT PublicPartyNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PartyNumber: PublicPartyNumber len=%d\n", len);
+- size = rose_public_party_number_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_E163_E164;
+- break;
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT NumberDigits -- not used: dataPartyNumber */
+- pri_message(pri, "!! PartyNumber: dataPartyNumber is reserved!\n");
+- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_X121 /* ??? */;
+- value->ton = PRI_TON_UNKNOWN /* ??? */;
+- break;
++ memset(&msg, 0, sizeof(msg));
++ msg.operation = ROSE_QSIG_ConnectedName;
++ msg.invoke_id = get_invokeid(ctrl);
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] IMPLICIT NumberDigits -- not used: telexPartyNumber */
+- pri_message(pri, "!! PartyNumber: telexPartyNumber is reserved!\n");
+- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_F69 /* ??? */;
+- value->ton = PRI_TON_UNKNOWN /* ??? */;
+- break;
++ /* ConnectedName */
++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.ConnectedName.name, name);
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT PrivatePartyNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PartyNumber: PrivatePartyNumber len=%d\n", len);
+- size = rose_private_party_number_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_PRIVATE;
+- break;
++ pos = rose_encode_invoke(ctrl, pos, end, &msg);
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] IMPLICIT NumberDigits -- not used: nationalStandatdPartyNumber */
+- pri_message(pri, "!! PartyNumber: nationalStandardPartyNumber is reserved!\n");
+- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- value->npi = PRI_NPI_NATIONAL;
+- value->ton = PRI_TON_NATIONAL;
+- break;
++ return pos;
++}
+
+- default:
+- pri_message(pri, "Invalid PartyNumber component 0x%X\n", comp->type);
+- return -1;
+- }
+- ASN1_FIXUP_LEN(comp, size);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PartyNumber: '%s' size=%d len=%d\n", value->partyaddress, size, len);
+- return size;
++/*!
++ * \internal
++ * \brief Encode and queue the Q.SIG ConnectedName invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode name.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int rose_connected_name_encode(struct pri *ctrl, q931_call *call, int messagetype)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
++
++ /* ConnectedName is the local_id.name */
++ end = enc_qsig_connected_name(ctrl, buffer, buffer + sizeof(buffer),
++ &call->local_id.name);
++ if (!end) {
++ return -1;
+ }
+- while (0);
+
+- return -1;
++ return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL);
+ }
+
+-
+-static int rose_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
++/*!
++ * \brief Put the APDU on the call queue.
++ *
++ * \param call Call to enqueue message.
++ * \param messagetype Q.931 message type.
++ * \param apdu Facility ie contents buffer.
++ * \param apdu_len Length of the contents buffer.
++ * \param response Sender supplied information to handle APDU response messages.
++ * NULL if don't care about responses.
++ *
++ * \note
++ * Only APDU messages with an invoke component can supply a response pointer.
++ * If any other APDU messages supply a response pointer then aliasing of the
++ * invoke_id can occur.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response)
+ {
+- int i = 0;
+- int size = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
++ struct apdu_event *cur = NULL;
++ struct apdu_event *new_event = NULL;
+
+- int scrind = -1;
+-
+- do {
+- /* Party Number */
+- GET_COMPONENT(comp, i, vdata, len);
+- size = rose_party_number_decode(pri, call, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened*) value);
+- if (size < 0)
++ if (!call || !messagetype || !apdu
++ || apdu_len < 1 || sizeof(new_event->apdu) < apdu_len) {
++ return -1;
++ }
++ switch (messagetype) {
++ case Q931_FACILITY:
++ break;
++ default:
++ if (q931_is_dummy_call(call)) {
++ pri_error(call->pri, "!! Cannot send %s message on dummy call reference.\n",
++ msg2str(messagetype));
+ return -1;
+- comp->len = size;
+- NEXT_COMPONENT(comp, i);
++ }
++ break;
++ }
+
+- /* Screening Indicator */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with NumberScreened ROSE component type 0x%x\n");
+- ASN1_GET_INTEGER(comp, scrind);
+- // Todo: scrind = screeningindicator_for_q931(pri, scrind);
+- NEXT_COMPONENT(comp, i);
++ new_event = calloc(1, sizeof(*new_event));
++ if (!new_event) {
++ pri_error(call->pri, "!! Malloc failed!\n");
++ return -1;
++ }
+
+- value->scrind = scrind;
++ /* Fill in the APDU event */
++ new_event->message = messagetype;
++ if (response) {
++ new_event->response = *response;
++ }
++ new_event->call = call;
++ new_event->apdu_len = apdu_len;
++ memcpy(new_event->apdu, apdu, apdu_len);
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " NumberScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len);
+-
+- return i-2; // We do not have a sequence header here.
++ /* Append APDU event to the end of the list. */
++ if (call->apdus) {
++ for (cur = call->apdus; cur->next; cur = cur->next) {
++ }
++ cur->next = new_event;
++ } else {
++ call->apdus = new_event;
+ }
+- while (0);
+
+- return -1;
++ return 0;
+ }
+
+-
+-static int rose_presented_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
++/* Used by q931.c to cleanup the apdu queue upon destruction of a call */
++void pri_call_apdu_queue_cleanup(q931_call *call)
+ {
+- int i = 0;
+- int size = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = data;
++ struct apdu_event *cur_event;
++ struct apdu_event *free_event;
+
+- /* Fill in default values */
+- value->ton = PRI_TON_UNKNOWN;
+- value->npi = PRI_NPI_UNKNOWN;
+- value->pres = -1; /* Data is not available */
++ if (call) {
++ cur_event = call->apdus;
++ call->apdus = NULL;
++ while (cur_event) {
++ if (cur_event->response.callback) {
++ /* Indicate to callback that the APDU is being cleaned up. */
++ cur_event->response.callback(APDU_CALLBACK_REASON_CLEANUP, call->pri,
++ call, cur_event, NULL);
+
+- do {
+- GET_COMPONENT(comp, i, vdata, len);
++ /* Stop any response timeout. */
++ pri_schedule_del(call->pri, cur_event->timer);
++ }
++ free_event = cur_event;
++ cur_event = cur_event->next;
++ free(free_event);
++ }
++ }
++}
+
+- switch(comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: presentationAllowedNumber comp->len=%d\n", comp->len);
+- value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
+- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
++/*!
++ * \internal
++ * \brief Find an outstanding APDU with the given invoke id.
++ *
++ * \param call Call to find APDU.
++ * \param invoke_id Invoke id to match outstanding APDUs in queue.
++ *
++ * \retval apdu_event if found.
++ * \retval NULL if not found.
++ */
++static struct apdu_event *pri_call_apdu_find(struct q931_call *call, int invoke_id)
++{
++ struct apdu_event *apdu;
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: presentationRestricted comp->len=%d\n", comp->len);
+- if (comp->len != 0) { /* must be NULL */
+- pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
+- return -1;
+- }
+- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
+- return 2;
++ for (apdu = call->apdus; apdu; apdu = apdu->next) {
++ /*
++ * Note: The APDU cannot be sent and still in the queue without a
++ * callback and timeout timer active. Therefore, an invoke_id of
++ * zero is valid and not just the result of a memset().
++ */
++ if (apdu->response.invoke_id == invoke_id && apdu->sent) {
++ break;
++ }
++ }
++ return apdu;
++}
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len);
+- if (comp->len != 0) { /* must be NULL */
+- pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
+- return -1;
+- }
+- value->pres = PRES_NUMBER_NOT_AVAILABLE;
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len);
+- return 2;
++/*!
++ * \brief Delete the given APDU event from the given call.
++ *
++ * \param call Call to remove the APDU.
++ * \param doomed APDU event to delete.
++ *
++ * \return Nothing
++ */
++void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed)
++{
++ struct apdu_event **prev;
++ struct apdu_event *cur;
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedNumber */
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " PresentedNumberScreened: presentationRestrictedNumber comp->len=%d\n", comp->len);
+- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
+- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value);
+- if (size < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, size);
+- return size + 2;
++ /* Find APDU in list. */
++ for (prev = &call->apdus, cur = call->apdus;
++ cur;
++ prev = &cur->next, cur = cur->next) {
++ if (cur == doomed) {
++ /* Stop any response timeout. */
++ pri_schedule_del(call->pri, cur->timer);
+
+- default:
+- pri_message(pri, "Invalid PresentedNumberScreened component 0x%X\n", comp->type);
++ /* Remove APDU from list. */
++ *prev = cur->next;
++ free(cur);
++ break;
+ }
+- return -1;
+ }
+- while (0);
+-
+- return -1;
+ }
+
+-
+-static int rose_call_transfer_complete_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
++/*! \note Only called when sending the SETUP message. */
++int pri_call_add_standard_apdus(struct pri *ctrl, q931_call *call)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = sequence->data;
+- int res = 0;
++ if (!ctrl->sendfacility) {
++ return 0;
++ }
+
+- int end_designation = 0;
+- struct addressingdataelements_presentednumberscreened redirection_number;
+- char redirection_name[50] = "";
+- int call_status = 0;
+- redirection_number.partyaddress[0] = 0;
+- redirection_number.partysubaddress[0] = 0;
+- call->callername[0] = 0;
+- call->callernum[0] = 0;
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (q931_is_ptmp(ctrl)) {
++ /* PTMP mode */
++ break;
++ }
++ /* PTP mode */
++ if (call->redirecting.count) {
++ rose_diverting_leg_information2_encode(ctrl, call);
+
++ /*
++ * Expect a DivertingLegInformation3 to update the COLR of the
++ * redirecting-to party we are attempting to call now.
++ */
++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3;
++ }
++ break;
++ case PRI_SWITCH_QSIG:
++ /* For Q.SIG it does network and cpe operations */
++ if (call->redirecting.count) {
++ rose_diverting_leg_information2_encode(ctrl, call);
+
+- /* Data checks */
+- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
+- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n");
+- return -1;
++ /*
++ * Expect a DivertingLegInformation3 to update the COLR of the
++ * redirecting-to party we are attempting to call now.
++ */
++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3;
++ }
++ add_callername_facility_ies(ctrl, call, 1);
++ break;
++ case PRI_SWITCH_NI2:
++ add_callername_facility_ies(ctrl, call, (ctrl->localtype == PRI_CPE));
++ break;
++ case PRI_SWITCH_DMS100:
++ if (ctrl->localtype == PRI_CPE) {
++ add_dms100_transfer_ability_apdu(ctrl, call);
++ }
++ break;
++ default:
++ break;
+ }
+
+- if (sequence->len == ASN1_LEN_INDEF) {
+- len -= 4; /* For the 2 extra characters at the end
+- * and two characters of header */
+- } else
+- len -= 2;
++ return 0;
++}
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: len=%d\n", len);
++/*!
++ * \brief Send the CallTransferComplete/EctInform invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode call transfer.
++ * \param call_status TRUE if call is alerting.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int send_call_transfer_complete(struct pri *ctrl, q931_call *call, int call_status)
++{
++ if (rose_call_transfer_complete_encode(ctrl, call, call_status)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for call transfer completed.\n");
++ return -1;
++ }
+
+- do {
+- /* End Designation */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid endDesignation type 0x%X of ROSE callTransferComplete component received\n");
+- ASN1_GET_INTEGER(comp, end_designation);
+- NEXT_COMPONENT(comp, i);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received endDesignation=%d\n", end_designation);
++ return 0;
++}
+
++/*!
++ * \internal
++ * \brief Encode a plain facility ETSI error code.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode error message response.
++ * \param invoke_id Invoke id to put in error message response.
++ * \param code Error code to put in error message response.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_error(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int invoke_id, enum rose_error_code code)
++{
++ struct rose_msg_error msg;
+
+- /* Redirection Number */
+- GET_COMPONENT(comp, i, vdata, len);
+- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number);
+- if (res < 0)
+- return -1;
+- comp->len = res;
+- if (res > 2) {
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress);
+- strncpy(call->callernum, redirection_number.partyaddress, 20);
+- call->callernum[20] = 0;
+- }
+- NEXT_COMPONENT(comp, i);
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
++ memset(&msg, 0, sizeof(msg));
++ msg.invoke_id = invoke_id;
++ msg.code = code;
+
+-#if 0 /* This one is optional. How do we check if it is there? */
+- /* Basic Call Info Elements */
+- GET_COMPONENT(comp, i, vdata, len);
+- NEXT_COMPONENT(comp, i);
+-#endif
++ pos = rose_encode_error(ctrl, pos, end, &msg);
+
++ return pos;
++}
+
+- /* Redirection Name */
+- GET_COMPONENT(comp, i, vdata, len);
+- res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name));
+- if (res < 0)
+- return -1;
+- memcpy(call->callername, comp->data, comp->len);
+- call->callername[comp->len] = 0;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- NEXT_COMPONENT(comp, i);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name);
++/*!
++ * \internal
++ * \brief Encode a plain facility Q.SIG error code.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode error message response.
++ * \param invoke_id Invoke id to put in error message response.
++ * \param code Error code to put in error message response.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_error(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int invoke_id, enum rose_error_code code)
++{
++ struct fac_extension_header header;
++ struct rose_msg_error msg;
+
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
++ }
+
+- /* Call Status */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid callStatus type 0x%X of ROSE callTransferComplete component received\n");
+- ASN1_GET_INTEGER(comp, call_status);
+- NEXT_COMPONENT(comp, i);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received callStatus=%d\n", call_status);
++ memset(&msg, 0, sizeof(msg));
++ msg.invoke_id = invoke_id;
++ msg.code = code;
+
++ pos = rose_encode_error(ctrl, pos, end, &msg);
+
+- /* Argument Extension */
+-#if 0 /* Not supported */
+- GET_COMPONENT(comp, i, vdata, len);
+- switch (comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */
+- res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++ return pos;
++}
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */
+- res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++/*!
++ * \internal
++ * \brief Encode and queue a plain facility error code.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode error message response.
++ * \param invoke_id Invoke id to put in error message response.
++ * \param code Error code to put in error message response.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_facility_error_encode(struct pri *ctrl, q931_call *call, int invoke_id,
++ enum rose_error_code code)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
+
+- default:
+- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type);
+- return -1;
+- }
+-#else
+- GET_COMPONENT(comp, i, vdata, len);
+- ASN1_FIXUP_LEN(comp, res);
+- NEXT_COMPONENT(comp, i);
+-#endif
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end =
++ enc_etsi_error(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id, code);
++ break;
++ case PRI_SWITCH_QSIG:
++ end =
++ enc_qsig_error(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id, code);
++ break;
++ default:
++ return -1;
++ }
++ if (!end) {
++ return -1;
++ }
+
+- if(i < len)
+- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len);
++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL);
++}
+
+- return 0;
++/*!
++ * \brief Encode and send a plain facility error code.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode error message response.
++ * \param invoke_id Invoke id to put in error message response.
++ * \param code Error code to put in error message response.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int send_facility_error(struct pri *ctrl, q931_call *call, int invoke_id,
++ enum rose_error_code code)
++{
++ if (rose_facility_error_encode(ctrl, call, invoke_id, code)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for error message.\n");
++ return -1;
+ }
+- while (0);
+
+- return -1;
++ return 0;
+ }
+
+-
+-static int rose_call_transfer_update_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
++/*!
++ * \internal
++ * \brief Encode a plain facility ETSI result ok.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode result ok message response.
++ * \param invoke_id Invoke id to put in result ok message response.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_etsi_result_ok(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int invoke_id)
+ {
+- int i = 0;
+- struct rose_component *comp = NULL;
+- unsigned char *vdata = sequence->data;
+- int res = 0;
++ struct rose_msg_result msg;
+
+- struct addressingdataelements_presentednumberscreened redirection_number;
+- redirection_number.partyaddress[0] = 0;
+- redirection_number.partysubaddress[0] = 0;
+- char redirection_name[50] = "";
+- call->callername[0] = 0;
+- call->callernum[0] = 0;
++ pos = facility_encode_header(ctrl, pos, end, NULL);
++ if (!pos) {
++ return NULL;
++ }
+
++ memset(&msg, 0, sizeof(msg));
++ msg.invoke_id = invoke_id;
++ msg.operation = ROSE_None;
+
+- /* Data checks */
+- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
+- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n");
+- return -1;
++ pos = rose_encode_result(ctrl, pos, end, &msg);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode a plain facility Q.SIG result ok.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param call Call leg from which to encode result ok message response.
++ * \param invoke_id Invoke id to put in result ok message response.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *enc_qsig_result_ok(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, q931_call *call, int invoke_id)
++{
++ struct fac_extension_header header;
++ struct rose_msg_result msg;
++
++ memset(&header, 0, sizeof(header));
++ header.nfe_present = 1;
++ header.nfe.source_entity = 0; /* endPINX */
++ header.nfe.destination_entity = 0; /* endPINX */
++ header.interpretation_present = 1;
++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */
++ pos = facility_encode_header(ctrl, pos, end, &header);
++ if (!pos) {
++ return NULL;
+ }
+
+- if (sequence->len == ASN1_LEN_INDEF) {
+- len -= 4; /* For the 2 extra characters at the end
+- * and two characters of header */
+- } else
+- len -= 2;
++ memset(&msg, 0, sizeof(msg));
++ msg.invoke_id = invoke_id;
++ msg.operation = ROSE_None;
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: len=%d\n", len);
++ pos = rose_encode_result(ctrl, pos, end, &msg);
+
+- do {
+- /* Redirection Number */
+- GET_COMPONENT(comp, i, vdata, len);
+- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number);
+- if (res < 0)
+- return -1;
+- comp->len = res;
+- if (res > 2) {
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress);
+- strncpy(call->callernum, redirection_number.partyaddress, 20);
+- call->callernum[20] = 0;
+- }
+- NEXT_COMPONENT(comp, i);
++ return pos;
++}
+
+- /* Redirection Name */
+- GET_COMPONENT(comp, i, vdata, len);
+- res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name));
+- if (res < 0)
+- return -1;
+- memcpy(call->callername, comp->data, comp->len);
+- call->callername[comp->len] = 0;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
+- NEXT_COMPONENT(comp, i);
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name);
++/*!
++ * \internal
++ * \brief Encode and queue a plain ROSE result ok.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode result ok message response.
++ * \param msgtype Q.931 message type to put facility ie in.
++ * \param invoke_id Invoke id to put in result ok message response.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int rose_result_ok_encode(struct pri *ctrl, q931_call *call, int msgtype, int invoke_id)
++{
++ unsigned char buffer[256];
++ unsigned char *end;
+
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ end =
++ enc_etsi_result_ok(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id);
++ break;
++ case PRI_SWITCH_QSIG:
++ end =
++ enc_qsig_result_ok(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id);
++ break;
++ default:
++ return -1;
++ }
++ if (!end) {
++ return -1;
++ }
+
+-#if 0 /* This one is optional. How do we check if it is there? */
+- /* Basic Call Info Elements */
+- GET_COMPONENT(comp, i, vdata, len);
+- NEXT_COMPONENT(comp, i);
+-#endif
++ return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL);
++}
+
++/*!
++ * \brief Encode and send a FACILITY message with a plain ROSE result ok.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which to encode result ok message response.
++ * \param invoke_id Invoke id to put in result ok message response.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int send_facility_result_ok(struct pri *ctrl, q931_call *call, int invoke_id)
++{
++ if (rose_result_ok_encode(ctrl, call, Q931_FACILITY, invoke_id)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for result OK message.\n");
++ return -1;
++ }
+
+- /* Argument Extension */
+-#if 0 /* Not supported */
+- GET_COMPONENT(comp, i, vdata, len);
+- switch (comp->type) {
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */
+- res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++ return 0;
++}
+
+- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */
+- res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
+- if (res < 0)
+- return -1;
+- ASN1_FIXUP_LEN(comp, res);
+- comp->len = res;
++int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI_REROUTING_RSP_CODE code)
++{
++ enum rose_error_code rose_err;
+
+- default:
+- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type);
+- return -1;
+- }
+-#else
+- GET_COMPONENT(comp, i, vdata, len);
+- ASN1_FIXUP_LEN(comp, res);
+- NEXT_COMPONENT(comp, i);
+-#endif
++ if (!ctrl || !call) {
++ return -1;
++ }
+
+- if(i < len)
+- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len);
++ /* Convert the public rerouting response code to an error code or result ok. */
++ rose_err = ROSE_ERROR_Gen_ResourceUnavailable;
++ switch (code) {
++ case PRI_REROUTING_RSP_OK_CLEAR:
++ return rose_result_ok_encode(ctrl, call, Q931_DISCONNECT, invoke_id);
++ case PRI_REROUTING_RSP_OK_RETAIN:
++ return send_facility_result_ok(ctrl, call, invoke_id);
++ case PRI_REROUTING_RSP_NOT_SUBSCRIBED:
++ rose_err = ROSE_ERROR_Gen_NotSubscribed;
++ break;
++ case PRI_REROUTING_RSP_NOT_AVAILABLE:
++ rose_err = ROSE_ERROR_Gen_NotAvailable;
++ break;
++ case PRI_REROUTING_RSP_NOT_ALLOWED:
++ rose_err = ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed;
++ break;
++ case PRI_REROUTING_RSP_INVALID_NUMBER:
++ rose_err = ROSE_ERROR_Div_InvalidDivertedToNr;
++ break;
++ case PRI_REROUTING_RSP_SPECIAL_SERVICE_NUMBER:
++ rose_err = ROSE_ERROR_Div_SpecialServiceNr;
++ break;
++ case PRI_REROUTING_RSP_DIVERSION_TO_SELF:
++ rose_err = ROSE_ERROR_Div_DiversionToServedUserNr;
++ break;
++ case PRI_REROUTING_RSP_MAX_DIVERSIONS_EXCEEDED:
++ rose_err = ROSE_ERROR_Div_NumberOfDiversionsExceeded;
++ break;
++ case PRI_REROUTING_RSP_RESOURCE_UNAVAILABLE:
++ rose_err = ROSE_ERROR_Gen_ResourceUnavailable;
++ break;
++ }
++ return send_facility_error(ctrl, call, invoke_id, rose_err);
++}
+
+- return 0;
++/*!
++ * \brief Handle the ROSE reject message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which the message came.
++ * \param msgtype Q.931 message type ie is in.
++ * \param ie Raw ie contents.
++ * \param header Decoded facility header before ROSE.
++ * \param reject Decoded ROSE reject message contents.
++ *
++ * \return Nothing
++ */
++void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
++ const struct fac_extension_header *header, const struct rose_msg_reject *reject)
++{
++ struct apdu_event *apdu;
++ union apdu_msg_data msg;
++
++ /* Gripe to the user about getting rejected. */
++ pri_error(ctrl, "ROSE REJECT:\n");
++ if (reject->invoke_id_present) {
++ pri_error(ctrl, "\tINVOKE ID: %d\n", reject->invoke_id);
+ }
+- while (0);
++ pri_error(ctrl, "\tPROBLEM: %s\n", rose_reject2str(reject->code));
+
+- return -1;
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ /* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
++ return;
++ default:
++ break;
++ }
++
++ if (!reject->invoke_id_present) {
++ /*
++ * No invoke id to look up so we cannot match it to any outstanding APDUs.
++ * This REJECT is apparently meant for someone monitoring the link.
++ */
++ return;
++ }
++ apdu = pri_call_apdu_find(call, reject->invoke_id);
++ if (!apdu) {
++ return;
++ }
++ msg.reject = reject;
++ if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_REJECT, ctrl, call, apdu, &msg)) {
++ pri_call_apdu_delete(call, apdu);
++ }
+ }
+
++/*!
++ * \brief Handle the ROSE error message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which the message came.
++ * \param msgtype Q.931 message type ie is in.
++ * \param ie Raw ie contents.
++ * \param header Decoded facility header before ROSE.
++ * \param error Decoded ROSE error message contents.
++ *
++ * \return Nothing
++ */
++void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
++ const struct fac_extension_header *header, const struct rose_msg_error *error)
++{
++ const char *dms100_operation;
++ struct apdu_event *apdu;
++ union apdu_msg_data msg;
+
+-/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */
++ /* Gripe to the user about getting an error. */
++ pri_error(ctrl, "ROSE RETURN ERROR:\n");
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ switch (error->invoke_id) {
++ case ROSE_DMS100_RLT_OPERATION_IND:
++ dms100_operation = "RLT_OPERATION_IND";
++ break;
++ case ROSE_DMS100_RLT_THIRD_PARTY:
++ dms100_operation = "RLT_THIRD_PARTY";
++ break;
++ default:
++ dms100_operation = NULL;
++ break;
++ }
++ if (dms100_operation) {
++ pri_error(ctrl, "\tOPERATION: %s\n", dms100_operation);
++ break;
++ }
++ /* fall through */
++ default:
++ pri_error(ctrl, "\tINVOKE ID: %d\n", error->invoke_id);
++ break;
++ }
++ pri_error(ctrl, "\tERROR: %s\n", rose_error2str(error->code));
+
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ /* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
++ return;
++ default:
++ break;
++ }
+
++ apdu = pri_call_apdu_find(call, error->invoke_id);
++ if (!apdu) {
++ return;
++ }
++ msg.error = error;
++ if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_ERROR, ctrl, call, apdu, &msg)) {
++ pri_call_apdu_delete(call, apdu);
++ }
++}
+
+-int rose_reject_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
++/*!
++ * \brief Handle the ROSE result message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which the message came.
++ * \param msgtype Q.931 message type ie is in.
++ * \param ie Raw ie contents.
++ * \param header Decoded facility header before ROSE.
++ * \param result Decoded ROSE result message contents.
++ *
++ * \return Nothing
++ */
++void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
++ const struct fac_extension_header *header, const struct rose_msg_result *result)
+ {
+- int i = 0;
+- int problemtag = -1;
+- int problem = -1;
+- int invokeidvalue = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL;
+- char *problemtagstr, *problemstr;
+-
+- do {
+- /* Invoke ID stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, invokeidvalue);
+- NEXT_COMPONENT(comp, i);
++ struct apdu_event *apdu;
++ union apdu_msg_data msg;
+
+- GET_COMPONENT(comp, i, vdata, len);
+- problemtag = comp->type;
+- problem = comp->data[0];
+-
+- if (pri->switchtype == PRI_SWITCH_DMS100) {
+- switch (problemtag) {
+- case 0x80:
+- problemtagstr = "General problem";
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ /* The DMS-100 switch apparently handles invoke_id as an invoke operation. */
++ switch (result->invoke_id) {
++ case ROSE_DMS100_RLT_OPERATION_IND:
++ if (result->operation != ROSE_DMS100_RLT_OperationInd) {
++ pri_message(ctrl, "Invalid Operation value in return result! %s\n",
++ rose_operation2str(result->operation));
+ break;
+- case 0x81:
+- problemtagstr = "Invoke problem";
+- break;
+- case 0x82:
+- problemtagstr = "Return result problem";
+- break;
+- case 0x83:
+- problemtagstr = "Return error problem";
+- break;
+- default:
+- problemtagstr = "Unknown";
+ }
+
+- switch (problem) {
+- case 0x00:
+- problemstr = "Unrecognized component";
+- break;
+- case 0x01:
+- problemstr = "Mistyped component";
+- break;
+- case 0x02:
+- problemstr = "Badly structured component";
+- break;
+- default:
+- problemstr = "Unknown";
++ /* We have enough data to transfer the call */
++ call->rlt_call_id = result->args.dms100.RLT_OperationInd.call_id;
++ call->transferable = 1;
++ break;
++ case ROSE_DMS100_RLT_THIRD_PARTY:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "Successfully completed RLT transfer!\n");
+ }
+-
+- pri_error(pri, "ROSE REJECT:\n");
+- pri_error(pri, "\tINVOKE ID: 0x%X\n", invokeidvalue);
+- pri_error(pri, "\tPROBLEM TYPE: %s (0x%x)\n", problemtagstr, problemtag);
+- pri_error(pri, "\tPROBLEM: %s (0x%x)\n", problemstr, problem);
+-
+- return 0;
+- } else {
+- pri_message(pri, "Unable to handle reject on switchtype %d!\n", pri->switchtype);
+- return -1;
++ break;
++ default:
++ pri_message(ctrl, "Could not parse invoke of type %d!\n", result->invoke_id);
++ break;
+ }
++ return;
++ default:
++ break;
++ }
+
+- } while(0);
+-
+- return -1;
++ apdu = pri_call_apdu_find(call, result->invoke_id);
++ if (!apdu) {
++ return;
++ }
++ msg.result = result;
++ if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_RESULT, ctrl, call, apdu, &msg)) {
++ pri_call_apdu_delete(call, apdu);
++ }
+ }
+-int rose_return_error_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
++
++/*!
++ * \brief Handle the ROSE invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param call Call leg from which the message came.
++ * \param msgtype Q.931 message type ie is in.
++ * \param ie Raw ie contents.
++ * \param header Decoded facility header before ROSE.
++ * \param invoke Decoded ROSE invoke message contents.
++ *
++ * \return Nothing
++ */
++void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie,
++ const struct fac_extension_header *header, const struct rose_msg_invoke *invoke)
+ {
+- int i = 0;
+- int errorvalue = -1;
+- int invokeidvalue = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL;
+- char *invokeidstr, *errorstr;
+-
+- do {
+- /* Invoke ID stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, invokeidvalue);
+- NEXT_COMPONENT(comp, i);
++ struct pri_subcommand *subcmd;
++ struct q931_party_id party_id;
++ struct q931_party_redirecting deflection;
+
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if second component in return error is 0x%x\n");
+- ASN1_GET_INTEGER(comp, errorvalue);
++ switch (invoke->operation) {
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_ActivationDiversion:
++ break;
++ case ROSE_ETSI_DeactivationDiversion:
++ break;
++ case ROSE_ETSI_ActivationStatusNotificationDiv:
++ break;
++ case ROSE_ETSI_DeactivationStatusNotificationDiv:
++ break;
++ case ROSE_ETSI_InterrogationDiversion:
++ break;
++ case ROSE_ETSI_DiversionInformation:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_CallDeflection:
++ if (!PRI_MASTER(ctrl)->deflection_support) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_NotSubscribed);
++ break;
++ }
++ if (!q931_master_pass_event(ctrl, call, msgtype)) {
++ /* Some other user is further along to connecting than this call. */
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Div_IncomingCallAccepted);
++ break;
++ }
++ if (call->master_call->deflection_in_progress) {
++ /* Someone else is already doing a call deflection. */
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Div_RequestAlreadyAccepted);
++ break;
++ }
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ /*
++ * ROSE_ERROR_Gen_ResourceUnavailable was not in the list of allowed codes,
++ * but we will send it anyway.
++ */
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_ResourceUnavailable);
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
+
+- if (pri->switchtype == PRI_SWITCH_DMS100) {
+- switch (invokeidvalue) {
+- case RLT_OPERATION_IND:
+- invokeidstr = "RLT_OPERATION_IND";
+- break;
+- case RLT_THIRD_PARTY:
+- invokeidstr = "RLT_THIRD_PARTY";
+- break;
+- default:
+- invokeidstr = "Unknown";
+- }
++ call->master_call->deflection_in_progress = 1;
+
+- switch (errorvalue) {
+- case 0x10:
+- errorstr = "RLT Bridge Fail";
+- break;
+- case 0x11:
+- errorstr = "RLT Call ID Not Found";
+- break;
+- case 0x12:
+- errorstr = "RLT Not Allowed";
+- break;
+- case 0x13:
+- errorstr = "RLT Switch Equip Congs";
+- break;
+- default:
+- errorstr = "Unknown";
+- }
++ q931_party_redirecting_init(&deflection);
+
+- pri_error(pri, "ROSE RETURN ERROR:\n");
+- pri_error(pri, "\tOPERATION: %s\n", invokeidstr);
+- pri_error(pri, "\tERROR: %s\n", errorstr);
++ /* Deflecting from the called address. */
++ q931_party_address_to_id(&deflection.from, &call->called);
++ if (invoke->args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present) {
++ deflection.from.number.presentation =
++ invoke->args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user
++ ? PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED
++ : PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ } else {
++ deflection.from.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ }
+
+- return 0;
++ /* Deflecting to the new address. */
++ rose_copy_address_to_q931(ctrl, &deflection.to,
++ &invoke->args.etsi.CallDeflection.deflection);
++ deflection.to.number.presentation = deflection.from.number.presentation;
++
++ deflection.count = (call->redirecting.count < PRI_MAX_REDIRECTS)
++ ? call->redirecting.count + 1 : PRI_MAX_REDIRECTS;
++ deflection.reason = PRI_REDIR_DEFLECTION;
++ if (deflection.count == 1) {
++ deflection.orig_called = deflection.from;
++ deflection.orig_reason = deflection.reason;
+ } else {
+- pri_message(pri, "Unable to handle return error on switchtype %d!\n", pri->switchtype);
++ deflection.orig_called = call->redirecting.orig_called;
++ deflection.orig_reason = call->redirecting.orig_reason;
+ }
+
+- } while(0);
+-
+- return -1;
+-}
++ subcmd->cmd = PRI_SUBCMD_REROUTING;
++ subcmd->u.rerouting.invoke_id = invoke->invoke_id;
++ subcmd->u.rerouting.subscription_option = 3;/* notApplicable */
++ q931_party_id_copy_to_pri(&subcmd->u.rerouting.caller, &call->local_id);
++ q931_party_redirecting_copy_to_pri(&subcmd->u.rerouting.deflection,
++ &deflection);
++ break;
++ case ROSE_ETSI_CallRerouting:
++ if (!PRI_MASTER(ctrl)->deflection_support) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_NotSubscribed);
++ break;
++ }
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_ResourceUnavailable);
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
+
+-int rose_return_result_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
+-{
+- int i = 0;
+- int operationidvalue = -1;
+- int invokeidvalue = -1;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL;
+-
+- do {
+- /* Invoke ID stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
+- ASN1_GET_INTEGER(comp, invokeidvalue);
+- NEXT_COMPONENT(comp, i);
++ q931_party_redirecting_init(&deflection);
+
+- if (pri->switchtype == PRI_SWITCH_DMS100) {
+- switch (invokeidvalue) {
+- case RLT_THIRD_PARTY:
+- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed RLT transfer!\n");
+- return 0;
+- case RLT_OPERATION_IND:
+- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Received RLT_OPERATION_IND\n");
+- /* Have to take out the rlt_call_id */
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Protocol error detected in parsing RLT_OPERATION_IND return result!\n");
++ /* Rerouting from the last address. */
++ rose_copy_presented_number_unscreened_to_q931(ctrl, &deflection.from.number,
++ &invoke->args.etsi.CallRerouting.last_rerouting);
+
+- /* Traverse the contents of this sequence */
+- /* First is the Operation Value */
+- SUB_COMPONENT(comp, i);
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "RLT_OPERATION_IND should be of type ASN1_INTEGER!\n");
+- ASN1_GET_INTEGER(comp, operationidvalue);
++ /* Rerouting to the new address. */
++ rose_copy_address_to_q931(ctrl, &deflection.to,
++ &invoke->args.etsi.CallRerouting.called_address);
++ switch (invoke->args.etsi.CallRerouting.subscription_option) {
++ default:
++ case 0: /* noNotification */
++ case 1: /* notificationWithoutDivertedToNr */
++ deflection.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ case 2: /* notificationWithDivertedToNr */
++ deflection.to.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ }
+
+- if (operationidvalue != RLT_OPERATION_IND) {
+- pri_message(pri, "Invalid Operation ID value (0x%x) in return result!\n", operationidvalue);
+- return -1;
+- }
++ /* Calling party subaddress update. */
++ party_id = call->local_id;
+
+- /* Next is the Call ID */
+- NEXT_COMPONENT(comp, i);
+- GET_COMPONENT(comp, i, vdata, len);
+- CHECK_COMPONENT(comp, ASN1_TAG_0, "Error check failed on Call ID!\n");
+- ASN1_GET_INTEGER(comp, call->rlt_call_id);
+- /* We have enough data to transfer the call */
+- call->transferable = 1;
++ deflection.count = invoke->args.etsi.CallRerouting.rerouting_counter;
++ deflection.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.etsi.CallRerouting.rerouting_reason);
++ if (deflection.count == 1) {
++ deflection.orig_called = deflection.from;
++ deflection.orig_reason = deflection.reason;
++ } else {
++ deflection.orig_called = call->redirecting.orig_called;
++ deflection.orig_reason = call->redirecting.orig_reason;
++ }
+
+- return 0;
+-
+- default:
+- pri_message(pri, "Could not parse invoke of type 0x%x!\n", invokeidvalue);
+- return -1;
++ subcmd->cmd = PRI_SUBCMD_REROUTING;
++ subcmd->u.rerouting.invoke_id = invoke->invoke_id;
++ subcmd->u.rerouting.subscription_option =
++ invoke->args.etsi.CallRerouting.subscription_option;
++ q931_party_id_copy_to_pri(&subcmd->u.rerouting.caller, &party_id);
++ q931_party_redirecting_copy_to_pri(&subcmd->u.rerouting.deflection,
++ &deflection);
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_InterrogateServedUserNumbers:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_DivertingLegInformation1:
++ if (invoke->args.etsi.DivertingLegInformation1.diverted_to_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl, &party_id.number,
++ &invoke->args.etsi.DivertingLegInformation1.diverted_to);
++ /*
++ * We set the presentation value since the sender cannot know the
++ * presentation value preference of the destination party.
++ */
++ if (party_id.number.str[0]) {
++ party_id.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ } else {
++ party_id.number.presentation =
++ PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED;
+ }
+- } else if (pri->switchtype == PRI_SWITCH_QSIG) {
+- switch (invokeidvalue) {
+- case 0x13:
+- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed QSIG CF callRerouting!\n");
+- return 0;
+- }
+ } else {
+- pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype);
+- return -1;
++ q931_party_number_init(&party_id.number);
++ party_id.number.valid = 1;
+ }
+
+- } while(0);
+-
+- return -1;
+-}
++ /*
++ * Unless otherwise indicated by CONNECT, the divertedToNumber will be
++ * the remote_id.number.
++ */
++ if (!call->connected_number_in_message) {
++ call->remote_id.number = party_id.number;
++ }
+
+-int rose_invoke_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
+-{
+- int i = 0;
+- int res = 0;
+- int operation_tag;
+- unsigned char *vdata = data;
+- struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL;
+-
+- do {
+- /* Invoke ID stuff */
+- GET_COMPONENT(comp, i, vdata, len);
+-#if 0
+- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n");
+-#endif
+- invokeid = comp;
+- NEXT_COMPONENT(comp, i);
++ /* divertedToNumber is put in redirecting.to.number */
++ switch (invoke->args.etsi.DivertingLegInformation1.subscription_option) {
++ default:
++ case 0: /* noNotification */
++ case 1: /* notificationWithoutDivertedToNr */
++ q931_party_number_init(&call->redirecting.to.number);
++ call->redirecting.to.number.valid = 1;
++ call->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ case 2: /* notificationWithDivertedToNr */
++ call->redirecting.to.number = party_id.number;
++ break;
++ }
+
+- /* Operation Tag */
+- GET_COMPONENT(comp, i, vdata, len);
+-#if 0
+- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if second ROSE component is of type 0x%x\n");
+-#endif
+- operationid = comp;
+- ASN1_GET_INTEGER(comp, operation_tag);
+- NEXT_COMPONENT(comp, i);
++ call->redirecting.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.etsi.DivertingLegInformation1.diversion_reason);
++ if (call->redirecting.count < PRI_MAX_REDIRECTS) {
++ ++call->redirecting.count;
++ }
++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3;
++ break;
++ case ROSE_ETSI_DivertingLegInformation2:
++ call->redirecting.state = Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3;
++ call->redirecting.count =
++ invoke->args.etsi.DivertingLegInformation2.diversion_counter;
++ if (!call->redirecting.count) {
++ /* To be safe, make sure that the count is non-zero. */
++ call->redirecting.count = 1;
++ }
++ call->redirecting.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.etsi.DivertingLegInformation2.diversion_reason);
+
+- /* No argument - return with error */
+- if (i >= len)
+- return -1;
++ /* divertingNr is put in redirecting.from.number */
++ if (invoke->args.etsi.DivertingLegInformation2.diverting_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->redirecting.from.number,
++ &invoke->args.etsi.DivertingLegInformation2.diverting);
++ } else if (!call->redirecting_number_in_message) {
++ q931_party_number_init(&call->redirecting.from.number);
++ call->redirecting.from.number.valid = 1;
++ }
+
+- /* Arguement Tag */
+- GET_COMPONENT(comp, i, vdata, len);
+- if (!comp->type)
+- return -1;
++ call->redirecting.orig_reason = PRI_REDIR_UNKNOWN;
+
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " [ Handling operation %d ]\n", operation_tag);
+- switch (operation_tag) {
+- case SS_CNID_CALLINGNAME:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, " Handle Name display operation\n");
+- return rose_calling_name_decode(pri, call, comp, len-i);
+- case ROSE_CALL_TRANSFER_IDENTIFY:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_ABANDON:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_INITIATE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_SETUP:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_ACTIVE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: CallTransferActive - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_CALL_TRANSFER_COMPLETE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- {
+- pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
++ /* originalCalledNr is put in redirecting.orig_called.number */
++ if (invoke->args.etsi.DivertingLegInformation2.original_called_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->redirecting.orig_called.number,
++ &invoke->args.etsi.DivertingLegInformation2.original_called);
++ } else {
++ q931_party_number_init(&call->redirecting.orig_called.number);
++ }
++ break;
++ case ROSE_ETSI_DivertingLegInformation3:
++ /*
++ * Unless otherwise indicated by CONNECT, this will be the
++ * remote_id.number.presentation.
++ */
++ if (!invoke->args.etsi.DivertingLegInformation3.presentation_allowed_indicator) {
++ call->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ if (!call->connected_number_in_message) {
++ call->remote_id.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
+ }
+- return rose_call_transfer_complete_decode(pri, call, comp, len-i);
+- case ROSE_CALL_TRANSFER_UPDATE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- {
+- pri_message(pri, "ROSE %i: Handle CallTransferUpdate\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
++ }
++
++ switch (call->redirecting.state) {
++ case Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3:
++ call->redirecting.state = Q931_REDIRECTING_STATE_IDLE;
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
+ }
+- return rose_call_transfer_update_decode(pri, call, comp, len-i);
+- case ROSE_SUBADDRESS_TRANSFER:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- return -1;
+- case ROSE_DIVERTING_LEG_INFORMATION2:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return rose_diverting_leg_information2_decode(pri, call, comp, len-i);
+- case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag);
+- dump_apdu (pri, comp->data, comp->len);
+- }
+- return -1;
+- case ROSE_AOC_CHARGING_REQUEST:
+- return aoc_aoce_charging_request_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
+- case ROSE_AOC_AOCS_CURRENCY:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-S Currency - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCS_SPECIAL_ARR:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-S Special Array - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCD_CURRENCY:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-D Currency - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCD_CHARGING_UNIT:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-D Charging Unit - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCE_CURRENCY:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC-E Currency - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case ROSE_AOC_AOCE_CHARGING_UNIT:
+- return aoc_aoce_charging_unit_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
+- if (0) { /* the following function is currently not used - just to make the compiler happy */
+- aoc_aoce_charging_unit_encode(pri, call, call->aoc_units); /* use this function to forward the aoc-e on a bridged channel */
+- return 0;
+- }
+- case ROSE_AOC_IDENTIFICATION_OF_CHARGE:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "ROSE %i: AOC Identification Of Charge - not handled!", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
+- }
+- return -1;
+- case SS_ANFPR_PATHREPLACEMENT:
+- /* Clear Queue */
+- res = pri_call_apdu_queue_cleanup(call->bridged_call);
+- if (res) {
+- pri_message(pri, "Could not Clear queue ADPU\n");
+- return -1;
+- }
+- anfpr_pathreplacement_respond(pri, call, ie);
+- break;
++ /* Setup redirecting subcommand */
++ subcmd->cmd = PRI_SUBCMD_REDIRECTING;
++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting,
++ &call->redirecting);
++ break;
+ default:
+- if (pri->debug & PRI_DEBUG_APDU) {
+- pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag);
+- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
++ break;
++ }
++ break;
++ case ROSE_ETSI_ChargingRequest:
++ /* Ignore messsage */
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_AOCSCurrency:
++ break;
++ case ROSE_ETSI_AOCSSpecialArr:
++ break;
++ case ROSE_ETSI_AOCDCurrency:
++ break;
++ case ROSE_ETSI_AOCDChargingUnit:
++ break;
++ case ROSE_ETSI_AOCECurrency:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_AOCEChargingUnit:
++ call->aoc_units = 0;
++ if (invoke->args.etsi.AOCEChargingUnit.type == 1
++ && !invoke->args.etsi.AOCEChargingUnit.charging_unit.free_of_charge) {
++ unsigned index;
++
++ for (index =
++ invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.
++ num_records; index--;) {
++ if (!invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.
++ list[index].not_available) {
++ call->aoc_units +=
++ invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.
++ recorded.list[index].number_of_units;
++ }
+ }
+- return -1;
+ }
+- } while(0);
+-
+- return -1;
+-}
++ /* the following function is currently not used - just to make the compiler happy */
++ if (0) {
++ /* use this function to forward the aoc-e on a bridged channel */
++ aoc_aoce_charging_unit_encode(ctrl, call, call->aoc_units);
++ }
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ITU_IdentificationOfCharge:
++ break;
++#endif /* Not handled yet */
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_EctExecute:
++ break;
++ case ROSE_ETSI_ExplicitEctExecute:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_RequestSubaddress:
++ /* Ignore since we are not handling subaddresses yet. */
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_SubaddressTransfer:
++ break;
++ case ROSE_ETSI_EctLinkIdRequest:
++ break;
++#endif /* Not handled yet */
++ case ROSE_ETSI_EctInform:
++ /* redirectionNumber is put in remote_id.number */
++ if (invoke->args.etsi.EctInform.redirection_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->remote_id.number, &invoke->args.etsi.EctInform.redirection);
++ }
++ if (!invoke->args.etsi.EctInform.status) {
++ /* The remote party for the transfer has not answered yet. */
++ call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE;
++ } else {
++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
++ }
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_ETSI_EctLoopTest:
++ break;
++#endif /* Not handled yet */
++ case ROSE_QSIG_CallingName:
++ /* CallingName is put in remote_id.name */
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.CallingName.name);
++ break;
++ case ROSE_QSIG_CalledName:
++ /* CalledName is put in remote_id.name */
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.CalledName.name);
+
+-int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_len, void (*function)(void *data), void *data)
+-{
+- struct apdu_event *cur = NULL;
+- struct apdu_event *new_event = NULL;
++ /* Setup connected line subcommand */
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
++ subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE;
++ q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &call->remote_id);
++ break;
++ case ROSE_QSIG_ConnectedName:
++ /* ConnectedName is put in remote_id.name */
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.ConnectedName.name);
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_BusyName:
++ break;
++#endif /* Not handled yet */
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_ChargeRequest:
++ break;
++ case ROSE_QSIG_GetFinalCharge:
++ break;
++ case ROSE_QSIG_AocFinal:
++ break;
++ case ROSE_QSIG_AocInterim:
++ break;
++ case ROSE_QSIG_AocRate:
++ break;
++ case ROSE_QSIG_AocComplete:
++ break;
++ case ROSE_QSIG_AocDivChargeReq:
++ break;
++#endif /* Not handled yet */
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_CallTransferIdentify:
++ break;
++ case ROSE_QSIG_CallTransferAbandon:
++ break;
++ case ROSE_QSIG_CallTransferInitiate:
++ break;
++ case ROSE_QSIG_CallTransferSetup:
++ break;
++#endif /* Not handled yet */
++ case ROSE_QSIG_CallTransferActive:
++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
+
+- if (!call || !messagetype || !apdu || (apdu_len < 1) || (apdu_len > 255))
+- return -1;
++ /* connectedAddress is put in remote_id */
++ rose_copy_presented_address_screened_to_q931(ctrl, &call->remote_id,
++ &invoke->args.qsig.CallTransferActive.connected);
+
+- if (!(new_event = calloc(1, sizeof(*new_event)))) {
+- pri_error(call->pri, "!! Malloc failed!\n");
+- return -1;
+- }
++ /* connectedName is put in remote_id.name */
++ if (invoke->args.qsig.CallTransferActive.connected_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.CallTransferActive.connected_name);
++ }
++ break;
++ case ROSE_QSIG_CallTransferComplete:
++ /* redirectionNumber is put in remote_id.number */
++ rose_copy_presented_number_screened_to_q931(ctrl, &call->remote_id.number,
++ &invoke->args.qsig.CallTransferComplete.redirection);
+
+- new_event->message = messagetype;
+- new_event->callback = function;
+- new_event->data = data;
+- memcpy(new_event->apdu, apdu, apdu_len);
+- new_event->apdu_len = apdu_len;
+-
+- if (call->apdus) {
+- cur = call->apdus;
+- while (cur->next) {
+- cur = cur->next;
++ /* redirectionName is put in remote_id.name */
++ if (invoke->args.qsig.CallTransferComplete.redirection_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->remote_id.name,
++ &invoke->args.qsig.CallTransferComplete.redirection_name);
+ }
+- cur->next = new_event;
+- } else
+- call->apdus = new_event;
+
+- return 0;
+-}
++ if (invoke->args.qsig.CallTransferComplete.call_status == 1) {
++ /* The remote party for the transfer has not answered yet. */
++ call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE;
++ } else {
++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
++ }
++ break;
++ case ROSE_QSIG_CallTransferUpdate:
++ party_id = call->remote_id;
+
+-int pri_call_apdu_queue_cleanup(q931_call *call)
+-{
+- struct apdu_event *cur_event = NULL, *free_event = NULL;
++ /* redirectionNumber is put in party_id.number */
++ rose_copy_presented_number_screened_to_q931(ctrl, &party_id.number,
++ &invoke->args.qsig.CallTransferUpdate.redirection);
+
+- if (call && call->apdus) {
+- cur_event = call->apdus;
+- while (cur_event) {
+- /* TODO: callbacks, some way of giving return res on status of apdu */
+- free_event = cur_event;
+- cur_event = cur_event->next;
+- free(free_event);
++ /* redirectionName is put in party_id.name */
++ if (invoke->args.qsig.CallTransferUpdate.redirection_name_present) {
++ rose_copy_name_to_q931(ctrl, &party_id.name,
++ &invoke->args.qsig.CallTransferUpdate.redirection_name);
+ }
+- call->apdus = NULL;
+- }
+
+- return 0;
+-}
+-
+-int pri_call_add_standard_apdus(struct pri *pri, q931_call *call)
+-{
+- if (!pri->sendfacility)
+- return 0;
+-
+- if (pri->switchtype == PRI_SWITCH_QSIG) { /* For Q.SIG it does network and cpe operations */
+- if (call->redirectingnum[0])
+- rose_diverting_leg_information2_encode(pri, call);
+- add_callername_facility_ies(pri, call, 1);
+- return 0;
+- }
+-
+-#if 0
+- if (pri->localtype == PRI_NETWORK) {
+- switch (pri->switchtype) {
+- case PRI_SWITCH_NI2:
+- add_callername_facility_ies(pri, call, 0);
++ if (q931_party_id_cmp(&party_id, &call->remote_id)) {
++ /* The remote_id data has changed. */
++ call->remote_id = party_id;
++ switch (call->incoming_ct_state) {
++ case INCOMING_CT_STATE_IDLE:
++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE;
+ break;
+ default:
+ break;
++ }
+ }
+- return 0;
+- } else if (pri->localtype == PRI_CPE) {
+- switch (pri->switchtype) {
+- case PRI_SWITCH_NI2:
+- add_callername_facility_ies(pri, call, 1);
+- break;
+- default:
+- break;
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_SubaddressTransfer:
++ break;
++#endif /* Not handled yet */
++ case ROSE_QSIG_PathReplacement:
++ anfpr_pathreplacement_respond(ctrl, call, ie);
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_ActivateDiversionQ:
++ break;
++ case ROSE_QSIG_DeactivateDiversionQ:
++ break;
++ case ROSE_QSIG_InterrogateDiversionQ:
++ break;
++ case ROSE_QSIG_CheckRestriction:
++ break;
++#endif /* Not handled yet */
++ case ROSE_QSIG_CallRerouting:
++ if (!PRI_MASTER(ctrl)->deflection_support) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_NotSubscribed);
++ break;
+ }
+- return 0;
+- }
+-#else
+- if (pri->switchtype == PRI_SWITCH_NI2)
+- add_callername_facility_ies(pri, call, (pri->localtype == PRI_CPE));
+-#endif
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ send_facility_error(ctrl, call, invoke->invoke_id,
++ ROSE_ERROR_Gen_ResourceUnavailable);
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
+
+- if ((pri->switchtype == PRI_SWITCH_DMS100) && (pri->localtype == PRI_CPE)) {
+- add_dms100_transfer_ability_apdu(pri, call);
+- }
++ q931_party_redirecting_init(&deflection);
+
++ /* Rerouting from the last address. */
++ rose_copy_presented_number_unscreened_to_q931(ctrl, &deflection.from.number,
++ &invoke->args.qsig.CallRerouting.last_rerouting);
++ if (invoke->args.qsig.CallRerouting.redirecting_name_present) {
++ rose_copy_name_to_q931(ctrl, &deflection.from.name,
++ &invoke->args.qsig.CallRerouting.redirecting_name);
++ }
+
++ /* Rerouting to the new address. */
++ rose_copy_address_to_q931(ctrl, &deflection.to,
++ &invoke->args.qsig.CallRerouting.called);
++ switch (invoke->args.qsig.CallRerouting.subscription_option) {
++ default:
++ case 0: /* noNotification */
++ case 1: /* notificationWithoutDivertedToNr */
++ deflection.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ case 2: /* notificationWithDivertedToNr */
++ deflection.to.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ }
+
+- return 0;
++ /* Calling party update. */
++ party_id = call->local_id;
++ rose_copy_presented_number_screened_to_q931(ctrl, &party_id.number,
++ &invoke->args.qsig.CallRerouting.calling);
++ if (invoke->args.qsig.CallRerouting.calling_name_present) {
++ rose_copy_name_to_q931(ctrl, &party_id.name,
++ &invoke->args.qsig.CallRerouting.calling_name);
++ }
++
++ deflection.count = invoke->args.qsig.CallRerouting.diversion_counter;
++ deflection.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.CallRerouting.rerouting_reason);
++
++ /* Original called party update. */
++ if (deflection.count == 1) {
++ deflection.orig_called = deflection.from;
++ deflection.orig_reason = deflection.reason;
++ } else {
++ deflection.orig_called = call->redirecting.orig_called;
++ deflection.orig_reason = call->redirecting.orig_reason;
++ }
++ if (invoke->args.qsig.CallRerouting.original_called_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &deflection.orig_called.number,
++ &invoke->args.qsig.CallRerouting.original_called);
++ }
++ if (invoke->args.qsig.CallRerouting.original_called_name_present) {
++ rose_copy_name_to_q931(ctrl, &deflection.orig_called.name,
++ &invoke->args.qsig.CallRerouting.original_called_name);
++ }
++ if (invoke->args.qsig.CallRerouting.original_rerouting_reason_present) {
++ deflection.orig_reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.CallRerouting.original_rerouting_reason);
++ }
++
++ subcmd->cmd = PRI_SUBCMD_REROUTING;
++ subcmd->u.rerouting.invoke_id = invoke->invoke_id;
++ subcmd->u.rerouting.subscription_option =
++ invoke->args.qsig.CallRerouting.subscription_option;
++ q931_party_id_copy_to_pri(&subcmd->u.rerouting.caller, &party_id);
++ q931_party_redirecting_copy_to_pri(&subcmd->u.rerouting.deflection,
++ &deflection);
++ break;
++ case ROSE_QSIG_DivertingLegInformation1:
++ q931_party_number_init(&party_id.number);
++ rose_copy_number_to_q931(ctrl, &party_id.number,
++ &invoke->args.qsig.DivertingLegInformation1.nominated_number);
++ if (party_id.number.str[0]) {
++ party_id.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ }
++
++ /*
++ * Unless otherwise indicated by CONNECT, the nominatedNr will be
++ * the remote_id.number.
++ */
++ if (!call->connected_number_in_message) {
++ call->remote_id.number = party_id.number;
++ }
++
++ /* nominatedNr is put in redirecting.to.number */
++ switch (invoke->args.qsig.DivertingLegInformation1.subscription_option) {
++ default:
++ case QSIG_NO_NOTIFICATION:
++ case QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR:
++ q931_party_number_init(&call->redirecting.to.number);
++ call->redirecting.to.number.valid = 1;
++ call->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ break;
++ case QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR:
++ call->redirecting.to.number = party_id.number;
++ break;
++ }
++
++ call->redirecting.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.DivertingLegInformation1.diversion_reason);
++ if (call->redirecting.count < PRI_MAX_REDIRECTS) {
++ ++call->redirecting.count;
++ }
++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3;
++ break;
++ case ROSE_QSIG_DivertingLegInformation2:
++ call->redirecting.state = Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3;
++ call->redirecting.count =
++ invoke->args.qsig.DivertingLegInformation2.diversion_counter;
++ if (!call->redirecting.count) {
++ /* To be safe, make sure that the count is non-zero. */
++ call->redirecting.count = 1;
++ }
++ call->redirecting.reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.DivertingLegInformation2.diversion_reason);
++
++ /* divertingNr is put in redirecting.from.number */
++ if (invoke->args.qsig.DivertingLegInformation2.diverting_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->redirecting.from.number,
++ &invoke->args.qsig.DivertingLegInformation2.diverting);
++ } else if (!call->redirecting_number_in_message) {
++ q931_party_number_init(&call->redirecting.from.number);
++ call->redirecting.from.number.valid = 1;
++ }
++
++ /* redirectingName is put in redirecting.from.name */
++ if (invoke->args.qsig.DivertingLegInformation2.redirecting_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->redirecting.from.name,
++ &invoke->args.qsig.DivertingLegInformation2.redirecting_name);
++ } else {
++ q931_party_name_init(&call->redirecting.from.name);
++ }
++
++ call->redirecting.orig_reason = PRI_REDIR_UNKNOWN;
++ if (invoke->args.qsig.DivertingLegInformation2.original_diversion_reason_present) {
++ call->redirecting.orig_reason = redirectingreason_for_q931(ctrl,
++ invoke->args.qsig.DivertingLegInformation2.original_diversion_reason);
++ }
++
++ /* originalCalledNr is put in redirecting.orig_called.number */
++ if (invoke->args.qsig.DivertingLegInformation2.original_called_present) {
++ rose_copy_presented_number_unscreened_to_q931(ctrl,
++ &call->redirecting.orig_called.number,
++ &invoke->args.qsig.DivertingLegInformation2.original_called);
++ } else {
++ q931_party_number_init(&call->redirecting.orig_called.number);
++ }
++
++ /* originalCalledName is put in redirecting.orig_called.name */
++ if (invoke->args.qsig.DivertingLegInformation2.original_called_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->redirecting.orig_called.name,
++ &invoke->args.qsig.DivertingLegInformation2.original_called_name);
++ } else {
++ q931_party_name_init(&call->redirecting.orig_called.name);
++ }
++ break;
++ case ROSE_QSIG_DivertingLegInformation3:
++ /*
++ * Unless otherwise indicated by CONNECT, this will be the
++ * remote_id.number.presentation.
++ */
++ if (!invoke->args.qsig.DivertingLegInformation3.presentation_allowed_indicator) {
++ call->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ if (!call->connected_number_in_message) {
++ call->remote_id.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ }
++ }
++
++ /* redirectionName is put in redirecting.to.name */
++ if (invoke->args.qsig.DivertingLegInformation3.redirection_name_present) {
++ rose_copy_name_to_q931(ctrl, &call->redirecting.to.name,
++ &invoke->args.qsig.DivertingLegInformation3.redirection_name);
++ if (!invoke->args.qsig.DivertingLegInformation3.presentation_allowed_indicator) {
++ call->redirecting.to.name.presentation = PRI_PRES_RESTRICTED;
++ }
++ } else {
++ q931_party_name_init(&call->redirecting.to.name);
++ }
++
++ switch (call->redirecting.state) {
++ case Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3:
++ call->redirecting.state = Q931_REDIRECTING_STATE_IDLE;
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (!subcmd) {
++ pri_error(ctrl, "ERROR: Too many facility subcommands\n");
++ break;
++ }
++ /* Setup redirecting subcommand */
++ subcmd->cmd = PRI_SUBCMD_REDIRECTING;
++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting,
++ &call->redirecting);
++ break;
++ default:
++ break;
++ }
++ break;
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_CfnrDivertedLegFailed:
++ break;
++#endif /* Not handled yet */
++#if 0 /* Not handled yet */
++ case ROSE_QSIG_MWIActivate:
++ break;
++ case ROSE_QSIG_MWIDeactivate:
++ break;
++ case ROSE_QSIG_MWIInterrogate:
++ break;
++#endif /* Not handled yet */
++ default:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "!! ROSE invoke operation not handled! %s\n",
++ rose_operation2str(invoke->operation));
++ }
++ break;
++ }
+ }
+-
+Index: pri_facility.h
+===================================================================
+--- a/pri_facility.h (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_facility.h (.../branches/1.4) (revision 1357)
+@@ -31,123 +31,21 @@
+ #define _PRI_FACILITY_H
+ #include "pri_q931.h"
+
++/* Forward declare some structs */
++struct fac_extension_header;
++struct rose_msg_invoke;
++struct rose_msg_result;
++struct rose_msg_error;
++struct rose_msg_reject;
++
+ /* Protocol Profile field */
++#define Q932_PROTOCOL_MASK 0x1F
+ #define Q932_PROTOCOL_ROSE 0x11 /* X.219 & X.229 */
+ #define Q932_PROTOCOL_CMIP 0x12 /* Q.941 */
+ #define Q932_PROTOCOL_ACSE 0x13 /* X.217 & X.227 */
+ #define Q932_PROTOCOL_GAT 0x16
+ #define Q932_PROTOCOL_EXTENSIONS 0x1F
+
+-/* Argument values */
+-#define ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE 0x80
+-#define ROSE_NAME_PRESENTATION_RESTRICTED_NULL 0x87
+-#define ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED 0xA1
+-#define ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE 0xA2
+-#define ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED 0xA3
+-#define ROSE_NAME_NOT_AVAIL 0x84
+-
+-/* Component types */
+-#define COMP_TYPE_INTERPRETATION 0x8B
+-#define COMP_TYPE_NETWORK_PROTOCOL_PROFILE 0x92
+-#define COMP_TYPE_INVOKE 0xA1
+-#define COMP_TYPE_RETURN_RESULT 0xA2
+-#define COMP_TYPE_RETURN_ERROR 0xA3
+-#define COMP_TYPE_REJECT 0xA4
+-#define COMP_TYPE_NFE 0xAA
+-
+-/* Operation ID values */
+-/* Q.952.7 (ECMA-178) ROSE operations (Transfer) */
+-#define ROSE_CALL_TRANSFER_IDENTIFY 7
+-#define ROSE_CALL_TRANSFER_ABANDON 8
+-#define ROSE_CALL_TRANSFER_INITIATE 9
+-#define ROSE_CALL_TRANSFER_SETUP 10
+-#define ROSE_CALL_TRANSFER_ACTIVE 11
+-#define ROSE_CALL_TRANSFER_COMPLETE 12
+-#define ROSE_CALL_TRANSFER_UPDATE 13
+-#define ROSE_SUBADDRESS_TRANSFER 14
+-/* Q.952 ROSE operations (Diverting) */
+-#define ROSE_DIVERTING_LEG_INFORMATION1 18
+-#define ROSE_DIVERTING_LEG_INFORMATION2 0x15
+-#define ROSE_DIVERTING_LEG_INFORMATION3 19
+-/* Q.956 ROSE operations (Advice Of Charge) */
+-#define ROSE_AOC_NO_CHARGING_INFO_AVAILABLE 26
+-#define ROSE_AOC_CHARGING_REQUEST 30
+-#define ROSE_AOC_AOCS_CURRENCY 31
+-#define ROSE_AOC_AOCS_SPECIAL_ARR 32
+-#define ROSE_AOC_AOCD_CURRENCY 33
+-#define ROSE_AOC_AOCD_CHARGING_UNIT 34
+-#define ROSE_AOC_AOCE_CURRENCY 35
+-#define ROSE_AOC_AOCE_CHARGING_UNIT 36
+-#define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37
+-/* Q.SIG operations */
+-#define SS_CNID_CALLINGNAME 0
+-#define SS_ANFPR_PATHREPLACEMENT 4
+-#define SS_DIVERTING_LEG_INFORMATION2 21
+-#define SS_MWI_ACTIVATE 80
+-#define SS_MWI_DEACTIVATE 81
+-#define SS_MWI_INTERROGATE 82
+-
+-/* ROSE definitions and data structures */
+-#define INVOKE_IDENTIFIER 0x02
+-#define INVOKE_LINKED_IDENTIFIER 0x80
+-#define INVOKE_NULL_IDENTIFIER __USE_ASN1_NULL
+-
+-/* ASN.1 Identifier Octet - Data types */
+-#define ASN1_TYPE_MASK 0x1f
+-#define ASN1_BOOLEAN 0x01
+-#define ASN1_INTEGER 0x02
+-#define ASN1_BITSTRING 0x03
+-#define ASN1_OCTETSTRING 0x04
+-#define ASN1_NULL 0x05
+-#define ASN1_OBJECTIDENTIFIER 0x06
+-#define ASN1_OBJECTDESCRIPTOR 0x07
+-#define ASN1_EXTERN 0x08
+-#define ASN1_REAL 0x09
+-#define ASN1_ENUMERATED 0x0a
+-#define ASN1_EMBEDDEDPDV 0x0b
+-#define ASN1_UTF8STRING 0x0c
+-#define ASN1_RELATIVEOBJECTID 0x0d
+-/* 0x0e & 0x0f are reserved for future ASN.1 editions */
+-#define ASN1_SEQUENCE 0x10
+-#define ASN1_SET 0x11
+-#define ASN1_NUMERICSTRING 0x12
+-#define ASN1_PRINTABLESTRING 0x13
+-#define ASN1_TELETEXSTRING 0x14
+-#define ASN1_IA5STRING 0x16
+-#define ASN1_UTCTIME 0x17
+-#define ASN1_GENERALIZEDTIME 0x18
+-
+-/* ASN.1 Identifier Octet - Tags */
+-#define ASN1_TAG_0 0x00
+-#define ASN1_TAG_1 0x01
+-#define ASN1_TAG_2 0x02
+-#define ASN1_TAG_3 0x03
+-#define ASN1_TAG_4 0x04
+-#define ASN1_TAG_5 0x05
+-#define ASN1_TAG_6 0x06
+-#define ASN1_TAG_7 0x07
+-#define ASN1_TAG_8 0x08
+-#define ASN1_TAG_9 0x09
+-
+-/* ASN.1 Identifier Octet - Primitive/Constructor Bit */
+-#define ASN1_PC_MASK 0x20
+-#define ASN1_PRIMITIVE 0x00
+-#define ASN1_CONSTRUCTOR 0x20
+-
+-/* ASN.1 Identifier Octet - Clan Bits */
+-#define ASN1_CLAN_MASK 0xc0
+-#define ASN1_UNIVERSAL 0x00
+-#define ASN1_APPLICATION 0x40
+-#define ASN1_CONTEXT_SPECIFIC 0x80
+-#define ASN1_PRIVATE 0xc0
+-
+-/* ASN.1 Length masks */
+-#define ASN1_LEN_INDEF 0x80
+-
+-
+-#define INVOKE_OPERATION_INT __USE_ASN1_INTEGER
+-#define INVOKE_OBJECT_ID __USE_ASN1_OBJECTIDENTIFIER
+-
+ /* Q.952 Divert cause */
+ #define Q952_DIVERT_REASON_UNKNOWN 0x00
+ #define Q952_DIVERT_REASON_CFU 0x01
+@@ -169,138 +67,112 @@
+ #define Q932_TON_SUBSCRIBER 0x04
+ #define Q932_TON_ABBREVIATED 0x06
+
+-/* RLT related Operations */
+-#define RLT_SERVICE_ID 0x3e
+-#define RLT_OPERATION_IND 0x01
+-#define RLT_THIRD_PARTY 0x02
++/* Q.SIG Subscription Option. Listed in ECMA-174 */
++#define QSIG_NO_NOTIFICATION 0x00
++#define QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR 0x01
++#define QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR 0x02
+
+-struct rose_component {
+- u_int8_t type;
+- u_int8_t len;
+- u_int8_t data[0];
++/*! Reasons an APDU callback is called. */
++enum APDU_CALLBACK_REASON {
++ /*!
++ * \brief Send setup error. Abort and cleanup.
++ * \note The message may or may not actually get sent.
++ * \note The callback cannot generate an event subcmd.
++ * \note The callback should not send messages. Out of order messages will result.
++ */
++ APDU_CALLBACK_REASON_ERROR,
++ /*!
++ * \brief Abort and cleanup.
++ * \note The APDU queue is being destroyed.
++ * \note The callback cannot generate an event subcmd.
++ * \note The callback cannot send messages as the call is likely being destroyed.
++ */
++ APDU_CALLBACK_REASON_CLEANUP,
++ /*!
++ * \brief Timeout waiting for responses to the message.
++ * \note The callback can generate an event subcmd.
++ * \note The callback can send messages.
++ */
++ APDU_CALLBACK_REASON_TIMEOUT,
++ /*!
++ * \brief Received a facility response message.
++ * \note The callback can generate an event subcmd.
++ * \note The callback can send messages.
++ */
++ APDU_CALLBACK_REASON_MSG_RESULT,
++ /*!
++ * \brief Received a facility error message.
++ * \note The callback can generate an event subcmd.
++ * \note The callback can send messages.
++ */
++ APDU_CALLBACK_REASON_MSG_ERROR,
++ /*!
++ * \brief Received a facility reject message.
++ * \note The callback can generate an event subcmd.
++ * \note The callback can send messages.
++ */
++ APDU_CALLBACK_REASON_MSG_REJECT,
+ };
+
+-#if 1
+- #define GET_COMPONENT(component, idx, ptr, length) \
+- if ((idx)+2 > (length)) \
+- break; \
+- (component) = (struct rose_component*)&((ptr)[idx]); \
+- if ((idx)+(component)->len+2 > (length)) { \
+- if ((component)->len != ASN1_LEN_INDEF) \
+- pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \
+- }
+-#else /* Debugging */
+- #define GET_COMPONENT(component, idx, ptr, length) \
+- if ((idx)+2 > (length)) \
+- break; \
+- (component) = (struct rose_component*)&((ptr)[idx]); \
+- if ((idx)+(component)->len+2 > (length)) { \
+- if ((component)->len != 128) \
+- pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \
+- } \
+- pri_message(pri, "XX %s:%d Got component %d (0x%02X), length %d\n", __FUNCTION__, __LINE__, (component)->type, (component)->type, (component)->len); \
+- if ((component)->len > 0) { \
+- int zzz; \
+- pri_message(pri, "XX Data:"); \
+- for (zzz = 0; zzz < (component)->len; ++zzz) \
+- pri_message(pri, " %02X", (component)->data[zzz]); \
+- pri_message(pri, "\n"); \
+- }
+-#endif
++union apdu_msg_data {
++ const struct rose_msg_result *result;
++ const struct rose_msg_error *error;
++ const struct rose_msg_reject *reject;
++};
+
+-#define NEXT_COMPONENT(component, idx) \
+- (idx) += (component)->len + 2
++union apdu_callback_param {
++ void *ptr;
++ long value;
++ char pad[8];
++};
+
+-#define SUB_COMPONENT(component, idx) \
+- (idx) += 2
++struct apdu_callback_data {
++ /*! APDU invoke id to match with any response messages. (Result/Error/Reject) */
++ int invoke_id;
++ /*!
++ * \brief Time to wait for responses to APDU in ms.
++ * \note Set to 0 if send the message only.
++ * \note Set to less than 0 for PRI_TIMER_T_RESPONSE time.
++ */
++ int timeout_time;
++ /*!
++ * \brief APDU callback function.
++ *
++ * \param reason Reason callback is called.
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ * \param apdu APDU queued entry. Do not change!
++ * \param msg APDU response message data. (NULL if was not the reason called.)
++ *
++ * \note
++ * A callback must be supplied if the sender cares about any APDU_CALLBACK_REASON.
++ *
++ * \return TRUE if no more responses are expected.
++ */
++ int (*callback)(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const union apdu_msg_data *msg);
++ /*! \brief Sender data for the callback function to identify the particular APDU. */
++ union apdu_callback_param user;
++};
+
+-#define CHECK_COMPONENT(component, comptype, message) \
+- if ((component)->type && ((component)->type & ASN1_TYPE_MASK) != (comptype)) { \
+- pri_message(pri, (message), (component)->type); \
+- asn1_dump(pri, (component), (component)->len+2); \
+- break; \
+- }
+-
+-#define ASN1_GET_INTEGER(component, variable) \
+- do { \
+- int comp_idx; \
+- (variable) = 0; \
+- for (comp_idx = 0; comp_idx < (component)->len; ++comp_idx) \
+- (variable) = ((variable) << 8) | (component)->data[comp_idx]; \
+- } while (0)
++struct apdu_event {
++ /*! Linked list pointer */
++ struct apdu_event *next;
++ /*! TRUE if this APDU has been sent. */
++ int sent;
++ /*! What message to send the ADPU in */
++ int message;
++ /*! Sender supplied information to handle APDU response messages. */
++ struct apdu_callback_data response;
++ /*! Q.931 call leg. (Needed for the APDU timeout.) */
++ struct q931_call *call;
++ /*! Response timeout timer. */
++ int timer;
++ /*! Length of ADPU */
++ int apdu_len;
++ /*! ADPU to send */
++ unsigned char apdu[255];
++};
+
+-#define ASN1_FIXUP_LEN(component, size) \
+- do { \
+- if ((component)->len == ASN1_LEN_INDEF) \
+- size += 2; \
+- } while (0)
+-
+-#define ASN1_ADD_SIMPLE(component, comptype, ptr, idx) \
+- do { \
+- (component) = (struct rose_component *)&((ptr)[(idx)]); \
+- (component)->type = (comptype); \
+- (component)->len = 0; \
+- (idx) += 2; \
+- } while (0)
+-
+-#define ASN1_ADD_BYTECOMP(component, comptype, ptr, idx, value) \
+- do { \
+- (component) = (struct rose_component *)&((ptr)[(idx)]); \
+- (component)->type = (comptype); \
+- (component)->len = 1; \
+- (component)->data[0] = (value); \
+- (idx) += 3; \
+- } while (0)
+-
+-#define ASN1_ADD_WORDCOMP(component, comptype, ptr, idx, value) \
+- do { \
+- int __val = (value); \
+- int __i = 0; \
+- (component) = (struct rose_component *)&((ptr)[(idx)]); \
+- (component)->type = (comptype); \
+- if ((__val >> 24)) \
+- (component)->data[__i++] = (__val >> 24) & 0xff; \
+- if ((__val >> 16)) \
+- (component)->data[__i++] = (__val >> 16) & 0xff; \
+- if ((__val >> 8)) \
+- (component)->data[__i++] = (__val >> 8) & 0xff; \
+- (component)->data[__i++] = __val & 0xff; \
+- (component)->len = __i; \
+- (idx) += 2 + __i; \
+- } while (0)
+-
+-#define ASN1_PUSH(stack, stackpointer, component) \
+- (stack)[(stackpointer)++] = (component)
+-
+-#define ASN1_FIXUP(stack, stackpointer, data, idx) \
+- do { \
+- --(stackpointer); \
+- (stack)[(stackpointer)]->len = (unsigned char *)&((data)[(idx)]) - (unsigned char *)(stack)[(stackpointer)] - 2; \
+- } while (0)
+-
+-/* Decoder for the invoke ROSE component */
+-int rose_invoke_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
+-
+-/* Decoder for the return result ROSE component */
+-int rose_return_result_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
+-
+-/* Decoder for the return error ROSE component */
+-int rose_return_error_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
+-
+-/* Decoder for the reject ROSE component */
+-int rose_reject_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len);
+-
+-int asn1_copy_string(char * buf, int buflen, struct rose_component *comp);
+-
+-int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len);
+-
+-/* Get Name types from ASN.1 */
+-int asn1_name_decode(void * data, int len, char *namebuf, int buflen);
+-
+-int typeofnumber_from_q931(struct pri *pri, int ton);
+-
+-int redirectingreason_from_q931(struct pri *pri, int redirectingreason);
+-
+ /* Queues an MWI apdu on a the given call */
+ int mwi_message_send(struct pri *pri, q931_call *call, struct pri_sr *req, int activate);
+
+@@ -310,21 +182,31 @@
+ int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
+
+ int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason);
++int send_reroute_request(struct pri *ctrl, q931_call *call, const struct q931_party_id *caller, const struct q931_party_redirecting *deflection, int subscription_option);
+
+ /* starts a QSIG Path Replacement */
+ int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
+
+-/* Use this function to queue a facility-IE born APDU onto a call
+- * call is the call to use, messagetype is any one of the Q931 messages,
+- * apdu is the apdu data, apdu_len is the length of the apdu data */
+-int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_len, void (*function)(void *data), void *data);
++int send_call_transfer_complete(struct pri *pri, q931_call *call, int call_status);
+
+-/* Used by q931.c to cleanup the apdu queue upon destruction of a call */
+-int pri_call_apdu_queue_cleanup(q931_call *call);
++int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call);
++int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype);
+
++int rose_connected_name_encode(struct pri *pri, q931_call *call, int messagetype);
++int rose_called_name_encode(struct pri *pri, q931_call *call, int messagetype);
++
++int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response);
++void pri_call_apdu_queue_cleanup(q931_call *call);
++void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed);
++
+ /* Adds the "standard" APDUs to a call */
+ int pri_call_add_standard_apdus(struct pri *pri, q931_call *call);
+
+-int asn1_dump(struct pri *pri, void *comp, int len);
++void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1, const unsigned char *end);
+
++void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_invoke *invoke);
++void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_result *result);
++void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_error *error);
++void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_reject *reject);
++
+ #endif /* _PRI_FACILITY_H */
+Index: libpri.h
+===================================================================
+--- a/libpri.h (.../tags/1.4.10.2) (revision 1357)
++++ b/libpri.h (.../branches/1.4) (revision 1357)
+@@ -26,7 +26,14 @@
+ * provided with that copy of Asterisk, instead of the license
+ * terms granted here.
+ */
+-
++
++/*
++ * NOTE:
++ * All new global identifiers that are added to this file MUST be
++ * prefixed with PRI_ or pri_ to indicate that they are part of this
++ * library and to reduce potential naming conflicts.
++ */
++
+ #ifndef _LIBPRI_H
+ #define _LIBPRI_H
+
+@@ -73,7 +80,8 @@
+ #define PRI_EVENT_ANSWER 8 /* Call has been answered (CONNECT) */
+ #define PRI_EVENT_HANGUP_ACK 9 /* Call hangup has been acknowledged */
+ #define PRI_EVENT_RESTART_ACK 10 /* Restart complete on a given channel (RESTART_ACKNOWLEDGE) */
+-#define PRI_EVENT_FACNAME 11 /* Caller*ID Name received on Facility */
++#define PRI_EVENT_FACNAME 11 /* Caller*ID Name received on Facility (DEPRECATED) */
++#define PRI_EVENT_FACILITY 11 /* Facility received (FACILITY) */
+ #define PRI_EVENT_INFO_RECEIVED 12 /* Additional info (digits) received (INFORMATION) */
+ #define PRI_EVENT_PROCEEDING 13 /* When we get CALL_PROCEEDING */
+ #define PRI_EVENT_SETUP_ACK 14 /* When we get SETUP_ACKNOWLEDGE */
+@@ -81,6 +89,14 @@
+ #define PRI_EVENT_NOTIFY 16 /* Notification received (NOTIFY) */
+ #define PRI_EVENT_PROGRESS 17 /* When we get PROGRESS */
+ #define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state (INFORMATION) */
++#define PRI_EVENT_SERVICE 19 /* SERVICE maintenance message */
++#define PRI_EVENT_SERVICE_ACK 20 /* SERVICE maintenance acknowledgement message */
++#define PRI_EVENT_HOLD 21 /* HOLD request received */
++#define PRI_EVENT_HOLD_ACK 22 /* HOLD_ACKNOWLEDGE received */
++#define PRI_EVENT_HOLD_REJ 23 /* HOLD_REJECT received */
++#define PRI_EVENT_RETRIEVE 24 /* RETRIEVE request received */
++#define PRI_EVENT_RETRIEVE_ACK 25 /* RETRIEVE_ACKNOWLEDGE received */
++#define PRI_EVENT_RETRIEVE_REJ 26 /* RETRIEVE_REJECT received */
+
+ /* Simple states */
+ #define PRI_STATE_DOWN 0
+@@ -101,13 +117,13 @@
+ #define PRI_PROG_CALLER_RETURNED_TO_ISDN (1 << 9)
+
+ /* Numbering plan identifier */
+-#define PRI_NPI_UNKNOWN 0x0
+-#define PRI_NPI_E163_E164 0x1
+-#define PRI_NPI_X121 0x3
+-#define PRI_NPI_F69 0x4
+-#define PRI_NPI_NATIONAL 0x8
+-#define PRI_NPI_PRIVATE 0x9
+-#define PRI_NPI_RESERVED 0xF
++#define PRI_NPI_UNKNOWN 0x0 /*!< Unknown numbering plan */
++#define PRI_NPI_E163_E164 0x1 /*!< ISDN/telephony numbering plan (public) */
++#define PRI_NPI_X121 0x3 /*!< Data numbering plan */
++#define PRI_NPI_F69 0x4 /*!< Telex numbering plan */
++#define PRI_NPI_NATIONAL 0x8 /*!< National standard numbering plan */
++#define PRI_NPI_PRIVATE 0x9 /*!< Private numbering plan */
++#define PRI_NPI_RESERVED 0xF /*!< Reserved for extension */
+
+ /* Type of number */
+ #define PRI_TON_UNKNOWN 0x0
+@@ -135,16 +151,49 @@
+ #define PRI_UNKNOWN 0x0
+
+ /* Presentation */
+-#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00
+-#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01
+-#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02
+-#define PRES_ALLOWED_NETWORK_NUMBER 0x03
+-#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20
+-#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21
+-#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22
+-#define PRES_PROHIB_NETWORK_NUMBER 0x23
+-#define PRES_NUMBER_NOT_AVAILABLE 0x43
++#define PRI_PRES_NUMBER_TYPE 0x03
++#define PRI_PRES_USER_NUMBER_UNSCREENED 0x00
++#define PRI_PRES_USER_NUMBER_PASSED_SCREEN 0x01
++#define PRI_PRES_USER_NUMBER_FAILED_SCREEN 0x02
++#define PRI_PRES_NETWORK_NUMBER 0x03
+
++#define PRI_PRES_RESTRICTION 0x60
++#define PRI_PRES_ALLOWED 0x00
++#define PRI_PRES_RESTRICTED 0x20
++#define PRI_PRES_UNAVAILABLE 0x40
++#define PRI_PRES_RESERVED 0x60
++
++#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED \
++ (PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED)
++
++#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN \
++ (PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_PASSED_SCREEN)
++
++#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN \
++ (PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_FAILED_SCREEN)
++
++#define PRES_ALLOWED_NETWORK_NUMBER \
++ (PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER)
++
++#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED \
++ (PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED)
++
++#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN \
++ (PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_PASSED_SCREEN)
++
++#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN \
++ (PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_FAILED_SCREEN)
++
++#define PRES_PROHIB_NETWORK_NUMBER \
++ (PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER)
++
++#define PRES_NUMBER_NOT_AVAILABLE \
++ (PRI_PRES_UNAVAILABLE | PRI_PRES_NETWORK_NUMBER)
++
++/* Reverse Charging Indication */
++#define PRI_REVERSECHARGE_NONE -1
++#define PRI_REVERSECHARGE_REQUESTED 1
++
+ /* Causes for disconnection */
+ #define PRI_CAUSE_UNALLOCATED 1
+ #define PRI_CAUSE_NO_ROUTE_TRANSIT_NET 2 /* !Q.SIG */
+@@ -157,6 +206,7 @@
+ #define PRI_CAUSE_NO_ANSWER 19
+ #define PRI_CAUSE_CALL_REJECTED 21
+ #define PRI_CAUSE_NUMBER_CHANGED 22
++#define PRI_CAUSE_NONSELECTED_USER_CLEARING 26
+ #define PRI_CAUSE_DESTINATION_OUT_OF_ORDER 27
+ #define PRI_CAUSE_INVALID_NUMBER_FORMAT 28
+ #define PRI_CAUSE_FACILITY_REJECTED 29 /* !Q.SIG */
+@@ -169,6 +219,7 @@
+ #define PRI_CAUSE_ACCESS_INFO_DISCARDED 43 /* !Q.SIG */
+ #define PRI_CAUSE_REQUESTED_CHAN_UNAVAIL 44
+ #define PRI_CAUSE_PRE_EMPTED 45 /* !Q.SIG */
++#define PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED 47
+ #define PRI_CAUSE_FACILITY_NOT_SUBSCRIBED 50 /* !Q.SIG */
+ #define PRI_CAUSE_OUTGOING_CALL_BARRED 52 /* !Q.SIG */
+ #define PRI_CAUSE_INCOMING_CALL_BARRED 54 /* !Q.SIG */
+@@ -259,8 +310,8 @@
+ #define PRI_RATE_ADAPT_ASYNC 0x40
+
+ /* Notifications */
+-#define PRI_NOTIFY_USER_SUSPENDED 0x00 /* User suspended */
+-#define PRI_NOTIFY_USER_RESUMED 0x01 /* User resumed */
++#define PRI_NOTIFY_USER_SUSPENDED 0x00 /* User suspended (Q.931) (Call is placed on hold) */
++#define PRI_NOTIFY_USER_RESUMED 0x01 /* User resumed (Q.931) (Call is taken off hold) */
+ #define PRI_NOTIFY_BEARER_CHANGE 0x02 /* Bearer service change (DSS1) */
+ #define PRI_NOTIFY_ASN1_COMPONENT 0x03 /* ASN.1 encoded component (DSS1) */
+ #define PRI_NOTIFY_COMPLETION_DELAY 0x04 /* Call completion delay */
+@@ -275,12 +326,12 @@
+ #define PRI_NOTIFY_CONF_OTHER_DISCONNECTED 0x4a /* Other party disconnected */
+ #define PRI_NOTIFY_CONF_FLOATING 0x4b /* Conference floating */
+ #define PRI_NOTIFY_WAITING_CALL 0x60 /* Call is waiting call */
+-#define PRI_NOTIFY_DIVERSION_ACTIVATED 0x68 /* Diversion activated (DSS1) */
+-#define PRI_NOTIFY_TRANSFER_ALERTING 0x69 /* Call transfer, alerting */
+-#define PRI_NOTIFY_TRANSFER_ACTIVE 0x6a /* Call transfer, active */
++#define PRI_NOTIFY_DIVERSION_ACTIVATED 0x68 /* Diversion activated (DSS1) (cfu, cfb, cfnr) (EN 300 207-1 Section 7.2.1) */
++#define PRI_NOTIFY_TRANSFER_ALERTING 0x69 /* Call transfer, alerting (EN 300 369-1 Section 7.2) */
++#define PRI_NOTIFY_TRANSFER_ACTIVE 0x6a /* Call transfer, active(answered) (EN 300 369-1 Section 7.2) */
+ #define PRI_NOTIFY_REMOTE_HOLD 0x79 /* Remote hold */
+ #define PRI_NOTIFY_REMOTE_RETRIEVAL 0x7a /* Remote retrieval */
+-#define PRI_NOTIFY_CALL_DIVERTING 0x7b /* Call is diverting */
++#define PRI_NOTIFY_CALL_DIVERTING 0x7b /* Call is diverting (EN 300 207-1 Section 7.2.1) */
+
+ #define PRI_COPY_DIGITS_CALLED_NUMBER
+
+@@ -305,6 +356,200 @@
+
+ typedef struct q931_call q931_call;
+
++/* Name character set enumeration values */
++#define PRI_CHAR_SET_UNKNOWN 0
++#define PRI_CHAR_SET_ISO8859_1 1
++#define PRI_CHAR_SET_WITHDRAWN 2
++#define PRI_CHAR_SET_ISO8859_2 3
++#define PRI_CHAR_SET_ISO8859_3 4
++#define PRI_CHAR_SET_ISO8859_4 5
++#define PRI_CHAR_SET_ISO8859_5 6
++#define PRI_CHAR_SET_ISO8859_7 7
++#define PRI_CHAR_SET_ISO10646_BMPSTRING 8
++#define PRI_CHAR_SET_ISO10646_UTF_8STRING 9
++
++/*! \brief Q.SIG name information. */
++struct pri_party_name {
++ /*! \brief TRUE if the name information is valid/present */
++ int valid;
++ /*!
++ * \brief Q.931 presentation-indicator encoded field
++ * \note Must tollerate the Q.931 screening-indicator field values being present.
++ */
++ int presentation;
++ /*!
++ * \brief Character set the name is using.
++ * \details
++ * unknown(0),
++ * iso8859-1(1),
++ * enum-value-withdrawn-by-ITU-T(2)
++ * iso8859-2(3),
++ * iso8859-3(4),
++ * iso8859-4(5),
++ * iso8859-5(6),
++ * iso8859-7(7),
++ * iso10646-BmpString(8),
++ * iso10646-utf-8String(9)
++ * \details
++ * Set to iso8859-1(1) if unsure what to use.
++ */
++ int char_set;
++ /*! \brief Name data with null terminator. */
++ char str[64];
++};
++
++struct pri_party_number {
++ /*! \brief TRUE if the number information is valid/present */
++ int valid;
++ /*! \brief Q.931 presentation-indicator and screening-indicator encoded fields */
++ int presentation;
++ /*! \brief Q.931 Type-Of-Number and numbering-plan encoded fields */
++ int plan;
++ /*! \brief Number data with null terminator. */
++ char str[64];
++};
++
++/*!
++ * \note This structure is a place holder for possible future subaddress support
++ * to maintain ABI compatibility.
++ */
++struct pri_party_subaddress {
++ /*! \brief TRUE if the subaddress information is valid/present */
++ int valid;
++ /*!
++ * \brief Subaddress type.
++ * \details
++ * nsap(0),
++ * user_specified(2)
++ */
++ int type;
++ /*!
++ * \brief TRUE if odd number of address signals
++ * \note The odd/even indicator is used when the type of subaddress is
++ * user_specified and the coding is BCD.
++ */
++ int odd_even_indicator;
++ /*! \brief Length of the subaddress data */
++ int length;
++ /*!
++ * \brief Subaddress data with null terminator.
++ * \note The null terminator is a convenience only since the data could be
++ * BCD/binary and thus have a null byte as part of the contents.
++ */
++ unsigned char data[32];
++};
++
++/*! \brief Information needed to identify an endpoint in a call. */
++struct pri_party_id {
++ /*! \brief Subscriber name */
++ struct pri_party_name name;
++ /*! \brief Subscriber phone number */
++ struct pri_party_number number;
++ /*! \brief Subscriber subaddress */
++ struct pri_party_subaddress subaddress;
++};
++
++/*! \brief Connected Line/Party information */
++struct pri_party_connected_line {
++ /*! Connected party ID */
++ struct pri_party_id id;
++};
++
++/*!
++ * \brief Redirecting Line information.
++ * \details
++ * RDNIS (Redirecting Directory Number Information Service)
++ * Where a call diversion or transfer was invoked.
++ */
++struct pri_party_redirecting {
++ /*! Who is redirecting the call (Sent to the party the call is redirected toward) */
++ struct pri_party_id from;
++ /*! Call is redirecting to a new party (Sent to the caller) */
++ struct pri_party_id to;
++ /*! Originally called party (in cases of multiple redirects) */
++ struct pri_party_id orig_called;
++ /*! Number of times the call was redirected */
++ int count;
++ /*! Original reason for redirect (in cases of multiple redirects) */
++ int orig_reason;
++ /*! Redirection reason */
++ int reason;
++};
++
++/*!
++ * \brief Information for rerouting/deflecting the call.
++ */
++struct pri_rerouting_data {
++ /*!
++ * \brief Updated caller-id information.
++ * \note The information may have been altered by procedure in the private network.
++ */
++ struct pri_party_id caller;
++ /*!
++ * \note
++ * deflection.to is the new called number and must always be present.
++ */
++ struct pri_party_redirecting deflection;
++ /*!
++ * \brief Diverting user subscription option to specify if caller is notified.
++ * \details
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2),
++ * notApplicable(3) (Status only.)
++ */
++ int subscription_option;
++ /*! Invocation ID to use when sending a reply to the call rerouting/deflection request. */
++ int invoke_id;
++};
++
++/* Subcommands derived from supplementary services. */
++#define PRI_SUBCMD_REDIRECTING 1
++#define PRI_SUBCMD_CONNECTED_LINE 2
++#define PRI_SUBCMD_REROUTING 3
++
++
++struct pri_subcommand {
++ /*! PRI_SUBCMD_xxx defined values */
++ int cmd;
++ union {
++ /*! Reserve room for possible expansion to maintain ABI compatibility. */
++ char reserve_space[512];
++ struct pri_party_connected_line connected_line;
++ struct pri_party_redirecting redirecting;
++ struct pri_rerouting_data rerouting;
++ } u;
++};
++
++/* Max number of subcommands per event message */
++#define PRI_MAX_SUBCOMMANDS 8
++
++struct pri_subcommands {
++ int counter_subcmd;
++ struct pri_subcommand subcmd[PRI_MAX_SUBCOMMANDS];
++};
++
++
++/*
++ * Event channel parameter encoding:
++ * 3322 2222 2222 1111 1111 1100 0000 0000
++ * 1098 7654 3210 9876 5432 1098 7654 3210
++ * xxxx xxxx xxxx xEDC BBBBBBBBB AAAAAAAAA
++ *
++ * Bit field
++ * A - B channel
++ * B - Span (DS1) (0 - 127)
++ * C - DS1 Explicit bit
++ * D - D channel (cis_call) bit (status only)
++ * E - Call is held bit (status only)
++ *
++ * B channel values:
++ * 0 - No channel (ISDN uses for call waiting feature)
++ * 1-127 - B channel #
++ * 0xFF - Any channel (Also if whole channel value is -1 in event)
++ */
++
++
+ typedef struct pri_event_generic {
+ /* Events with no additional information fall in this category */
+ int e;
+@@ -328,6 +573,7 @@
+ int progressmask;
+ q931_call *call;
+ char useruserinfo[260]; /* User->User info */
++ struct pri_subcommands *subcmds;
+ } pri_event_ringing;
+
+ typedef struct pri_event_answer {
+@@ -338,8 +584,10 @@
+ int progressmask;
+ q931_call *call;
+ char useruserinfo[260]; /* User->User info */
++ struct pri_subcommands *subcmds;
+ } pri_event_answer;
+
++/*! Deprecated replaced by struct pri_event_facility. */
+ typedef struct pri_event_facname {
+ int e;
+ char callingname[256];
+@@ -351,6 +599,24 @@
+ int callingplan; /* Dialing plan of Calling entity */
+ } pri_event_facname;
+
++struct pri_event_facility {
++ int e;
++ char callingname[256]; /*!< Deprecated, preserved for struct pri_event_facname compatibility */
++ char callingnum[256]; /*!< Deprecated, preserved for struct pri_event_facname compatibility */
++ int channel;
++ int cref;
++ /*!
++ * \brief Master call or normal call.
++ * \note Call pointer known about by upper layer.
++ * \note NULL if dummy call reference.
++ */
++ q931_call *call;
++ int callingpres; /*!< Presentation of Calling CallerID (Deprecated, preserved for struct pri_event_facname compatibility) */
++ int callingplan; /*!< Dialing plan of Calling entity (Deprecated, preserved for struct pri_event_facname compatibility) */
++ struct pri_subcommands *subcmds;
++ q931_call *subcall; /*!< Subcall to send any reply toward. */
++};
++
+ #define PRI_CALLINGPLANANI
+ #define PRI_CALLINGPLANRDNIS
+ typedef struct pri_event_ring {
+@@ -376,13 +642,18 @@
+ int layer1; /* User layer 1 */
+ int complete; /* Have we seen "Complete" i.e. no more number? */
+ q931_call *call; /* Opaque call pointer */
+- char callingsubaddr[256]; /* Calling parties subaddress */
++ char callingsubaddr[256]; /* Calling parties subaddress, backwards compatibility */
+ int progress;
+ int progressmask;
+ char origcalledname[256];
+ char origcallednum[256];
+ int callingplanorigcalled; /* Dialing plan of Originally Called Number */
+ int origredirectingreason;
++ int reversecharge;
++ struct pri_subcommands *subcmds;
++ struct pri_party_id calling; /* Calling Party's info, initially subaddress' */
++ struct pri_party_subaddress called_subaddress; /* Called party's subaddress */
++ char keypad_digits[64]; /* Keypad digits in the SETUP message. */
+ } pri_event_ring;
+
+ typedef struct pri_event_hangup {
+@@ -390,10 +661,23 @@
+ int channel; /* Channel requested */
+ int cause;
+ int cref;
+- q931_call *call; /* Opaque call pointer */
++ q931_call *call; /* Opaque call pointer of call hanging up. */
+ long aoc_units; /* Advise of Charge number of charged units */
+ char useruserinfo[260]; /* User->User info */
+-} pri_event_hangup;
++ struct pri_subcommands *subcmds;
++ /*!
++ * \brief Opaque held call pointer for possible transfer to active call.
++ * \note The call_held and call_active pointers must not be NULL if
++ * transfer held call on disconnect is available.
++ */
++ q931_call *call_held;
++ /*!
++ * \brief Opaque active call pointer for possible transfer with held call.
++ * \note The call_held and call_active pointers must not be NULL if
++ * transfer held call on disconnect is available.
++ */
++ q931_call *call_active;
++} pri_event_hangup;
+
+ typedef struct pri_event_restart_ack {
+ int e;
+@@ -409,18 +693,22 @@
+ int progressmask;
+ int cause;
+ q931_call *call;
++ struct pri_subcommands *subcmds;
+ } pri_event_proceeding;
+-
++
+ typedef struct pri_event_setup_ack {
+ int e;
+ int channel;
+ q931_call *call;
++ struct pri_subcommands *subcmds;
+ } pri_event_setup_ack;
+
+ typedef struct pri_event_notify {
+ int e;
+ int channel;
+ int info;
++ struct pri_subcommands *subcmds;
++ q931_call *call;
+ } pri_event_notify;
+
+ typedef struct pri_event_keypad_digit {
+@@ -428,14 +716,72 @@
+ int channel;
+ q931_call *call;
+ char digits[64];
++ struct pri_subcommands *subcmds;
+ } pri_event_keypad_digit;
+
++typedef struct pri_event_service {
++ int e;
++ int channel;
++ int changestatus;
++} pri_event_service;
++
++typedef struct pri_event_service_ack {
++ int e;
++ int channel;
++ int changestatus;
++} pri_event_service_ack;
++
++struct pri_event_hold {
++ int e;
++ int channel;
++ q931_call *call;
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_hold_ack {
++ int e;
++ int channel;
++ q931_call *call;
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_hold_rej {
++ int e;
++ int channel;
++ q931_call *call;
++ int cause;
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_retrieve {
++ int e;
++ int channel;
++ q931_call *call;
++ int flexible; /* Are we flexible with our channel selection? */
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_retrieve_ack {
++ int e;
++ int channel;
++ q931_call *call;
++ struct pri_subcommands *subcmds;
++};
++
++struct pri_event_retrieve_rej {
++ int e;
++ int channel;
++ q931_call *call;
++ int cause;
++ struct pri_subcommands *subcmds;
++};
++
+ typedef union {
+ int e;
+ pri_event_generic gen; /* Generic view */
+ pri_event_restart restart; /* Restart view */
+ pri_event_error err; /* Error view */
+- pri_event_facname facname; /* Caller*ID Name on Facility */
++ pri_event_facname facname; /* Caller*ID Name on Facility (Deprecated, use pri_event.facility) */
+ pri_event_ring ring; /* Ring */
+ pri_event_hangup hangup; /* Hang up */
+ pri_event_ringing ringing; /* Ringing */
+@@ -445,6 +791,15 @@
+ pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */
+ pri_event_notify notify; /* Notification */
+ pri_event_keypad_digit digit; /* Digits that come during a call */
++ pri_event_service service; /* service message */
++ pri_event_service_ack service_ack; /* service acknowledgement message */
++ struct pri_event_facility facility;
++ struct pri_event_hold hold;
++ struct pri_event_hold_ack hold_ack;
++ struct pri_event_hold_rej hold_rej;
++ struct pri_event_retrieve retrieve;
++ struct pri_event_retrieve_ack retrieve_ack;
++ struct pri_event_retrieve_rej retrieve_rej;
+ } pri_event;
+
+ struct pri;
+@@ -456,7 +811,7 @@
+
+ /* Create a D-channel on a given file descriptor. The file descriptor must be a
+ channel operating in HDLC mode with FCS computed by the fd's driver. Also it
+- must be NON-BLOCKING! Frames received on the fd should include FCS. Nodetype
++ must be NON-BLOCKING! Frames received on the fd should include FCS. Nodetype
+ must be one of PRI_NETWORK or PRI_CPE. switchtype should be PRI_SWITCH_* */
+ struct pri *pri_new(int fd, int nodetype, int switchtype);
+ struct pri *pri_new_bri(int fd, int ptpmode, int nodetype, int switchtype);
+@@ -521,7 +876,7 @@
+
+ #define PRI_KEYPAD_FACILITY_TX
+ /* Send a keypad facility string of digits */
+-int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits);
++int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits);
+
+ /* Answer the incomplete(call without called number) call on the given channel.
+ Set non-isdn to non-zero if you are not connecting to ISDN equipment */
+@@ -531,6 +886,18 @@
+ Set non-isdn to non-zero if you are not connecting to ISDN equipment */
+ int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
+
++/*!
++ * \brief Give connected line information to a call
++ * \note Could be used instead of pri_sr_set_caller_party() before calling pri_setup().
++ */
++int pri_connected_line_update(struct pri *pri, q931_call *call, const struct pri_party_connected_line *connected);
++
++/*!
++ * \brief Give redirection information to a call
++ * \note Could be used instead of pri_sr_set_redirecting_parties() before calling pri_setup().
++ */
++int pri_redirecting_update(struct pri *pri, q931_call *call, const struct pri_party_redirecting *redirecting);
++
+ /* Set CRV reference for GR-303 calls */
+
+
+@@ -556,9 +923,20 @@
+
+ int pri_reset(struct pri *pri, int channel);
+
++/* handle b-channel maintenance messages */
++extern int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus);
++
+ /* Create a new call */
+ q931_call *pri_new_call(struct pri *pri);
+
++/*!
++ * \brief Deterimine if the given call control pointer is a dummy call.
++ *
++ * \retval TRUE if given call is a dummy call.
++ * \retval FALSE otherwise.
++ */
++int pri_is_dummy_call(q931_call *call);
++
+ /* Retrieve CRV reference for GR-303 calls. Returns >0 on success. */
+ int pri_get_crv(struct pri *pri, q931_call *call, int *callmode);
+
+@@ -573,8 +951,8 @@
+ extern pri_event *pri_schedule_run_tv(struct pri *pri, const struct timeval *now);
+
+ int pri_call(struct pri *pri, q931_call *c, int transmode, int channel,
+- int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres,
+- char *called,int calledplan, int ulayer1);
++ int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres,
++ char *called, int calledplan, int ulayer1);
+
+ struct pri_sr *pri_sr_new(void);
+ void pri_sr_free(struct pri_sr *sr);
+@@ -582,25 +960,91 @@
+ int pri_sr_set_channel(struct pri_sr *sr, int channel, int exclusive, int nonisdn);
+ int pri_sr_set_bearer(struct pri_sr *sr, int transmode, int userl1);
+ int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int complete);
++
++/*!
++ * \brief Set the caller party ID information in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param caller Caller party ID information to set.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_caller_party(struct pri_sr *sr, const struct pri_party_id *caller);
++/*! \note Use pri_sr_set_caller_party() instead to pass more precise caller information. */
+ int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres);
++
++/*!
++ * \brief Set the calling subaddress information in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param subaddress information to set.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_caller_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress);
++
++/*!
++ * \brief Set the called subaddress information in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param subaddress information to set.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_called_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress);
++
++/*!
++ * \brief Set the redirecting information in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param caller Redirecting information to set.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_redirecting_parties(struct pri_sr *sr, const struct pri_party_redirecting *redirecting);
++/*! \note Use pri_sr_set_redirecting_parties() instead to pass more precise redirecting information. */
+ int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason);
++
++/*!
++ * \brief Set the keypad digits in the call SETUP record.
++ *
++ * \param sr New call SETUP record.
++ * \param keypad_digits Keypad digits to send.
++ *
++ * \return Nothing
++ */
++void pri_sr_set_keypad_digits(struct pri_sr *sr, const char *keypad_digits);
++
+ #define PRI_USER_USER_TX
+ /* Set the user user field. Warning! don't send binary data accross this field */
+ void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars);
++void pri_sr_set_reversecharge(struct pri_sr *sr, int requested);
+
+ void pri_call_set_useruser(q931_call *sr, const char *userchars);
+
+ int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req);
+
+-/* Set a call has a call indpendent signalling connection (i.e. no bchan) */
++/*!
++ * \brief Set a call as a call indpendent signalling connection (i.e. no bchan)
++ * \note Call will automaticlly disconnect after signalling sent.
++ */
+ int pri_sr_set_connection_call_independent(struct pri_sr *req);
+
++/*!
++ * \brief Set a call as a call indpendent signalling connection (i.e. no bchan)
++ * \note Call will stay connected until explicitly disconnected.
++ */
++int pri_sr_set_no_channel_call(struct pri_sr *req);
++
+ /* Send an MWI indication to a remote location. If activate is non zero, activates, if zero, deactivates */
+ int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan);
+
+ /* Send an MWI deactivate request to a remote location */
+ int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan);
+
++/* Set service message support flag */
++int pri_set_service_message_support(struct pri *pri, int supportflag);
++
+ #define PRI_2BCT
+ /* Attempt to pass the channels back to the NET side if compatable and
+ * suscribed. Sometimes called 2 bchannel transfer (2BCT) */
+@@ -656,48 +1100,208 @@
+
+ int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason);
+
++/*!
++ * \brief Set the call deflection/rerouting feature enable flag.
++ *
++ * \param ctrl D channel controller.
++ * \param enable TRUE to enable call deflection/rerouting feature.
++ *
++ * \return Nothing
++ */
++void pri_reroute_enable(struct pri *ctrl, int enable);
++
++/*!
++ * \brief Send the CallRerouting/CallDeflection message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ * \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.)
++ * \param deflection Call rerouting/deflecting redirection data.
++ * \param subscription_option Diverting user subscription option to specify if caller is notified.
++ *
++ * \note
++ * deflection->to is the new called number and must always be present.
++ * \note
++ * subscription option:
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_reroute_call(struct pri *ctrl, q931_call *call, const struct pri_party_id *caller, const struct pri_party_redirecting *deflection, int subscription_option);
++
++enum PRI_REROUTING_RSP_CODE {
++ /*!
++ * Rerouting invocation accepted and the network provider option
++ * "served user call retention on invocation of diversion"
++ * is "clear call on invocation".
++ */
++ PRI_REROUTING_RSP_OK_CLEAR,
++ /*!
++ * Rerouting invocation accepted and the network provider option
++ * "served user call retention on invocation of diversion"
++ * is "retain call until alerting begins at the deflected-to user".
++ */
++ PRI_REROUTING_RSP_OK_RETAIN,
++ PRI_REROUTING_RSP_NOT_SUBSCRIBED,
++ PRI_REROUTING_RSP_NOT_AVAILABLE,
++ /*! Supplementary service interaction not allowed. */
++ PRI_REROUTING_RSP_NOT_ALLOWED,
++ PRI_REROUTING_RSP_INVALID_NUMBER,
++ /*! Deflection to prohibited number (e.g., operator, police, emergency). */
++ PRI_REROUTING_RSP_SPECIAL_SERVICE_NUMBER,
++ /*! Deflection to served user number. */
++ PRI_REROUTING_RSP_DIVERSION_TO_SELF,
++ PRI_REROUTING_RSP_MAX_DIVERSIONS_EXCEEDED,
++ PRI_REROUTING_RSP_RESOURCE_UNAVAILABLE,
++};
++
++/*!
++ * \brief Send the CallRerouteing/CallDeflection response message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ * \param invoke_id Value given by the initiating request.
++ * \param code The result to send.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI_REROUTING_RSP_CODE code);
++
++/*!
++ * \brief Set the call hold feature enable flag.
++ *
++ * \param ctrl D channel controller.
++ * \param enable TRUE to enable call hold feature.
++ *
++ * \return Nothing
++ */
++void pri_hold_enable(struct pri *ctrl, int enable);
++
++/*!
++ * \brief Send the HOLD message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_hold(struct pri *ctrl, q931_call *call);
++
++/*!
++ * \brief Send the HOLD ACKNOWLEDGE message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_hold_ack(struct pri *ctrl, q931_call *call);
++
++/*!
++ * \brief Send the HOLD REJECT message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param cause Q.931 cause code for rejecting the hold request.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause);
++
++/*!
++ * \brief Send the RETRIEVE message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param channel Encoded channel id to use. If zero do not send channel id.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_retrieve(struct pri *ctrl, q931_call *call, int channel);
++
++/*!
++ * \brief Send the RETRIEVE ACKNOWLEDGE message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param channel Encoded channel id to use.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel);
++
++/*!
++ * \brief Send the RETRIEVE REJECT message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param cause Q.931 cause code for rejecting the retrieve request.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause);
++
+ /* Get/Set PRI Timers */
+ #define PRI_GETSET_TIMERS
+ int pri_set_timer(struct pri *pri, int timer, int value);
+ int pri_get_timer(struct pri *pri, int timer);
+-int pri_timer2idx(char *timer);
++int pri_timer2idx(const char *timer_name);
+
+-#define PRI_MAX_TIMERS 32
++/*! New configurable timers and counters must be added to the end of the list */
++enum PRI_TIMERS_AND_COUNTERS {
++ PRI_TIMER_N200, /*!< Maximum numer of Q.921 retransmissions */
++ PRI_TIMER_N201, /*!< Maximum numer of octets in an information field */
++ PRI_TIMER_N202, /*!< Maximum numer of transmissions of the TEI identity request message */
++ PRI_TIMER_K, /*!< Maximum number of outstanding I-frames */
+
+-#define PRI_TIMER_N200 0 /* Maximum numer of q921 retransmissions */
+-#define PRI_TIMER_N201 1 /* Maximum numer of octets in an information field */
+-#define PRI_TIMER_N202 2 /* Maximum numer of transmissions of the TEI identity request message */
+-#define PRI_TIMER_K 3 /* Maximum number of outstanding I-frames */
++ PRI_TIMER_T200, /*!< Time between SABME's */
++ PRI_TIMER_T201, /*!< Minimum time between retransmissions of the TEI Identity check messages */
++ PRI_TIMER_T202, /*!< Minimum time between transmission of TEI Identity request messages */
++ PRI_TIMER_T203, /*!< Maximum time without exchanging packets */
+
+-#define PRI_TIMER_T200 4 /* time between SABME's */
+-#define PRI_TIMER_T201 5 /* minimum time between retransmissions of the TEI Identity check messages */
+-#define PRI_TIMER_T202 6 /* minimum time between transmission of TEI Identity request messages */
+-#define PRI_TIMER_T203 7 /* maxiumum time without exchanging packets */
++ PRI_TIMER_T300,
++ PRI_TIMER_T301, /*!< Maximum time to respond to an ALERT */
++ PRI_TIMER_T302,
++ PRI_TIMER_T303, /*!< Maximum time to wait after sending a SETUP without a response */
++ PRI_TIMER_T304,
++ PRI_TIMER_T305, /*!< Wait for DISCONNECT acknowledge */
++ PRI_TIMER_T306,
++ PRI_TIMER_T307,
++ PRI_TIMER_T308, /*!< Wait for RELEASE acknowledge */
++ PRI_TIMER_T309, /*!< Time active calls can tollerate data link layer being down before clearing. */
++ PRI_TIMER_T310, /*!< Maximum time between receiving a CALL_PROCEEDING and receiving a ALERT/CONNECT/DISCONNECT/PROGRESS */
++ PRI_TIMER_T313, /*!< Wait for CONNECT acknowledge, CPE side only */
++ PRI_TIMER_T314,
++ PRI_TIMER_T316, /*!< Maximum time between transmitting a RESTART and receiving a RESTART ACK */
++ PRI_TIMER_T317,
++ PRI_TIMER_T318,
++ PRI_TIMER_T319,
++ PRI_TIMER_T320,
++ PRI_TIMER_T321,
++ PRI_TIMER_T322,
+
+-#define PRI_TIMER_T300 8
+-#define PRI_TIMER_T301 9 /* maximum time to respond to an ALERT */
+-#define PRI_TIMER_T302 10
+-#define PRI_TIMER_T303 11 /* maximum time to wait after sending a SETUP without a response */
+-#define PRI_TIMER_T304 12
+-#define PRI_TIMER_T305 13
+-#define PRI_TIMER_T306 14
+-#define PRI_TIMER_T307 15
+-#define PRI_TIMER_T308 16
+-#define PRI_TIMER_T309 17
+-#define PRI_TIMER_T310 18 /* maximum time between receiving a CALLPROCEEDING and receiving a ALERT/CONNECT/DISCONNECT/PROGRESS */
+-#define PRI_TIMER_T313 19
+-#define PRI_TIMER_T314 20
+-#define PRI_TIMER_T316 21 /* maximum time between transmitting a RESTART and receiving a RESTART ACK */
+-#define PRI_TIMER_T317 22
+-#define PRI_TIMER_T318 23
+-#define PRI_TIMER_T319 24
+-#define PRI_TIMER_T320 25
+-#define PRI_TIMER_T321 26
+-#define PRI_TIMER_T322 27
++ PRI_TIMER_TM20, /*!< Maximum time awaiting XID response */
++ PRI_TIMER_NM20, /*!< Number of XID retransmits */
+
+-#define PRI_TIMER_TM20 28 /* maximum time avaiting XID response */
+-#define PRI_TIMER_NM20 29 /* number of XID retransmits */
++ PRI_TIMER_T_HOLD, /*!< Maximum time to wait for HOLD request response. */
++ PRI_TIMER_T_RETRIEVE, /*!< Maximum time to wait for RETRIEVE request response. */
+
++ PRI_TIMER_T_RESPONSE, /*!< Maximum time to wait for a typical APDU response. */
++
++ /* Must be last in the enum list */
++ PRI_MAX_TIMERS
++};
++
+ /* Get PRI version */
+ const char *pri_get_version(void);
+
+Index: asn1_primitive.c
+===================================================================
+--- a/asn1_primitive.c (.../tags/1.4.10.2) (revision 0)
++++ b/asn1_primitive.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,1306 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief ASN.1 BER encode/decode primitives
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include <stdio.h>
++#include <ctype.h>
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "asn1.h"
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Dump the memory contents indicated in printable characters. (Helper function.)
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param start Dump memory starting position.
++ * \param end Dump memory ending position. (Not included in dump.)
++ *
++ * \return Nothing
++ */
++static void asn1_dump_mem_helper(struct pri *ctrl, const unsigned char *start,
++ const unsigned char *end)
++{
++ pri_message(ctrl, " - \"");
++ for (; start < end; ++start) {
++ pri_message(ctrl, "%c", (isprint(*start)) ? *start : '~');
++ }
++ pri_message(ctrl, "\"\n");
++}
++
++/*!
++ * \internal
++ * \brief Dump the memory contents indicated.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param indent Number of spaces to indent for each new memory dump line.
++ * \param pos Dump memory starting position.
++ * \param length Number of bytes to dump.
++ *
++ * \return Nothing
++ */
++static void asn1_dump_mem(struct pri *ctrl, unsigned indent, const unsigned char *pos,
++ unsigned length)
++{
++ const unsigned char *seg_start;
++ const unsigned char *end;
++ unsigned delimiter;
++ unsigned count;
++
++ seg_start = pos;
++ end = pos + length;
++ if (pos < end) {
++ delimiter = '<';
++ for (;;) {
++ pri_message(ctrl, "%*s", indent, "");
++ for (count = 0; count++ < 16 && pos < end;) {
++ pri_message(ctrl, "%c%02X", delimiter, *pos++);
++ delimiter = (count == 8) ? '-' : ' ';
++ }
++ if (end <= pos) {
++ break;
++ }
++ asn1_dump_mem_helper(ctrl, seg_start, pos);
++ seg_start = pos;
++ }
++ } else {
++ pri_message(ctrl, "%*s<", indent, "");
++ }
++ pri_message(ctrl, ">");
++ asn1_dump_mem_helper(ctrl, seg_start, end);
++}
++
++/*!
++ * \brief Convert the given tag value to a descriptive string.
++ *
++ * \param tag Component tag value to convert to a string.
++ *
++ * \return Converted tag string.
++ */
++const char *asn1_tag2str(unsigned tag)
++{
++ static const char *primitives[32] = {
++ [ASN1_TYPE_INDEF_TERM] = "Indefinite length terminator",
++ [ASN1_TYPE_BOOLEAN] = "Boolean",
++ [ASN1_TYPE_INTEGER] = "Integer",
++ [ASN1_TYPE_BIT_STRING] = "Bit String",
++ [ASN1_TYPE_OCTET_STRING] = "Octet String",
++ [ASN1_TYPE_NULL] = "NULL",
++ [ASN1_TYPE_OBJECT_IDENTIFIER] = "OID",
++ [ASN1_TYPE_OBJECT_DESCRIPTOR] = "Object Descriptor",
++ [ASN1_TYPE_EXTERN] = "External",
++ [ASN1_TYPE_REAL] = "Real",
++ [ASN1_TYPE_ENUMERATED] = "Enumerated",
++ [ASN1_TYPE_EMBEDDED_PDV] = "Embedded PDV",
++ [ASN1_TYPE_UTF8_STRING] = "UTF8 String",
++ [ASN1_TYPE_RELATIVE_OID] = "Relative OID",
++ [ASN1_TYPE_SEQUENCE] = "Sequence",
++ [ASN1_TYPE_SET] = "Set",
++ [ASN1_TYPE_NUMERIC_STRING] = "Numeric String",
++ [ASN1_TYPE_PRINTABLE_STRING] = "Printable String",
++ [ASN1_TYPE_TELETEX_STRING] = "Teletex String",
++ [ASN1_TYPE_VIDEOTEX_STRING] = "Videotex String",
++ [ASN1_TYPE_IA5_STRING] = "IA5 String",
++ [ASN1_TYPE_UTC_TIME] = "UTC Time",
++ [ASN1_TYPE_GENERALIZED_TIME] = "Generalized Time",
++ [ASN1_TYPE_GRAPHIC_STRING] = "Graphic String",
++ [ASN1_TYPE_VISIBLE_STRING] = "Visible/ISO646 String",
++ [ASN1_TYPE_GENERAL_STRING] = "General String",
++ [ASN1_TYPE_UNIVERSAL_STRING] = "Universal String",
++ [ASN1_TYPE_CHAR_STRING] = "Character String",
++ [ASN1_TYPE_BMP_STRING] = "BMP String",
++ [ASN1_TYPE_EXTENSION] = "Type Extension",
++ };
++ static char buf[64];
++ const char *description;
++ unsigned asn1_constructed; /*! TRUE if the tag is constructed. */
++ unsigned asn1_type;
++
++ asn1_constructed = ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED);
++ asn1_type = tag & ASN1_TYPE_MASK;
++
++ switch (tag & ASN1_CLASS_MASK) {
++ case ASN1_CLASS_UNIVERSAL:
++ if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_INDEF_TERM)) {
++ description = NULL;
++ } else {
++ description = primitives[asn1_type];
++ }
++ if (!description) {
++ description = "Reserved";
++ }
++ snprintf(buf, sizeof(buf), "%s%s(%u 0x%02X)", description,
++ asn1_constructed ? "/C" : "", tag, tag);
++ return buf;
++ case ASN1_CLASS_APPLICATION:
++ description = "Application";
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC:
++ description = "Context Specific";
++ break;
++ case ASN1_CLASS_PRIVATE:
++ description = "Private";
++ break;
++ default:
++ snprintf(buf, sizeof(buf), "Unknown tag (%u 0x%02X)", tag, tag);
++ return buf;
++ }
++ snprintf(buf, sizeof(buf), "%s%s [%u 0x%02X]", description,
++ asn1_constructed ? "/C" : "", asn1_type, asn1_type);
++ return buf;
++}
++
++/*!
++ * \brief Decode the ASN.1 tag value.
++ *
++ * \param tag_pos ASN.1 tag starting position.
++ * \param end End of ASN.1 encoded data buffer.
++ * \param tag Decoded tag value returned on success.
++ *
++ * \retval Next octet after the tag on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_tag(const unsigned char *tag_pos, const unsigned char *end,
++ unsigned *tag)
++{
++ unsigned extended_tag;
++
++ if (end <= tag_pos) {
++ return NULL;
++ }
++ *tag = *tag_pos++;
++ if ((*tag & ASN1_TYPE_MASK) == ASN1_TYPE_EXTENSION) {
++ /* Extract the extended tag value */
++ extended_tag = 0;
++ do {
++ if (end <= tag_pos) {
++ return NULL;
++ }
++ extended_tag <<= 7;
++ extended_tag |= *tag_pos & ~0x80;
++ } while (*tag_pos++ & 0x80);
++ if (extended_tag && extended_tag < ASN1_TYPE_EXTENSION) {
++ /*
++ * The sender did not need to use the extended format.
++ * This is an encoding error on their part, but we will
++ * accept it anyway.
++ *
++ * Note we cannot return a null tag value from this path.
++ * We would misinterpret the indefinite length
++ * terminator.
++ */
++ *tag &= ~ASN1_TYPE_MASK;
++ *tag |= extended_tag;
++ }
++ }
++
++ return tag_pos;
++}
++
++/*!
++ * \brief Decode the length of an ASN.1 component length.
++ *
++ * \param len_pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param length Decoded length value returned on success. (-1 if indefinite)
++ *
++ * \retval Next octet after the length on success.
++ * \retval NULL on error.
++ *
++ * \note The decoded length is checked to see if there is enough buffer
++ * left for the component body.
++ */
++const unsigned char *asn1_dec_length(const unsigned char *len_pos,
++ const unsigned char *end, int *length)
++{
++ unsigned length_size;
++
++ if (end <= len_pos) {
++ /* Not enough buffer to determine how the length is encoded */
++ return NULL;
++ }
++
++ if (*len_pos < 0x80) {
++ /* Short length encoding */
++ *length = *len_pos++;
++ } else if (*len_pos == 0x80) {
++ /* Indefinite length encoding */
++ *length = -1;
++ ++len_pos;
++ if (end < len_pos + ASN1_INDEF_TERM_LEN) {
++ /* Not enough buffer for the indefinite length terminator */
++ return NULL;
++ }
++ return len_pos;
++ } else {
++ /* Long length encoding */
++ length_size = *len_pos++ & 0x7f;
++ if (length_size == 0x7f) {
++ /* Reserved extension encoding that has not been defined. */
++ return NULL;
++ }
++ if (end < len_pos + length_size) {
++ /* Not enough buffer for the length value */
++ return NULL;
++ }
++ *length = 0;
++ while (length_size--) {
++ *length = (*length << 8) | *len_pos++;
++ }
++ }
++
++ if (end < len_pos + *length) {
++ /* Not enough buffer for the component body. */
++ return NULL;
++ }
++ return len_pos;
++}
++
++/*!
++ * \internal
++ * \brief Skip to the end of an indefinite length constructed component helper.
++ *
++ * \param pos ASN.1 tag starting position.
++ * \param end End of ASN.1 decoding data buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *asn1_dec_indef_end_fixup_helper(const unsigned char *pos,
++ const unsigned char *end)
++{
++ unsigned tag;
++ int length;
++
++ while (pos < end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag));
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length < 0) {
++ /* Skip over indefinite length sub-component */
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED
++ || tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET)
++ || tag ==
++ (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) {
++ /* This is an ITU encoded indefinite length component. */
++ ASN1_CALL(pos, asn1_dec_indef_end_fixup_helper(pos, end));
++ } else {
++ /* This is a non-ITU encoded indefinite length component. */
++ while (pos < end && *pos != ASN1_INDEF_TERM) {
++ ++pos;
++ }
++ pos += ASN1_INDEF_TERM_LEN;
++ }
++ } else {
++ /* Skip over defininte length sub-component */
++ pos += length;
++ }
++ }
++ if (end < pos + ASN1_INDEF_TERM_LEN) {
++ return NULL;
++ }
++
++ return pos + ASN1_INDEF_TERM_LEN;
++}
++
++/*!
++ * \brief Skip to the end of an indefinite length constructed component.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param pos ASN.1 tag starting position.
++ * \param end End of ASN.1 decoding data buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_indef_end_fixup(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end)
++{
++ if (pos < end && *pos != ASN1_INDEF_TERM && (ctrl->debug & PRI_DEBUG_APDU)) {
++ pri_message(ctrl,
++ " Skipping unused indefinite length constructed component octets!\n");
++ }
++ return asn1_dec_indef_end_fixup_helper(pos, end);
++}
++
++/*!
++ * \brief Decode the boolean primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param value Decoded boolean value.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_boolean(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, int32_t *value)
++{
++ int length;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length != 1) {
++ /*
++ * The encoding rules say the length can only be one.
++ * It is rediculus to get anything else anyway.
++ */
++ return NULL;
++ }
++
++ *value = *pos++ ? 1 : 0;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = %d\n", name, asn1_tag2str(tag), *value);
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the integer type primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param value Decoded integer type value.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_int(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, int32_t *value)
++{
++ int length;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length <= 0) {
++ /*
++ * The encoding rules say the length can not be indefinite.
++ * It cannot be empty for that matter either.
++ */
++ return NULL;
++ }
++
++#if 1
++ /* Read value as signed */
++ if (*pos & 0x80) {
++ /* The value is negative */
++ *value = -1;
++ } else {
++ *value = 0;
++ }
++#else
++ /* Read value as unsigned */
++ *value = 0;
++#endif
++ while (length--) {
++ *value = (*value << 8) | *pos;
++ pos++;
++ }
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = %d 0x%04X\n", name, asn1_tag2str(tag), *value,
++ *value);
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the null primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_null(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end)
++{
++ int length;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length != 0) {
++ /*
++ * The encoding rules say the length can only be zero.
++ * It is rediculus to get anything else anyway.
++ */
++ return NULL;
++ }
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s\n", name, asn1_tag2str(tag));
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the object identifier primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param oid Decoded OID type value.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_oid(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct asn1_oid *oid)
++{
++ int length;
++ unsigned num_values;
++ unsigned value;
++ unsigned delimiter;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length < 0) {
++ /*
++ * The encoding rules say the length can not be indefinite.
++ */
++ return NULL;
++ }
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s =", name, asn1_tag2str(tag));
++ }
++ delimiter = ' ';
++ num_values = 0;
++ while (length) {
++ value = 0;
++ for (;;) {
++ --length;
++ value = (value << 7) | (*pos & 0x7F);
++ if (!(*pos++ & 0x80)) {
++ /* Last octet in the OID subidentifier value */
++ if (num_values < ARRAY_LEN(oid->value)) {
++ oid->value[num_values] = value;
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "%c%u", delimiter, value);
++ }
++ delimiter = '.';
++ } else {
++ /* Too many OID subidentifier values */
++ delimiter = '~';
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "%c%u", delimiter, value);
++ }
++ }
++ ++num_values;
++ break;
++ }
++ if (!length) {
++ oid->num_values = 0;
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "\n"
++ " Last OID subidentifier value not terminated!\n");
++ }
++ return NULL;
++ }
++ }
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "\n");
++ }
++
++ if (num_values <= ARRAY_LEN(oid->value)) {
++ oid->num_values = num_values;
++ return pos;
++ } else {
++ /* Need to increase the size of the OID subidentifier list. */
++ oid->num_values = 0;
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Too many OID values!\n");
++ }
++ return NULL;
++ }
++}
++
++/*!
++ * \brief Decode a binary string primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param buf_size Size of the supplied string buffer. (Must be nonzero)
++ * \param str Where to put the decoded string.
++ * \param str_len Length of the decoded string.
++ *
++ * \note The string will be null terminated just in case.
++ * The buffer needs to have enough room for a null terminator.
++ * \note The parse will fail if the parsed string is too large for
++ * the supplied buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_string_bin(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
++ unsigned char *str, size_t *str_len)
++{
++ int length;
++ size_t sub_buf_size;
++ size_t sub_str_len;
++ unsigned char *sub_str;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length < 0) {
++ /* This is an indefinite length string */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = Indefinite length string\n", name,
++ asn1_tag2str(tag));
++ }
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) {
++ /*
++ * This is an ITU encoded indefinite length string
++ * and could contain null.
++ */
++
++ /* Ensure that an empty string is null terminated. */
++ *str = 0;
++
++ /* Collect all substrings into the original string buffer. */
++ *str_len = 0;
++ sub_str = str;
++ sub_buf_size = buf_size;
++ for (;;) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag));
++ if (tag == ASN1_INDEF_TERM) {
++ /* End-of-contents octets */
++ break;
++ }
++
++ /* Append the substring to the accumulated indefinite string. */
++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end,
++ sub_buf_size, sub_str, &sub_str_len));
++
++ sub_buf_size -= sub_str_len;
++ sub_str += sub_str_len;
++ *str_len += sub_str_len;
++ }
++ } else {
++ /*
++ * This is a non-ITU encoded indefinite length string
++ * and must not contain null's.
++ */
++ for (length = 0;; ++length) {
++ if (end <= pos + length) {
++ /* Not enough buffer left */
++ return NULL;
++ }
++ if (pos[length] == 0) {
++ /* Found End-of-contents octets */
++ break;
++ }
++ }
++
++ if (buf_size - 1 < length) {
++ /* The destination buffer is not large enough for the data */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " String buffer not large enough!\n");
++ }
++ return NULL;
++ }
++
++ /* Extract the string and null terminate it. */
++ memcpy(str, pos, length);
++ str[length] = 0;
++ *str_len = length;
++
++ pos += length + 1;
++ }
++ if (end <= pos) {
++ /* Not enough buffer left for End-of-contents octets */
++ return NULL;
++ }
++ if (*pos++ != 0) {
++ /* We actually did not find the End-of-contents octets. */
++ return NULL;
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ /* Dump the collected string buffer contents. */
++ pri_message(ctrl, " Completed string =\n");
++ asn1_dump_mem(ctrl, 6, str, *str_len);
++ }
++ } else {
++ /* This is a definite length string */
++ if (buf_size - 1 < length) {
++ /* The destination buffer is not large enough for the data */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = Buffer not large enough!\n", name,
++ asn1_tag2str(tag));
++ }
++ return NULL;
++ }
++
++ /* Extract the string and null terminate it. */
++ memcpy(str, pos, length);
++ str[length] = 0;
++ *str_len = length;
++
++ pos += length;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ /* Dump the collected string buffer contents. */
++ pri_message(ctrl, " %s %s =\n", name, asn1_tag2str(tag));
++ asn1_dump_mem(ctrl, 4, str, *str_len);
++ }
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode a string that can be truncated to a maximum length primitive.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this primitive.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param buf_size Size of the supplied string buffer. (Must be nonzero)
++ * \param str Where to put the decoded null terminated string.
++ * \param str_len Length of the decoded string.
++ * (computed for convenience since you could just do a strlen())
++ *
++ * \note The parsed string will be truncated if the string buffer
++ * cannot contain it.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *asn1_dec_string_max(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
++ unsigned char *str, size_t *str_len)
++{
++ int length;
++ size_t str_length;
++ size_t sub_buf_size;
++ size_t sub_str_len;
++ unsigned char *sub_str;
++
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ if (length < 0) {
++ /* This is an indefinite length string */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = Indefinite length string\n", name,
++ asn1_tag2str(tag));
++ }
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) {
++ /* This is an ITU encoded indefinite length string. */
++
++ /* Ensure that an empty string is null terminated. */
++ *str = 0;
++
++ /* Collect all substrings into the original string buffer. */
++ *str_len = 0;
++ sub_str = str;
++ sub_buf_size = buf_size;
++ for (;;) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag));
++ if (tag == ASN1_INDEF_TERM) {
++ /* End-of-contents octets */
++ break;
++ }
++
++ /* Append the substring to the accumulated indefinite string. */
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, name, tag, pos, end,
++ sub_buf_size, sub_str, &sub_str_len));
++
++ sub_buf_size -= sub_str_len;
++ sub_str += sub_str_len;
++ *str_len += sub_str_len;
++ }
++ } else {
++ /* This is a non-ITU encoded indefinite length string. */
++ for (length = 0;; ++length) {
++ if (end <= pos + length) {
++ /* Not enough buffer left */
++ return NULL;
++ }
++ if (pos[length] == 0) {
++ /* Found End-of-contents octets */
++ break;
++ }
++ }
++
++ /* Extract the string, truncate if necessary, and terminate it. */
++ str_length = (buf_size - 1 < length) ? buf_size - 1 : length;
++ memcpy(str, pos, str_length);
++ str[str_length] = 0;
++ *str_len = str_length;
++
++ pos += length + 1;
++ }
++ if (end <= pos) {
++ /* Not enough buffer left for End-of-contents octets */
++ return NULL;
++ }
++ if (*pos++ != 0) {
++ /* We actually did not find the End-of-contents octets. */
++ return NULL;
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Completed string = \"%s\"\n", str);
++ }
++ } else {
++ /*
++ * This is a definite length string
++ *
++ * Extract the string, truncate if necessary, and terminate it.
++ */
++ str_length = (buf_size - 1 < length) ? buf_size - 1 : length;
++ memcpy(str, pos, str_length);
++ str[str_length] = 0;
++ *str_len = str_length;
++
++ pos += length;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s = \"%s\"\n", name, asn1_tag2str(tag), str);
++ }
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Recursive ASN.1 buffer decoding dump helper.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param pos ASN.1 tag starting position.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param level Indentation level to use.
++ * \param indefinite_term TRUE if to stop on an indefinite length terminator.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *asn1_dump_helper(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end, unsigned level, unsigned indefinite_term)
++{
++ unsigned delimiter;
++ unsigned tag;
++ int length;
++ const unsigned char *len_pos;
++
++ while (pos < end && (!indefinite_term || *pos != ASN1_INDEF_TERM)) {
++ /* Decode the tag */
++ pri_message(ctrl, "%*s", 2 * level, "");
++ len_pos = asn1_dec_tag(pos, end, &tag);
++ if (!len_pos) {
++ pri_message(ctrl, "Invalid tag encoding!\n");
++ return NULL;
++ }
++
++ /* Dump the tag contents. */
++ pri_message(ctrl, "%s ", asn1_tag2str(tag));
++ delimiter = '<';
++ while (pos < len_pos) {
++ pri_message(ctrl, "%c%02X", delimiter, *pos);
++ delimiter = ' ';
++ ++pos;
++ }
++ pri_message(ctrl, "> ");
++
++ /* Decode the length */
++ pos = asn1_dec_length(len_pos, end, &length);
++ if (!pos) {
++ pri_message(ctrl, "Invalid length encoding!\n");
++ return NULL;
++ }
++
++ /* Dump the length contents. */
++ if (length < 0) {
++ pri_message(ctrl, "Indefinite length ");
++ } else {
++ pri_message(ctrl, "Len:%d ", length);
++ }
++ delimiter = '<';
++ while (len_pos < pos) {
++ pri_message(ctrl, "%c%02X", delimiter, *len_pos);
++ delimiter = ' ';
++ ++len_pos;
++ }
++ pri_message(ctrl, ">\n");
++
++ /* Dump the body contents */
++ ++level;
++ if (length < 0) {
++ /* Indefinite length */
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) {
++ /* This is an ITU encoded indefinite length component. */
++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, end, level, 1));
++ } else if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET)
++ || tag ==
++ (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) {
++ pri_message(ctrl, "%*sThis tag must always be constructed!\n", 2 * level,
++ "");
++ /* Assume tag was constructed to keep going */
++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, end, level, 1));
++ } else {
++ /* This is a non-ITU encoded indefinite length component. */
++ pri_message(ctrl, "%*sNon-ITU indefininte length component.\n",
++ 2 * level, "");
++ length = 0;
++ while (pos + length < end && pos[length] != ASN1_INDEF_TERM) {
++ ++length;
++ }
++ if (length) {
++ asn1_dump_mem(ctrl, 2 * level, pos, length);
++ pos += length;
++ }
++ }
++ --level;
++ if (end < pos + ASN1_INDEF_TERM_LEN) {
++ pri_message(ctrl, "%*sNot enough room for the End-of-contents octets!\n",
++ 2 * level, "");
++ pos = end;
++ } else {
++ pri_message(ctrl, "%*sEnd-of-contents <%02X %02X>%s\n", 2 * level, "",
++ pos[0], pos[1], (pos[1] != 0) ? " Invalid!" : "");
++ pos += ASN1_INDEF_TERM_LEN;
++ }
++ } else {
++ /* Defininte length */
++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) {
++ /* Dump constructed contents */
++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, pos + length, level, 0));
++ } else if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET)
++ || tag ==
++ (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) {
++ /* Assume tag was constructed to keep going */
++ pri_message(ctrl, "%*sThis tag must always be constructed!\n", 2 * level,
++ "");
++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, pos + length, level, 0));
++ } else if (0 < length) {
++ /* Dump primitive contents. */
++ asn1_dump_mem(ctrl, 2 * level, pos, length);
++ pos += length;
++ }
++ --level;
++ }
++
++#if 0
++ pri_message(ctrl, "%*sEnd\n", 2 * level, "");
++#endif
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Dump the given ASN.1 buffer contents.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param start_asn1 First octet in the ASN.1 buffer. (ASN.1 tag starting position)
++ * \param end One beyond the last octet in the ASN.1 buffer.
++ *
++ * \return Nothing
++ */
++void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1,
++ const unsigned char *end)
++{
++ pri_message(ctrl, "ASN.1 dump\n");
++ if (start_asn1) {
++ asn1_dump_helper(ctrl, start_asn1, end, 1, 0);
++ }
++ pri_message(ctrl, "ASN.1 end\n");
++}
++
++/*!
++ * \brief Encode the length of an ASN.1 component body of predetermined size.
++ *
++ * \param len_pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param length Predetermined component body length.
++ *
++ * \note The encoding buffer does not need to be checked after calling.
++ * It is already checked to have the requested room.
++ *
++ * \retval Next octet after the length on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_length(unsigned char *len_pos, unsigned char *end, size_t length)
++{
++ u_int32_t body_length; /* Length of component contents */
++ u_int32_t value;
++ u_int32_t test_mask;
++ unsigned length_size; /* Length of the length encoding */
++
++ body_length = length;
++
++ /* Determine length encoding length */
++ if (body_length < 128) {
++ length_size = 1;
++ } else {
++ /* Find most significant octet of 32 bit integer that carries meaning. */
++ test_mask = 0xFF000000;
++ for (length_size = 4; --length_size;) {
++ if (body_length & test_mask) {
++ /*
++ * Found the first 8 bits of a multiple octet length that
++ * is not all zeroes.
++ */
++ break;
++ }
++ test_mask >>= 8;
++ }
++ length_size += 1 + 1;
++ }
++
++ if (end < len_pos + length_size + body_length) {
++ /* No room for the length and component body in the buffer */
++ return NULL;
++ }
++
++ /* Encode the component body length */
++ if (length_size == 1) {
++ *len_pos++ = body_length;
++ } else {
++ *len_pos++ = 0x80 | --length_size;
++ while (length_size--) {
++ value = body_length;
++ value >>= (8 * length_size);
++ *len_pos++ = value & 0xFF;
++ }
++ }
++
++ return len_pos;
++}
++
++/*!
++ * \brief Encode the length of an already encoded ASN.1 component.
++ *
++ * \param len_pos Starting position of the ASN.1 component length.
++ * \param component_end Next octet after the component body.
++ * \param end End of ASN.1 encoding data buffer.
++ *
++ * \note The total component size could increase or decrease.
++ * \note The component length field must have been initialized with
++ * ASN1_LEN_INIT() or ASN1_CONSTRUCTED_BEGIN().
++ *
++ * \retval Next octet after the component body on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_length_fixup(unsigned char *len_pos,
++ unsigned char *component_end, unsigned char *end)
++{
++ u_int32_t body_length; /* Length of component contents */
++ u_int32_t value;
++ u_int32_t test_mask;
++ unsigned length_size; /* Length of the length encoding */
++
++ if (component_end < len_pos + *len_pos) {
++ /* Sanity check */
++ return NULL;
++ }
++
++ body_length = component_end - len_pos - *len_pos;
++
++ /* Determine length encoding length */
++ if (body_length < 128) {
++ length_size = 1;
++ } else {
++ /* Find most significant octet of 32 bit integer that carries meaning. */
++ test_mask = 0xFF000000;
++ for (length_size = 4; --length_size;) {
++ if (body_length & test_mask) {
++ /*
++ * Found the first 8 bits of a multiple octet length that
++ * is not all zeroes.
++ */
++ break;
++ }
++ test_mask >>= 8;
++ }
++ length_size += 1 + 1;
++ }
++
++ component_end = len_pos + length_size + body_length;
++ if (end < component_end) {
++ /* No room for the component in the buffer */
++ return NULL;
++ }
++ if (length_size != *len_pos) {
++ /* Must shift the component body */
++ memmove(len_pos + length_size, len_pos + *len_pos, body_length);
++ }
++
++ /* Encode the component body length */
++ if (length_size == 1) {
++ *len_pos = body_length;
++ } else {
++ *len_pos++ = 0x80 | --length_size;
++ while (length_size--) {
++ value = body_length;
++ value >>= (8 * length_size);
++ *len_pos++ = value & 0xFF;
++ }
++ }
++
++ return component_end;
++}
++
++/*!
++ * \brief Encode the boolean primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param value Component value to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_boolean(unsigned char *pos, unsigned char *end, unsigned tag,
++ int32_t value)
++{
++ if (end < pos + 3) {
++ /* No room for the component in the buffer */
++ return NULL;
++ }
++
++ /* Encode component */
++ *pos++ = tag;
++ *pos++ = 1;
++ *pos++ = value ? 1 : 0;
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the integer type primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param value Component value to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_int(unsigned char *pos, unsigned char *end, unsigned tag,
++ int32_t value)
++{
++ unsigned count;
++ u_int32_t test_mask;
++ u_int32_t val;
++
++ /* Find most significant octet of 32 bit integer that carries meaning. */
++ test_mask = 0xFF800000;
++ val = (u_int32_t) value;
++ for (count = 4; --count;) {
++ if ((val & test_mask) != test_mask && (val & test_mask) != 0) {
++ /*
++ * The first 9 bits of a multiple octet integer is not
++ * all ones or zeroes.
++ */
++ break;
++ }
++ test_mask >>= 8;
++ }
++
++ if (end < pos + 3 + count) {
++ /* No room for the component in the buffer */
++ return NULL;
++ }
++
++ /* Encode component */
++ *pos++ = tag;
++ *pos++ = count + 1;
++ do {
++ val = (u_int32_t) value;
++ val >>= (8 * count);
++ *pos++ = val & 0xFF;
++ } while (count--);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the null type primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_null(unsigned char *pos, unsigned char *end, unsigned tag)
++{
++ if (end < pos + 2) {
++ /* No room for the component in the buffer */
++ return NULL;
++ }
++
++ /* Encode component */
++ *pos++ = tag;
++ *pos++ = 0;
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the object identifier (OID) primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param oid Component value to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_oid(unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct asn1_oid *oid)
++{
++ unsigned char *len_pos;
++ unsigned num_values;
++ unsigned count;
++ u_int32_t value;
++
++ if (end < pos + 2) {
++ /* No room for the component tag and length in the buffer */
++ return NULL;
++ }
++
++ *pos++ = tag;
++ len_pos = pos++;
++
++ /* For all OID subidentifer values */
++ for (num_values = 0; num_values < oid->num_values; ++num_values) {
++ /*
++ * Count the number of 7 bit chunks that are needed
++ * to encode the integer.
++ */
++ value = oid->value[num_values] >> 7;
++ for (count = 0; value; ++count) {
++ /* There are bits still set */
++ value >>= 7;
++ }
++
++ if (end < pos + count + 1) {
++ /* No room for the component body in the buffer */
++ return NULL;
++ }
++
++ /* Store OID subidentifier value */
++ do {
++ value = oid->value[num_values];
++ value >>= (7 * count);
++ *pos++ = (value & 0x7F) | (count ? 0x80 : 0);
++ } while (count--);
++ }
++
++ /* length */
++ *len_pos = pos - len_pos - 1;
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the binary string type primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param str Binary string to encode.
++ * \param str_len Length of binary string to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_string_bin(unsigned char *pos, unsigned char *end, unsigned tag,
++ const unsigned char *str, size_t str_len)
++{
++ if (end < pos + 1) {
++ /* No room for the component tag in the buffer */
++ return NULL;
++ }
++
++ /* Encode component */
++ *pos++ = tag;
++ ASN1_CALL(pos, asn1_enc_length(pos, end, str_len));
++ memcpy(pos, str, str_len);
++
++ return pos + str_len;
++}
++
++/*!
++ * \brief Encode a string that can be truncated to a maximum length primitive.
++ *
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * \param str Null terminated string to encode.
++ * \param max_len Maximum length of string to encode.
++ *
++ * \note The string will be truncated if it is too long.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *asn1_enc_string_max(unsigned char *pos, unsigned char *end, unsigned tag,
++ const unsigned char *str, size_t max_len)
++{
++ size_t str_len;
++
++ str_len = strlen((char *) str);
++ if (max_len < str_len) {
++ str_len = max_len;
++ }
++ return asn1_enc_string_bin(pos, end, tag, str, str_len);
++}
++
++/* ------------------------------------------------------------------- */
++/* end asn1_primitive.c */
+
+Property changes on: asn1_primitive.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: pri.c
+===================================================================
+--- a/pri.c (.../tags/1.4.10.2) (revision 1357)
++++ b/pri.c (.../branches/1.4) (revision 1357)
+@@ -42,8 +42,56 @@
+ #include "pri_facility.h"
+ #include "pri_q921.h"
+ #include "pri_q931.h"
+-#include "pri_timers.h"
+
++#define PRI_BIT(a_bit) (1UL << (a_bit))
++#define PRI_ALL_SWITCHES 0xFFFFFFFF
++
++struct pri_timer_table {
++ const char *name;
++ enum PRI_TIMERS_AND_COUNTERS number;
++ unsigned long used_by;
++};
++
++/*!
++ * \note Sort the timer table entries in the order of the timer name so
++ * pri_dump_info_str() can display them in a consitent order.
++ */
++static const struct pri_timer_table pri_timer[] = {
++/* *INDENT-OFF* */
++ /* timer name timer number used by switches */
++ { "N200", PRI_TIMER_N200, PRI_ALL_SWITCHES },
++ { "N201", PRI_TIMER_N201, PRI_ALL_SWITCHES },
++ { "N202", PRI_TIMER_N202, PRI_ALL_SWITCHES },
++ { "K", PRI_TIMER_K, PRI_ALL_SWITCHES },
++ { "T200", PRI_TIMER_T200, PRI_ALL_SWITCHES },
++ { "T202", PRI_TIMER_T202, PRI_ALL_SWITCHES },
++ { "T203", PRI_TIMER_T203, PRI_ALL_SWITCHES },
++ { "T300", PRI_TIMER_T300, PRI_ALL_SWITCHES },
++ { "T301", PRI_TIMER_T301, PRI_ALL_SWITCHES },
++ { "T302", PRI_TIMER_T302, PRI_ALL_SWITCHES },
++ { "T303", PRI_TIMER_T303, PRI_ALL_SWITCHES },
++ { "T304", PRI_TIMER_T304, PRI_ALL_SWITCHES },
++ { "T305", PRI_TIMER_T305, PRI_ALL_SWITCHES },
++ { "T306", PRI_TIMER_T306, PRI_ALL_SWITCHES },
++ { "T307", PRI_TIMER_T307, PRI_ALL_SWITCHES },
++ { "T308", PRI_TIMER_T308, PRI_ALL_SWITCHES },
++ { "T309", PRI_TIMER_T309, PRI_ALL_SWITCHES },
++ { "T310", PRI_TIMER_T310, PRI_ALL_SWITCHES },
++ { "T313", PRI_TIMER_T313, PRI_ALL_SWITCHES },
++ { "T314", PRI_TIMER_T314, PRI_ALL_SWITCHES },
++ { "T316", PRI_TIMER_T316, PRI_ALL_SWITCHES },
++ { "T317", PRI_TIMER_T317, PRI_ALL_SWITCHES },
++ { "T318", PRI_TIMER_T318, PRI_ALL_SWITCHES },
++ { "T319", PRI_TIMER_T319, PRI_ALL_SWITCHES },
++ { "T320", PRI_TIMER_T320, PRI_ALL_SWITCHES },
++ { "T321", PRI_TIMER_T321, PRI_ALL_SWITCHES },
++ { "T322", PRI_TIMER_T322, PRI_ALL_SWITCHES },
++ { "T-HOLD", PRI_TIMER_T_HOLD, PRI_ALL_SWITCHES },
++ { "T-RETRIEVE", PRI_TIMER_T_RETRIEVE, PRI_ALL_SWITCHES },
++ { "T-RESPONSE", PRI_TIMER_T_RESPONSE, PRI_ALL_SWITCHES },
++/* *INDENT-ON* */
++};
++
+ char *pri_node2str(int node)
+ {
+ switch(node) {
+@@ -84,14 +132,39 @@
+ }
+ }
+
+-static void pri_default_timers(struct pri *pri, int switchtype)
++static void pri_default_timers(struct pri *ctrl, int switchtype)
+ {
+- static const int defaulttimers[20][PRI_MAX_TIMERS] = PRI_TIMERS_ALL;
+- int x;
++ unsigned idx;
+
+- for (x = 0; x<PRI_MAX_TIMERS; x++) {
+- pri->timers[x] = defaulttimers[switchtype][x];
++ /* Initialize all timers/counters to unsupported/disabled. */
++ for (idx = 0; idx < PRI_MAX_TIMERS; ++idx) {
++ ctrl->timers[idx] = -1;
+ }
++
++ /* Set timer values to standard defaults. Time is in ms. */
++ ctrl->timers[PRI_TIMER_N200] = 3; /* Max numer of Q.921 retransmissions */
++ ctrl->timers[PRI_TIMER_N202] = 3; /* Max numer of transmissions of the TEI identity request message */
++ ctrl->timers[PRI_TIMER_K] = 7; /* Max number of outstanding I-frames */
++ ctrl->timers[PRI_TIMER_T200] = 1000; /* Time between SABME's */
++ ctrl->timers[PRI_TIMER_T202] = 10 * 1000; /* Min time between transmission of TEI Identity request messages */
++ ctrl->timers[PRI_TIMER_T203] = 10 * 1000; /* Max time without exchanging packets */
++ ctrl->timers[PRI_TIMER_T305] = 30 * 1000; /* Wait for DISCONNECT acknowledge */
++ ctrl->timers[PRI_TIMER_T308] = 4 * 1000; /* Wait for RELEASE acknowledge */
++ ctrl->timers[PRI_TIMER_T313] = 4 * 1000; /* Wait for CONNECT acknowledge, CPE side only */
++ ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */
++ ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */
++ ctrl->timers[PRI_TIMER_T303] = 4 * 1000; /* Length between SETUP retransmissions and timeout */
++
++ ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000; /* Wait for HOLD request response. */
++ ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */
++
++ ctrl->timers[PRI_TIMER_T_RESPONSE] = 4 * 1000; /* Maximum time to wait for a typical APDU response. */
++
++ /* Set any switch specific override default values */
++ switch (switchtype) {
++ default:
++ break;
++ }
+ }
+
+ int pri_set_timer(struct pri *pri, int timer, int value)
+@@ -110,66 +183,30 @@
+ return pri->timers[timer];
+ }
+
+-int pri_timer2idx(char *timer)
++int pri_set_service_message_support(struct pri *pri, int supportflag)
+ {
+- if (!strcasecmp(timer, "N200"))
+- return PRI_TIMER_N200;
+- else if (!strcasecmp(timer, "N201"))
+- return PRI_TIMER_N201;
+- else if (!strcasecmp(timer, "N202"))
+- return PRI_TIMER_N202;
+- else if (!strcasecmp(timer, "K"))
+- return PRI_TIMER_K;
+- else if (!strcasecmp(timer, "T200"))
+- return PRI_TIMER_T200;
+- else if (!strcasecmp(timer, "T202"))
+- return PRI_TIMER_T202;
+- else if (!strcasecmp(timer, "T203"))
+- return PRI_TIMER_T203;
+- else if (!strcasecmp(timer, "T300"))
+- return PRI_TIMER_T300;
+- else if (!strcasecmp(timer, "T301"))
+- return PRI_TIMER_T301;
+- else if (!strcasecmp(timer, "T302"))
+- return PRI_TIMER_T302;
+- else if (!strcasecmp(timer, "T303"))
+- return PRI_TIMER_T303;
+- else if (!strcasecmp(timer, "T304"))
+- return PRI_TIMER_T304;
+- else if (!strcasecmp(timer, "T305"))
+- return PRI_TIMER_T305;
+- else if (!strcasecmp(timer, "T306"))
+- return PRI_TIMER_T306;
+- else if (!strcasecmp(timer, "T307"))
+- return PRI_TIMER_T307;
+- else if (!strcasecmp(timer, "T308"))
+- return PRI_TIMER_T308;
+- else if (!strcasecmp(timer, "T309"))
+- return PRI_TIMER_T309;
+- else if (!strcasecmp(timer, "T310"))
+- return PRI_TIMER_T310;
+- else if (!strcasecmp(timer, "T313"))
+- return PRI_TIMER_T313;
+- else if (!strcasecmp(timer, "T314"))
+- return PRI_TIMER_T314;
+- else if (!strcasecmp(timer, "T316"))
+- return PRI_TIMER_T316;
+- else if (!strcasecmp(timer, "T317"))
+- return PRI_TIMER_T317;
+- else if (!strcasecmp(timer, "T318"))
+- return PRI_TIMER_T318;
+- else if (!strcasecmp(timer, "T319"))
+- return PRI_TIMER_T319;
+- else if (!strcasecmp(timer, "T320"))
+- return PRI_TIMER_T320;
+- else if (!strcasecmp(timer, "T321"))
+- return PRI_TIMER_T321;
+- else if (!strcasecmp(timer, "T322"))
+- return PRI_TIMER_T322;
+- else
++ if (!pri) {
+ return -1;
++ }
++ pri->service_message_support = supportflag;
++ return 0;
+ }
+
++int pri_timer2idx(const char *timer_name)
++{
++ unsigned idx;
++ enum PRI_TIMERS_AND_COUNTERS timer_number;
++
++ timer_number = -1;
++ for (idx = 0; idx < ARRAY_LEN(pri_timer); ++idx) {
++ if (!strcasecmp(timer_name, pri_timer[idx].name)) {
++ timer_number = pri_timer[idx].number;
++ break;
++ }
++ }
++ return timer_number;
++}
++
+ static int __pri_read(struct pri *pri, void *buf, int buflen)
+ {
+ int res = read(pri->fd, buf, buflen);
+@@ -192,18 +229,53 @@
+ return res;
+ }
+
+-/* Pass in the master for this function */
+ void __pri_free_tei(struct pri * p)
+ {
+- free (p);
++ if (p) {
++ struct q931_call *call;
++
++ call = p->dummy_call;
++ if (call) {
++ pri_schedule_del(call->pri, call->retranstimer);
++ pri_call_apdu_queue_cleanup(call);
++ }
++ free(p->msg_line);
++ free(p);
++ }
+ }
+
+ struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int tei, int bri)
+ {
++ struct d_ctrl_dummy *dummy_ctrl;
+ struct pri *p;
+
+- if (!(p = calloc(1, sizeof(*p))))
+- return NULL;
++ switch (switchtype) {
++ case PRI_SWITCH_GR303_EOC:
++ case PRI_SWITCH_GR303_TMC:
++ case PRI_SWITCH_GR303_TMC_SWITCHING:
++ case PRI_SWITCH_GR303_EOC_PATH:
++ p = calloc(1, sizeof(*p));
++ if (!p) {
++ return NULL;
++ }
++ dummy_ctrl = NULL;
++ break;
++ default:
++ dummy_ctrl = calloc(1, sizeof(*dummy_ctrl));
++ if (!dummy_ctrl) {
++ return NULL;
++ }
++ p = &dummy_ctrl->ctrl;
++ break;
++ }
++ if (!master) {
++ /* This is the master record. */
++ p->msg_line = calloc(1, sizeof(*p->msg_line));
++ if (!p->msg_line) {
++ free(p);
++ return NULL;
++ }
++ }
+
+ p->bri = bri;
+ p->fd = fd;
+@@ -231,7 +303,14 @@
+ p->q931_rxcount = 0;
+ p->q931_txcount = 0;
+ #endif
+- if (switchtype == PRI_SWITCH_GR303_EOC) {
++ if (dummy_ctrl) {
++ /* Initialize the dummy call reference call record. */
++ dummy_ctrl->ctrl.dummy_call = &dummy_ctrl->dummy_call;
++ q931_init_call_record(&dummy_ctrl->ctrl, dummy_ctrl->ctrl.dummy_call,
++ Q931_DUMMY_CALL_REFERENCE);
++ }
++ switch (switchtype) {
++ case PRI_SWITCH_GR303_EOC:
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_EOC;
+ p->tei = Q921_TEI_GR303_EOC_OPS;
+@@ -240,7 +319,8 @@
+ free(p);
+ p = NULL;
+ }
+- } else if (switchtype == PRI_SWITCH_GR303_TMC) {
++ break;
++ case PRI_SWITCH_GR303_TMC:
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_TMC_CALLPROC;
+ p->tei = Q921_TEI_GR303_TMC_CALLPROC;
+@@ -249,14 +329,19 @@
+ free(p);
+ p = NULL;
+ }
+- } else if (switchtype == PRI_SWITCH_GR303_TMC_SWITCHING) {
++ break;
++ case PRI_SWITCH_GR303_TMC_SWITCHING:
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_TMC_SWITCHING;
+ p->tei = Q921_TEI_GR303_TMC_SWITCHING;
+- } else if (switchtype == PRI_SWITCH_GR303_EOC_PATH) {
++ break;
++ case PRI_SWITCH_GR303_EOC_PATH:
+ p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
+ p->sapi = Q921_SAPI_GR303_EOC;
+ p->tei = Q921_TEI_GR303_EOC_PATH;
++ break;
++ default:
++ break;
+ }
+ /* Start Q.921 layer, Wait if we're the network */
+ if (p)
+@@ -327,44 +412,47 @@
+
+ char *pri_event2str(int id)
+ {
+- switch(id) {
+- case PRI_EVENT_DCHAN_UP:
+- return "D-Channel Up";
+- case PRI_EVENT_DCHAN_DOWN:
+- return "D-channel Down";
+- case PRI_EVENT_RESTART:
+- return "Restart channel";
+- case PRI_EVENT_RING:
+- return "Ring";
+- case PRI_EVENT_HANGUP:
+- return "Hangup";
+- case PRI_EVENT_RINGING:
+- return "Ringing";
+- case PRI_EVENT_ANSWER:
+- return "Answer";
+- case PRI_EVENT_HANGUP_ACK:
+- return "Hangup ACK";
+- case PRI_EVENT_RESTART_ACK:
+- return "Restart ACK";
+- case PRI_EVENT_FACNAME:
+- return "FacName";
+- case PRI_EVENT_INFO_RECEIVED:
+- return "Info Received";
+- case PRI_EVENT_PROCEEDING:
+- return "Proceeding";
+- case PRI_EVENT_SETUP_ACK:
+- return "Setup ACK";
+- case PRI_EVENT_HANGUP_REQ:
+- return "Hangup Req";
+- case PRI_EVENT_NOTIFY:
+- return "Notify";
+- case PRI_EVENT_PROGRESS:
+- return "Progress";
+- case PRI_EVENT_CONFIG_ERR:
+- return "Configuration Error";
+- default:
+- return "Unknown Event";
++ unsigned idx;
++ struct {
++ int id;
++ char *name;
++ } events[] = {
++/* *INDENT-OFF* */
++ { PRI_EVENT_DCHAN_UP, "D-Channel Up" },
++ { PRI_EVENT_DCHAN_DOWN, "D-channel Down" },
++ { PRI_EVENT_RESTART, "Restart channel" },
++ { PRI_EVENT_CONFIG_ERR, "Configuration Error" },
++ { PRI_EVENT_RING, "Ring" },
++ { PRI_EVENT_HANGUP, "Hangup" },
++ { PRI_EVENT_RINGING, "Ringing" },
++ { PRI_EVENT_ANSWER, "Answer" },
++ { PRI_EVENT_HANGUP_ACK, "Hangup ACK" },
++ { PRI_EVENT_RESTART_ACK, "Restart ACK" },
++ { PRI_EVENT_FACILITY, "Facility" },
++ { PRI_EVENT_INFO_RECEIVED, "Info Received" },
++ { PRI_EVENT_PROCEEDING, "Proceeding" },
++ { PRI_EVENT_SETUP_ACK, "Setup ACK" },
++ { PRI_EVENT_HANGUP_REQ, "Hangup Req" },
++ { PRI_EVENT_NOTIFY, "Notify" },
++ { PRI_EVENT_PROGRESS, "Progress" },
++ { PRI_EVENT_KEYPAD_DIGIT, "Keypad Digit" },
++ { PRI_EVENT_SERVICE, "Service" },
++ { PRI_EVENT_SERVICE_ACK, "Service ACK" },
++ { PRI_EVENT_HOLD, "Hold" },
++ { PRI_EVENT_HOLD_ACK, "Hold Ack" },
++ { PRI_EVENT_HOLD_REJ, "Hold Rej" },
++ { PRI_EVENT_RETRIEVE, "Retrieve" },
++ { PRI_EVENT_RETRIEVE_ACK, "Retrieve ACK" },
++ { PRI_EVENT_RETRIEVE_REJ, "Retrieve Rej" },
++/* *INDENT-ON* */
++ };
++
++ for (idx = 0; idx < ARRAY_LEN(events); ++idx) {
++ if (events[idx].id == id) {
++ return events[idx].name;
++ }
+ }
++ return "Unknown Event";
+ }
+
+ pri_event *pri_check_event(struct pri *pri)
+@@ -506,7 +594,7 @@
+ return q931_information(pri, call, digit);
+ }
+
+-int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits)
++int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits)
+ {
+ if (!pri || !call || !digits || !digits[0])
+ return -1;
+@@ -514,15 +602,6 @@
+ return q931_keypad_facility(pri, call, digits);
+ }
+
+-
+-int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason)
+-{
+- if (!pri || !call)
+- return -1;
+-
+- return qsig_cf_callrerouting(pri, call, dest, original, reason);
+-}
+-
+ int pri_notify(struct pri *pri, q931_call *call, int channel, int info)
+ {
+ if (!pri || !call)
+@@ -533,7 +612,7 @@
+ void pri_destroycall(struct pri *pri, q931_call *call)
+ {
+ if (pri && call)
+- __q931_destroycall(pri, call);
++ q931_destroycall(pri, call);
+ return;
+ }
+
+@@ -551,6 +630,268 @@
+ return q931_connect(pri, call, channel, nonisdn);
+ }
+
++/*!
++ * \internal
++ * \brief Copy the PRI party name to the Q.931 party name structure.
++ *
++ * \param q931_name Q.931 party name structure
++ * \param pri_name PRI party name structure
++ *
++ * \return Nothing
++ */
++static void pri_copy_party_name_to_q931(struct q931_party_name *q931_name, const struct pri_party_name *pri_name)
++{
++ q931_party_name_init(q931_name);
++ if (pri_name->valid) {
++ q931_name->valid = 1;
++ q931_name->presentation = pri_name->presentation;
++ q931_name->char_set = pri_name->char_set;
++ libpri_copy_string(q931_name->str, pri_name->str, sizeof(q931_name->str));
++ }
++}
++
++/*!
++ * \internal
++ * \brief Copy the PRI party number to the Q.931 party number structure.
++ *
++ * \param q931_number Q.931 party number structure
++ * \param pri_number PRI party number structure
++ *
++ * \return Nothing
++ */
++static void pri_copy_party_number_to_q931(struct q931_party_number *q931_number, const struct pri_party_number *pri_number)
++{
++ q931_party_number_init(q931_number);
++ if (pri_number->valid) {
++ q931_number->valid = 1;
++ q931_number->presentation = pri_number->presentation;
++ q931_number->plan = pri_number->plan;
++ libpri_copy_string(q931_number->str, pri_number->str, sizeof(q931_number->str));
++ }
++}
++
++/*!
++ * \internal
++ * \brief Copy the PRI party subaddress to the Q.931 party subaddress structure.
++ *
++ * \param q931_subaddress Q.931 party subaddress structure
++ * \param pri_subaddress PRI party subaddress structure
++ *
++ * \return Nothing
++ */
++static void pri_copy_party_subaddress_to_q931(struct q931_party_subaddress *q931_subaddress, const struct pri_party_subaddress *pri_subaddress)
++{
++ int length;
++ int maxlen = sizeof(q931_subaddress->data) - 1;
++
++ q931_party_subaddress_init(q931_subaddress);
++
++ if (!pri_subaddress->valid) {
++ return;
++ }
++
++ q931_subaddress->valid = 1;
++ q931_subaddress->type = pri_subaddress->type;
++
++ length = pri_subaddress->length;
++ if (length > maxlen){
++ length = maxlen;
++ } else {
++ q931_subaddress->odd_even_indicator = pri_subaddress->odd_even_indicator;
++ }
++ q931_subaddress->length = length;
++ memcpy(q931_subaddress->data, pri_subaddress->data, length);
++ q931_subaddress->data[length] = '\0';
++}
++
++/*!
++ * \internal
++ * \brief Copy the PRI party id to the Q.931 party id structure.
++ *
++ * \param q931_id Q.931 party id structure
++ * \param pri_id PRI party id structure
++ *
++ * \return Nothing
++ */
++static void pri_copy_party_id_to_q931(struct q931_party_id *q931_id, const struct pri_party_id *pri_id)
++{
++ pri_copy_party_name_to_q931(&q931_id->name, &pri_id->name);
++ pri_copy_party_number_to_q931(&q931_id->number, &pri_id->number);
++ pri_copy_party_subaddress_to_q931(&q931_id->subaddress, &pri_id->subaddress);
++}
++
++int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pri_party_connected_line *connected)
++{
++ struct q931_party_id party_id;
++ unsigned idx;
++ struct q931_call *subcall;
++
++ if (!ctrl || !call) {
++ return -1;
++ }
++
++ pri_copy_party_id_to_q931(&party_id, &connected->id);
++ q931_party_id_fixup(ctrl, &party_id);
++ if (!q931_party_id_cmp(&party_id, &call->local_id)) {
++ /* The local party information did not change so do nothing. */
++ return 0;
++ }
++ call->local_id = party_id;
++
++ /* Update all subcalls with new local_id. */
++ if (call->outboundbroadcast && call->master_call == call) {
++ for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
++ subcall = call->subcalls[idx];
++ if (subcall) {
++ subcall->local_id = party_id;
++ }
++ }
++ }
++
++ switch (call->ourcallstate) {
++ case Q931_CALL_STATE_CALL_INITIATED:
++ case Q931_CALL_STATE_OVERLAP_SENDING:
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ /*
++ * The local party transferred to someone else before
++ * the remote end answered.
++ */
++ case Q931_CALL_STATE_ACTIVE:
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (q931_is_ptmp(ctrl)) {
++ /* PTMP mode */
++ q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE,
++ &call->local_id.number);
++ } else {
++ /* PTP mode */
++ /* Immediately send EctInform APDU, callStatus=answered(0) */
++ send_call_transfer_complete(ctrl, call, 0);
++ }
++ break;
++ case PRI_SWITCH_QSIG:
++ /* Immediately send CallTransferComplete APDU, callStatus=answered(0) */
++ send_call_transfer_complete(ctrl, call, 0);
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ /* Just save the data for further developments. */
++ break;
++ }
++
++ return 0;
++}
++
++int pri_redirecting_update(struct pri *ctrl, q931_call *call, const struct pri_party_redirecting *redirecting)
++{
++ unsigned idx;
++ struct q931_call *subcall;
++
++ if (!ctrl || !call) {
++ return -1;
++ }
++
++ /* Save redirecting.to information and reason. */
++ pri_copy_party_id_to_q931(&call->redirecting.to, &redirecting->to);
++ q931_party_id_fixup(ctrl, &call->redirecting.to);
++ call->redirecting.reason = redirecting->reason;
++
++ /*
++ * Update all subcalls with new redirecting.to information and reason.
++ * I do not think we will ever have any subcalls when this data is relevant,
++ * but update it just in case.
++ */
++ if (call->outboundbroadcast && call->master_call == call) {
++ for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
++ subcall = call->subcalls[idx];
++ if (subcall) {
++ subcall->redirecting.to = call->redirecting.to;
++ subcall->redirecting.reason = redirecting->reason;
++ }
++ }
++ }
++
++ switch (call->ourcallstate) {
++ case Q931_CALL_STATE_NULL:
++ /* Save the remaining redirecting information before we place a call. */
++ pri_copy_party_id_to_q931(&call->redirecting.from, &redirecting->from);
++ q931_party_id_fixup(ctrl, &call->redirecting.from);
++ pri_copy_party_id_to_q931(&call->redirecting.orig_called, &redirecting->orig_called);
++ q931_party_id_fixup(ctrl, &call->redirecting.orig_called);
++ call->redirecting.orig_reason = redirecting->orig_reason;
++ if (redirecting->count <= 0) {
++ if (call->redirecting.from.number.valid) {
++ /*
++ * We are redirecting with an unknown count
++ * so assume the count is one.
++ */
++ call->redirecting.count = 1;
++ } else {
++ call->redirecting.count = 0;
++ }
++ } else if (redirecting->count < PRI_MAX_REDIRECTS) {
++ call->redirecting.count = redirecting->count;
++ } else {
++ call->redirecting.count = PRI_MAX_REDIRECTS;
++ }
++ break;
++ case Q931_CALL_STATE_OVERLAP_RECEIVING:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ /* This is an incoming call that has not connected yet. */
++ if (!call->redirecting.to.number.valid) {
++ /* Not being redirected toward valid number data. Ignore. */
++ break;
++ }
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (q931_is_ptmp(ctrl)) {
++ /* PTMP mode */
++ q931_notify_redirection(ctrl, call, PRI_NOTIFY_CALL_DIVERTING,
++ &call->redirecting.to.number);
++ break;
++ }
++ /* PTP mode - same behaviour as Q.SIG */
++ /* fall through */
++ case PRI_SWITCH_QSIG:
++ if (call->redirecting.state != Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3
++ || strcmp(call->redirecting.to.number.str, call->called.number.str) != 0) {
++ /* immediately send divertingLegInformation1 APDU */
++ if (rose_diverting_leg_information1_encode(ctrl, call)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for divertingLegInfo1\n");
++ }
++ }
++ call->redirecting.state = Q931_REDIRECTING_STATE_IDLE;
++
++ /* immediately send divertingLegInformation3 APDU */
++ if (rose_diverting_leg_information3_encode(ctrl, call, Q931_FACILITY)
++ || q931_facility(ctrl, call)) {
++ pri_message(ctrl,
++ "Could not schedule facility message for divertingLegInfo3\n");
++ }
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ pri_message(ctrl, "Ignored redirecting update because call in state %s(%d).\n",
++ q931_call_state_str(call->ourcallstate), call->ourcallstate);
++ break;
++ }
++
++ return 0;
++}
++
+ #if 0
+ /* deprecated routines, use pri_hangup */
+ int pri_release(struct pri *pri, q931_call *call, int cause)
+@@ -619,7 +960,7 @@
+ return -1;
+ if (cause == -1)
+ /* normal clear cause */
+- cause = 16;
++ cause = PRI_CAUSE_NORMAL_CLEARING;
+ return q931_hangup(pri, call, cause);
+ }
+
+@@ -630,6 +971,14 @@
+ return q931_restart(pri, channel);
+ }
+
++int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus)
++{
++ if (!pri) {
++ return -1;
++ }
++ return maintenance_service(pri, span, channel, changestatus);
++}
++
+ q931_call *pri_new_call(struct pri *pri)
+ {
+ if (!pri)
+@@ -637,6 +986,14 @@
+ return q931_new_call(pri);
+ }
+
++int pri_is_dummy_call(q931_call *call)
++{
++ if (!call) {
++ return 0;
++ }
++ return q931_is_dummy_call(call);
++}
++
+ void pri_dump_event(struct pri *pri, pri_event *e)
+ {
+ if (!pri || !e)
+@@ -667,7 +1024,10 @@
+ static void pri_sr_init(struct pri_sr *req)
+ {
+ memset(req, 0, sizeof(struct pri_sr));
+-
++ q931_party_redirecting_init(&req->redirecting);
++ q931_party_id_init(&req->caller);
++ q931_party_address_init(&req->called);
++ req->reversecharge = PRI_REVERSECHARGE_NONE;
+ }
+
+ int pri_sr_set_connection_call_independent(struct pri_sr *req)
+@@ -675,10 +1035,21 @@
+ if (!req)
+ return -1;
+
+- req->justsignalling = 1; /* have to set justsignalling for all those pesky IEs we need to setup */
++ req->cis_call = 1; /* have to set cis_call for all those pesky IEs we need to setup */
++ req->cis_auto_disconnect = 1;
+ return 0;
+ }
+
++int pri_sr_set_no_channel_call(struct pri_sr *req)
++{
++ if (!req) {
++ return -1;
++ }
++
++ req->cis_call = 1;
++ return 0;
++}
++
+ /* Don't call any other pri functions on this */
+ int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called,
+ int calledplan)
+@@ -689,14 +1060,9 @@
+
+ pri_sr_init(&req);
+ pri_sr_set_connection_call_independent(&req);
++ pri_sr_set_caller(&req, caller, callername, callerplan, callerpres);
++ pri_sr_set_called(&req, called, calledplan, 0);
+
+- req.caller = caller;
+- req.callerplan = callerplan;
+- req.callername = callername;
+- req.callerpres = callerpres;
+- req.called = called;
+- req.calledplan = calledplan;
+-
+ if (mwi_message_send(pri, c, &req, 1) < 0) {
+ pri_message(pri, "Unable to send MWI activate message\n");
+ return -1;
+@@ -714,14 +1080,9 @@
+
+ pri_sr_init(&req);
+ pri_sr_set_connection_call_independent(&req);
++ pri_sr_set_caller(&req, caller, callername, callerplan, callerpres);
++ pri_sr_set_called(&req, called, calledplan, 0);
+
+- req.caller = caller;
+- req.callerplan = callerplan;
+- req.callername = callername;
+- req.callerpres = callerpres;
+- req.called = called;
+- req.calledplan = calledplan;
+-
+ if(mwi_message_send(pri, c, &req, 0) < 0) {
+ pri_message(pri, "Unable to send MWI deactivate message\n");
+ return -1;
+@@ -740,22 +1101,18 @@
+
+ int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive,
+ int nonisdn, char *caller, int callerplan, char *callername, int callerpres, char *called,
+- int calledplan,int ulayer1)
++ int calledplan, int ulayer1)
+ {
+ struct pri_sr req;
+ if (!pri || !c)
+ return -1;
+ pri_sr_init(&req);
++ pri_sr_set_caller(&req, caller, callername, callerplan, callerpres);
++ pri_sr_set_called(&req, called, calledplan, 0);
+ req.transmode = transmode;
+ req.channel = channel;
+ req.exclusive = exclusive;
+ req.nonisdn = nonisdn;
+- req.caller = caller;
+- req.callerplan = callerplan;
+- req.callername = callername;
+- req.callerpres = callerpres;
+- req.called = called;
+- req.calledplan = calledplan;
+ req.userl1 = ulayer1;
+ return q931_setup(pri, c, &req);
+ }
+@@ -773,28 +1130,85 @@
+ __pri_error = func;
+ }
+
+-void pri_message(struct pri *pri, char *fmt, ...)
++static void pri_old_message(struct pri *ctrl, const char *fmt, va_list *ap)
+ {
+ char tmp[1024];
+- va_list ap;
+- va_start(ap, fmt);
+- vsnprintf(tmp, sizeof(tmp), fmt, ap);
+- va_end(ap);
++
++ vsnprintf(tmp, sizeof(tmp), fmt, *ap);
+ if (__pri_message)
+- __pri_message(pri, tmp);
++ __pri_message(ctrl, tmp);
+ else
+ fputs(tmp, stdout);
+ }
+
+-void pri_error(struct pri *pri, char *fmt, ...)
++void pri_message(struct pri *ctrl, const char *fmt, ...)
+ {
++ int added_length;
++ va_list ap;
++
++ ctrl = PRI_MASTER(ctrl);
++ if (!ctrl || !ctrl->msg_line) {
++ /* Just have to do it the old way. */
++ va_start(ap, fmt);
++ pri_old_message(ctrl, fmt, &ap);
++ va_end(ap);
++ return;
++ }
++
++ va_start(ap, fmt);
++ added_length = vsnprintf(ctrl->msg_line->str + ctrl->msg_line->length,
++ sizeof(ctrl->msg_line->str) - ctrl->msg_line->length, fmt, ap);
++ va_end(ap);
++ if (added_length < 0
++ || sizeof(ctrl->msg_line->str) <= ctrl->msg_line->length + added_length) {
++ static char truncated_output[] =
++ "v-- Error building output or output was truncated. (Next line) --v\n";
++
++ /*
++ * This clause should never need to run because the
++ * output line accumulation buffer is quite large.
++ */
++
++ /* vsnprintf() error or output string was truncated. */
++ if (__pri_message) {
++ __pri_message(ctrl, truncated_output);
++ } else {
++ fputs(truncated_output, stdout);
++ }
++
++ /* Add a terminating '\n' to force a flush of the line. */
++ ctrl->msg_line->length = strlen(ctrl->msg_line->str);
++ if (ctrl->msg_line->length) {
++ ctrl->msg_line->str[ctrl->msg_line->length - 1] = '\n';
++ } else {
++ ctrl->msg_line->str[0] = '\n';
++ ctrl->msg_line->str[1] = '\0';
++ }
++ } else {
++ ctrl->msg_line->length += added_length;
++ }
++
++ if (ctrl->msg_line->length
++ && ctrl->msg_line->str[ctrl->msg_line->length - 1] == '\n') {
++ /* The accumulated output line was terminated so send it out. */
++ ctrl->msg_line->length = 0;
++ if (__pri_message) {
++ __pri_message(ctrl, ctrl->msg_line->str);
++ } else {
++ fputs(ctrl->msg_line->str, stdout);
++ }
++ }
++}
++
++void pri_error(struct pri *pri, const char *fmt, ...)
++{
+ char tmp[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(tmp, sizeof(tmp), fmt, ap);
+ va_end(ap);
+ if (__pri_error)
+- __pri_error(pri, tmp);
++ __pri_error(PRI_MASTER(pri), tmp);
+ else
+ fputs(tmp, stderr);
+ }
+@@ -821,49 +1235,102 @@
+ return pri->fd;
+ }
+
+-char *pri_dump_info_str(struct pri *pri)
++/*!
++ * \internal
++ * \brief Append snprintf output to the given buffer.
++ *
++ * \param buf Buffer currently filling.
++ * \param buf_used Offset into buffer where to put new stuff.
++ * \param buf_size Actual buffer size of buf.
++ * \param format printf format string.
++ *
++ * \return Total buffer space used.
++ */
++static size_t pri_snprintf(char *buf, size_t buf_used, size_t buf_size, const char *format, ...) __attribute__((format(printf, 4, 5)));
++static size_t pri_snprintf(char *buf, size_t buf_used, size_t buf_size, const char *format, ...)
+ {
+- char buf[4096];
+- int len = 0;
++ va_list args;
++
++ if (buf_used < buf_size) {
++ va_start(args, format);
++ buf_used += vsnprintf(buf + buf_used, buf_size - buf_used, format, args);
++ va_end(args);
++ }
++ if (buf_size < buf_used) {
++ buf_used = buf_size + 1;
++ }
++ return buf_used;
++}
++
++char *pri_dump_info_str(struct pri *ctrl)
++{
++ char *buf;
++ size_t buf_size;
++ size_t used;
+ #ifdef LIBPRI_COUNTERS
+ struct q921_frame *f;
+- int q921outstanding = 0;
++ unsigned q921outstanding;
+ #endif
+- if (!pri)
++ unsigned idx;
++ unsigned long switch_bit;
++
++ if (!ctrl) {
+ return NULL;
++ }
+
++ buf_size = 4096; /* This should be bigger than we will ever need. */
++ buf = malloc(buf_size);
++ if (!buf) {
++ return NULL;
++ }
++
+ /* Might be nice to format these a little better */
+- len += sprintf(buf + len, "Switchtype: %s\n", pri_switch2str(pri->switchtype));
+- len += sprintf(buf + len, "Type: %s\n", pri_node2str(pri->localtype));
++ used = 0;
++ used = pri_snprintf(buf, used, buf_size, "Switchtype: %s\n",
++ pri_switch2str(ctrl->switchtype));
++ used = pri_snprintf(buf, used, buf_size, "Type: %s\n", pri_node2str(ctrl->localtype));
+ #ifdef LIBPRI_COUNTERS
+ /* Remember that Q921 Counters include Q931 packets (and any retransmissions) */
+- len += sprintf(buf + len, "Q931 RX: %d\n", pri->q931_rxcount);
+- len += sprintf(buf + len, "Q931 TX: %d\n", pri->q931_txcount);
+- len += sprintf(buf + len, "Q921 RX: %d\n", pri->q921_rxcount);
+- len += sprintf(buf + len, "Q921 TX: %d\n", pri->q921_txcount);
+- f = pri->txqueue;
++ used = pri_snprintf(buf, used, buf_size, "Q931 RX: %d\n", ctrl->q931_rxcount);
++ used = pri_snprintf(buf, used, buf_size, "Q931 TX: %d\n", ctrl->q931_txcount);
++ used = pri_snprintf(buf, used, buf_size, "Q921 RX: %d\n", ctrl->q921_rxcount);
++ used = pri_snprintf(buf, used, buf_size, "Q921 TX: %d\n", ctrl->q921_txcount);
++ q921outstanding = 0;
++ f = ctrl->txqueue;
+ while (f) {
+ q921outstanding++;
+ f = f->next;
+ }
+- len += sprintf(buf + len, "Q921 Outstanding: %d\n", q921outstanding);
++ used = pri_snprintf(buf, used, buf_size, "Q921 Outstanding: %u\n", q921outstanding);
+ #endif
+- len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen, pri->window);
+- len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej);
+- len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit);
+- len += sprintf(buf + len, "Retrans: %d\n", pri->retrans);
+- len += sprintf(buf + len, "Busy: %d\n", pri->busy);
+- len += sprintf(buf + len, "Overlap Dial: %d\n", pri->overlapdial);
+- len += sprintf(buf + len, "Logical Channel Mapping: %d\n", pri->chan_mapping_logical);
+- len += sprintf(buf + len, "T200 Timer: %d\n", pri->timers[PRI_TIMER_T200]);
+- len += sprintf(buf + len, "T203 Timer: %d\n", pri->timers[PRI_TIMER_T203]);
+- len += sprintf(buf + len, "T305 Timer: %d\n", pri->timers[PRI_TIMER_T305]);
+- len += sprintf(buf + len, "T308 Timer: %d\n", pri->timers[PRI_TIMER_T308]);
+- len += sprintf(buf + len, "T309 Timer: %d\n", pri->timers[PRI_TIMER_T309]);
+- len += sprintf(buf + len, "T313 Timer: %d\n", pri->timers[PRI_TIMER_T313]);
+- len += sprintf(buf + len, "N200 Counter: %d\n", pri->timers[PRI_TIMER_N200]);
++ used = pri_snprintf(buf, used, buf_size, "Window Length: %d/%d\n", ctrl->windowlen,
++ ctrl->window);
++ used = pri_snprintf(buf, used, buf_size, "Sentrej: %d\n", ctrl->sentrej);
++ used = pri_snprintf(buf, used, buf_size, "SolicitFbit: %d\n", ctrl->solicitfbit);
++ used = pri_snprintf(buf, used, buf_size, "Retrans: %d\n", ctrl->retrans);
++ used = pri_snprintf(buf, used, buf_size, "Busy: %d\n", ctrl->busy);
++ used = pri_snprintf(buf, used, buf_size, "Overlap Dial: %d\n", ctrl->overlapdial);
++ used = pri_snprintf(buf, used, buf_size, "Logical Channel Mapping: %d\n",
++ ctrl->chan_mapping_logical);
++ used = pri_snprintf(buf, used, buf_size, "Timer and counter settings:\n");
++ switch_bit = PRI_BIT(ctrl->switchtype);
++ for (idx = 0; idx < ARRAY_LEN(pri_timer); ++idx) {
++ if (pri_timer[idx].used_by & switch_bit) {
++ enum PRI_TIMERS_AND_COUNTERS tmr;
+
+- return strdup(buf);
++ tmr = pri_timer[idx].number;
++ if (0 <= ctrl->timers[tmr] || tmr == PRI_TIMER_T309) {
++ used = pri_snprintf(buf, used, buf_size, " %s: %d\n",
++ pri_timer[idx].name, ctrl->timers[tmr]);
++ }
++ }
++ }
++
++ if (buf_size < used) {
++ pri_message(ctrl,
++ "pri_dump_info_str(): Produced output exceeded buffer capacity. (Truncated)\n");
++ }
++ return buf;
+ }
+
+ int pri_get_crv(struct pri *pri, q931_call *call, int *callmode)
+@@ -913,26 +1380,213 @@
+
+ int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int numcomplete)
+ {
+- sr->called = called;
+- sr->calledplan = calledplan;
++ q931_party_address_init(&sr->called);
++ if (called) {
++ sr->called.number.valid = 1;
++ sr->called.number.plan = calledplan;
++ libpri_copy_string(sr->called.number.str, called, sizeof(sr->called.number.str));
++ }
+ sr->numcomplete = numcomplete;
+ return 0;
+ }
+
++void pri_sr_set_called_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress)
++{
++ pri_copy_party_subaddress_to_q931(&sr->called.subaddress, subaddress);
++}
++
+ int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres)
+ {
+- sr->caller = caller;
+- sr->callername = callername;
+- sr->callerplan = callerplan;
+- sr->callerpres = callerpres;
++ q931_party_id_init(&sr->caller);
++ if (caller) {
++ sr->caller.number.valid = 1;
++ sr->caller.number.presentation = callerpres;
++ sr->caller.number.plan = callerplan;
++ libpri_copy_string(sr->caller.number.str, caller, sizeof(sr->caller.number.str));
++
++ if (callername) {
++ sr->caller.name.valid = 1;
++ sr->caller.name.presentation = callerpres;
++ sr->caller.name.char_set = PRI_CHAR_SET_ISO8859_1;
++ libpri_copy_string(sr->caller.name.str, callername,
++ sizeof(sr->caller.name.str));
++ }
++ }
+ return 0;
+ }
+
++void pri_sr_set_caller_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress)
++{
++ pri_copy_party_subaddress_to_q931(&sr->caller.subaddress, subaddress);
++}
++
++void pri_sr_set_caller_party(struct pri_sr *sr, const struct pri_party_id *caller)
++{
++ pri_copy_party_id_to_q931(&sr->caller, caller);
++}
++
+ int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason)
+ {
+- sr->redirectingnum = num;
+- sr->redirectingplan = plan;
+- sr->redirectingpres = pres;
+- sr->redirectingreason = reason;
++ q931_party_redirecting_init(&sr->redirecting);
++ if (num && num[0]) {
++ sr->redirecting.from.number.valid = 1;
++ sr->redirecting.from.number.presentation = pres;
++ sr->redirecting.from.number.plan = plan;
++ libpri_copy_string(sr->redirecting.from.number.str, num,
++ sizeof(sr->redirecting.from.number.str));
++
++ sr->redirecting.count = 1;
++ sr->redirecting.reason = reason;
++ }
+ return 0;
+ }
++
++void pri_sr_set_redirecting_parties(struct pri_sr *sr, const struct pri_party_redirecting *redirecting)
++{
++ pri_copy_party_id_to_q931(&sr->redirecting.from, &redirecting->from);
++ pri_copy_party_id_to_q931(&sr->redirecting.to, &redirecting->to);
++ pri_copy_party_id_to_q931(&sr->redirecting.orig_called, &redirecting->orig_called);
++ sr->redirecting.orig_reason = redirecting->orig_reason;
++ sr->redirecting.reason = redirecting->reason;
++ if (redirecting->count <= 0) {
++ if (sr->redirecting.from.number.valid) {
++ /*
++ * We are redirecting with an unknown count
++ * so assume the count is one.
++ */
++ sr->redirecting.count = 1;
++ } else {
++ sr->redirecting.count = 0;
++ }
++ } else if (redirecting->count < PRI_MAX_REDIRECTS) {
++ sr->redirecting.count = redirecting->count;
++ } else {
++ sr->redirecting.count = PRI_MAX_REDIRECTS;
++ }
++}
++
++void pri_sr_set_reversecharge(struct pri_sr *sr, int requested)
++{
++ sr->reversecharge = requested;
++}
++
++void pri_sr_set_keypad_digits(struct pri_sr *sr, const char *keypad_digits)
++{
++ sr->keypad_digits = keypad_digits;
++}
++
++void pri_hold_enable(struct pri *ctrl, int enable)
++{
++ ctrl = PRI_MASTER(ctrl);
++ if (ctrl) {
++ ctrl->hold_support = enable ? 1 : 0;
++ }
++}
++
++int pri_hold(struct pri *ctrl, q931_call *call)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_hold(ctrl, call);
++}
++
++int pri_hold_ack(struct pri *ctrl, q931_call *call)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_hold_ack(ctrl, call);
++}
++
++int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_hold_rej(ctrl, call, cause);
++}
++
++int pri_retrieve(struct pri *ctrl, q931_call *call, int channel)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_retrieve(ctrl, call, channel);
++}
++
++int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_retrieve_ack(ctrl, call, channel);
++}
++
++int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause)
++{
++ if (!ctrl || !call) {
++ return -1;
++ }
++ return q931_send_retrieve_rej(ctrl, call, cause);
++}
++
++int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason)
++{
++ if (!pri || !call || !dest)
++ return -1;
++
++ return qsig_cf_callrerouting(pri, call, dest, original, reason);
++}
++
++void pri_reroute_enable(struct pri *ctrl, int enable)
++{
++ ctrl = PRI_MASTER(ctrl);
++ if (ctrl) {
++ ctrl->deflection_support = enable ? 1 : 0;
++ }
++}
++
++int pri_reroute_call(struct pri *ctrl, q931_call *call, const struct pri_party_id *caller, const struct pri_party_redirecting *deflection, int subscription_option)
++{
++ const struct q931_party_id *caller_id;
++ struct q931_party_id local_caller;
++ struct q931_party_redirecting reroute;
++
++ if (!ctrl || !call || !deflection) {
++ return -1;
++ }
++
++ if (caller) {
++ /* Convert the caller update information. */
++ pri_copy_party_id_to_q931(&local_caller, caller);
++ q931_party_id_fixup(ctrl, &local_caller);
++ caller_id = &local_caller;
++ } else {
++ caller_id = NULL;
++ }
++
++ /* Convert the deflection information. */
++ q931_party_redirecting_init(&reroute);
++ pri_copy_party_id_to_q931(&reroute.from, &deflection->from);
++ q931_party_id_fixup(ctrl, &reroute.from);
++ pri_copy_party_id_to_q931(&reroute.to, &deflection->to);
++ q931_party_id_fixup(ctrl, &reroute.to);
++ pri_copy_party_id_to_q931(&reroute.orig_called, &deflection->orig_called);
++ q931_party_id_fixup(ctrl, &reroute.orig_called);
++ reroute.reason = deflection->reason;
++ reroute.orig_reason = deflection->orig_reason;
++ if (deflection->count <= 0) {
++ /*
++ * We are deflecting with an unknown count
++ * so assume the count is one.
++ */
++ reroute.count = 1;
++ } else if (deflection->count < PRI_MAX_REDIRECTS) {
++ reroute.count = deflection->count;
++ } else {
++ reroute.count = PRI_MAX_REDIRECTS;
++ }
++
++ return send_reroute_request(ctrl, call, caller_id, &reroute, subscription_option);
++}
+Index: Makefile
+===================================================================
+--- a/Makefile (.../tags/1.4.10.2) (revision 1357)
++++ b/Makefile (.../branches/1.4) (revision 1357)
+@@ -41,15 +41,55 @@
+
+ STATIC_LIBRARY=libpri.a
+ DYNAMIC_LIBRARY:=libpri.so.$(SONAME)
+-STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o version.o
+-DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo version.lo
+-CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS)
++STATIC_OBJS= \
++ copy_string.o \
++ pri.o \
++ q921.o \
++ prisched.o \
++ q931.o \
++ pri_facility.o \
++ asn1_primitive.o \
++ rose.o \
++ rose_address.o \
++ rose_etsi_aoc.o \
++ rose_etsi_diversion.o \
++ rose_etsi_ect.o \
++ rose_other.o \
++ rose_q931.o \
++ rose_qsig_aoc.o \
++ rose_qsig_ct.o \
++ rose_qsig_diversion.o \
++ rose_qsig_mwi.o \
++ rose_qsig_name.o \
++ version.o
++DYNAMIC_OBJS= \
++ copy_string.lo \
++ pri.lo \
++ q921.lo \
++ prisched.lo \
++ q931.lo \
++ pri_facility.lo \
++ asn1_primitive.lo \
++ rose.lo \
++ rose_address.lo \
++ rose_etsi_aoc.lo \
++ rose_etsi_diversion.lo \
++ rose_etsi_ect.lo \
++ rose_other.lo \
++ rose_q931.lo \
++ rose_qsig_aoc.lo \
++ rose_qsig_ct.lo \
++ rose_qsig_diversion.lo \
++ rose_qsig_mwi.lo \
++ rose_qsig_name.lo \
++ version.lo
++CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) $(LIBPRI_OPT)
+ INSTALL_PREFIX=$(DESTDIR)
+ INSTALL_BASE=/usr
+ libdir?=$(INSTALL_BASE)/lib
+ SOFLAGS:=-Wl,-h$(DYNAMIC_LIBRARY)
+ LDCONFIG = /sbin/ldconfig
+-ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX))
++ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX XGNUX))
+ LDCONFIG_FLAGS=-n
+ else
+ ifeq (${OSARCH},FreeBSD)
+@@ -74,7 +114,9 @@
+ #A ultrasparc cpu is really v9 but the stock debian stable 3.0 gcc doesnt support it.
+ ifeq ($(PROC),sparc64)
+ PROC=ultrasparc
+-CFLAGS += -mtune=$(PROC) -O3 -pipe -fomit-frame-pointer -mcpu=v8
++LIBPRI_OPT = -mtune=$(PROC) -O3 -pipe -fomit-frame-pointer -mcpu=v8
++else
++LIBPRI_OPT = -O2
+ endif
+
+ all: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY)
+@@ -132,6 +174,9 @@
+ pridump: pridump.o
+ $(CC) -o pridump pridump.o -L. -lpri $(CFLAGS)
+
++rosetest: rosetest.o
++ $(CC) -o rosetest rosetest.o -L. -lpri $(CFLAGS)
++
+ MAKE_DEPS= -MD -MT $@ -MF .$(subst /,_,$@).d -MP
+
+ %.o: %.c
+Index: q931.c
+===================================================================
+--- a/q931.c (.../tags/1.4.10.2) (revision 1357)
++++ b/q931.c (.../branches/1.4) (revision 1357)
+@@ -33,6 +33,7 @@
+ #include "pri_q921.h"
+ #include "pri_q931.h"
+ #include "pri_facility.h"
++#include "rose.h"
+
+ #include <unistd.h>
+ #include <stdlib.h>
+@@ -67,7 +68,7 @@
+ { Q931_RESTART_ACKNOWLEDGE, "RESTART ACKNOWLEDGE", { Q931_RESTART_INDICATOR } },
+
+ /* Miscellaneous */
+- { Q931_STATUS, "STATUS", { Q931_CAUSE, Q931_CALL_STATE } },
++ { Q931_STATUS, "STATUS", { Q931_CAUSE, Q931_IE_CALL_STATE } },
+ { Q931_STATUS_ENQUIRY, "STATUS ENQUIRY" },
+ { Q931_USER_INFORMATION, "USER_INFORMATION" },
+ { Q931_SEGMENT, "SEGMENT" },
+@@ -79,22 +80,32 @@
+ /* Call Management */
+ { Q931_HOLD, "HOLD" },
+ { Q931_HOLD_ACKNOWLEDGE, "HOLD ACKNOWLEDGE" },
+- { Q931_HOLD_REJECT, "HOLD REJECT" },
++ { Q931_HOLD_REJECT, "HOLD REJECT", { Q931_CAUSE } },
+ { Q931_RETRIEVE, "RETRIEVE" },
+ { Q931_RETRIEVE_ACKNOWLEDGE, "RETRIEVE ACKNOWLEDGE" },
+- { Q931_RETRIEVE_REJECT, "RETRIEVE REJECT" },
++ { Q931_RETRIEVE_REJECT, "RETRIEVE REJECT", { Q931_CAUSE } },
+ { Q931_RESUME, "RESUME" },
+ { Q931_RESUME_ACKNOWLEDGE, "RESUME ACKNOWLEDGE", { Q931_CHANNEL_IDENT } },
+ { Q931_RESUME_REJECT, "RESUME REJECT", { Q931_CAUSE } },
+ { Q931_SUSPEND, "SUSPEND" },
+ { Q931_SUSPEND_ACKNOWLEDGE, "SUSPEND ACKNOWLEDGE" },
+ { Q931_SUSPEND_REJECT, "SUSPEND REJECT" },
++};
+
+- /* Maintenance */
+- { NATIONAL_SERVICE, "SERVICE" },
+- { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE" },
++static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand);
++static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int *allow_event, int *allow_posthandle);
++
++struct msgtype att_maintenance_msgs[] = {
++ { ATT_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } },
++ { ATT_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } },
+ };
+
++struct msgtype national_maintenance_msgs[] = {
++ { NATIONAL_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } },
++ { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } },
++};
++static int post_handle_maintenance_message(struct pri *ctrl, int protodisc, struct q931_mh *mh, struct q931_call *c);
++
+ static struct msgtype causes[] = {
+ { PRI_CAUSE_UNALLOCATED, "Unallocated (unassigned) number" },
+ { PRI_CAUSE_NO_ROUTE_TRANSIT_NET, "No route to specified transmit network" },
+@@ -107,6 +118,7 @@
+ { PRI_CAUSE_NO_ANSWER, "User alerting, no answer" },
+ { PRI_CAUSE_CALL_REJECTED, "Call Rejected" },
+ { PRI_CAUSE_NUMBER_CHANGED, "Number changed" },
++ { PRI_CAUSE_NONSELECTED_USER_CLEARING, "Non-selected user clearing" },
+ { PRI_CAUSE_DESTINATION_OUT_OF_ORDER, "Destination out of order" },
+ { PRI_CAUSE_INVALID_NUMBER_FORMAT, "Invalid number format" },
+ { PRI_CAUSE_FACILITY_REJECTED, "Facility rejected" },
+@@ -119,13 +131,14 @@
+ { PRI_CAUSE_ACCESS_INFO_DISCARDED, "Access information discarded" },
+ { PRI_CAUSE_REQUESTED_CHAN_UNAVAIL, "Requested channel not available" },
+ { PRI_CAUSE_PRE_EMPTED, "Pre-empted" },
++ { PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED, "Resource unavailable, unspecified" },
+ { PRI_CAUSE_FACILITY_NOT_SUBSCRIBED, "Facility not subscribed" },
+ { PRI_CAUSE_OUTGOING_CALL_BARRED, "Outgoing call barred" },
+ { PRI_CAUSE_INCOMING_CALL_BARRED, "Incoming call barred" },
+ { PRI_CAUSE_BEARERCAPABILITY_NOTAUTH, "Bearer capability not authorized" },
+ { PRI_CAUSE_BEARERCAPABILITY_NOTAVAIL, "Bearer capability not available" },
++ { PRI_CAUSE_SERVICEOROPTION_NOTAVAIL, "Service or option not available, unspecified" },
+ { PRI_CAUSE_BEARERCAPABILITY_NOTIMPL, "Bearer capability not implemented" },
+- { PRI_CAUSE_SERVICEOROPTION_NOTAVAIL, "Service or option not available, unspecified" },
+ { PRI_CAUSE_CHAN_NOT_IMPLEMENTED, "Channel not implemented" },
+ { PRI_CAUSE_FACILITY_NOT_IMPLEMENTED, "Facility not implemented" },
+ { PRI_CAUSE_INVALID_CALL_REFERENCE, "Invalid call reference value" },
+@@ -163,8 +176,9 @@
+ { PRI_NSF_CALL_REDIRECTION_SERVICE, "Call Redirection Service" }
+ };
+
+-#define FLAG_PREFERRED 2
+-#define FLAG_EXCLUSIVE 4
++#define FLAG_WHOLE_INTERFACE 0x01
++#define FLAG_PREFERRED 0x02
++#define FLAG_EXCLUSIVE 0x04
+
+ #define RESET_INDICATOR_CHANNEL 0
+ #define RESET_INDICATOR_DS1 6
+@@ -214,26 +228,49 @@
+ #define LOC_NETWORK_BEYOND_INTERWORKING 0xa
+
+ static char *ie2str(int ie);
+-static char *msg2str(int msg);
+
+
+-#define FUNC_DUMP(name) void ((name))(int full_ie, struct pri *pri, q931_ie *ie, int len, char prefix)
+-#define FUNC_RECV(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
+-#define FUNC_SEND(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++#define FUNC_DUMP(name) void (name)(int full_ie, struct pri *pri, q931_ie *ie, int len, char prefix)
++#define FUNC_RECV(name) int (name)(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len)
++#define FUNC_SEND(name) int (name)(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+
+ #if 1
+ /* Update call state with transition trace. */
+-#define UPDATE_OURCALLSTATE(pri,c,newstate) do {\
+- if (pri->debug & (PRI_DEBUG_Q931_STATE) && c->ourcallstate != newstate) \
+- pri_message(pri, DBGHEAD "call %d on channel %d enters state %d (%s)\n", DBGINFO, \
+- c->cr, c->channelno, newstate, callstate2str(newstate)); \
+- c->ourcallstate = newstate; \
++#define UPDATE_OURCALLSTATE(ctrl, call, newstate) \
++ do { \
++ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) && (call)->ourcallstate != (newstate)) { \
++ pri_message((ctrl), \
++ DBGHEAD "%s %d enters state %d (%s). Hold state: %s\n", \
++ DBGINFO, ((call) == (call)->master_call) ? "Call" : "Subcall", \
++ (call)->cr, (newstate), q931_call_state_str(newstate), \
++ q931_hold_state_str((call)->master_call->hold_state)); \
++ } \
++ (call)->ourcallstate = (newstate); \
+ } while (0)
+ #else
+ /* Update call state with no trace. */
+-#define UPDATE_OURCALLSTATE(pri,c,newstate) c->ourcallstate = newstate
++#define UPDATE_OURCALLSTATE(ctrl, call, newstate) (call)->ourcallstate = (newstate)
+ #endif
+
++#if 1
++/* Update hold state with transition trace. */
++#define UPDATE_HOLD_STATE(ctrl, master_call, newstate) \
++ do { \
++ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) \
++ && (master_call)->hold_state != (newstate)) { \
++ pri_message((ctrl), \
++ DBGHEAD "Call %d in state %d (%s) enters Hold state: %s\n", \
++ DBGINFO, (master_call)->cr, (master_call)->ourcallstate, \
++ q931_call_state_str((master_call)->ourcallstate), \
++ q931_hold_state_str(newstate)); \
++ } \
++ (master_call)->hold_state = (newstate); \
++ } while (0)
++#else
++/* Update hold state with no trace. */
++#define UPDATE_HOLD_STATE(ctrl, master_call, newstate) (master_call)->hold_state = (newstate)
++#endif
++
+ struct ie {
+ /* Maximal count of same IEs at the message (0 - any, 1..n - limited) */
+ int max_count;
+@@ -249,6 +286,506 @@
+ FUNC_SEND(*transmit);
+ };
+
++/*!
++ * \internal
++ * \brief Encode the channel id information to pass to upper level.
++ *
++ * \param call Q.931 call leg
++ *
++ * \return Encoded channel value.
++ */
++static int q931_encode_channel(const q931_call *call)
++{
++ int held_call;
++ int channelno;
++ int ds1no;
++
++ switch (call->master_call->hold_state) {
++ case Q931_HOLD_STATE_CALL_HELD:
++ case Q931_HOLD_STATE_RETRIEVE_REQ:
++ case Q931_HOLD_STATE_RETRIEVE_IND:
++ held_call = 1 << 18;
++
++ /* So a -1 does not wipe out the held_call flag. */
++ channelno = call->channelno & 0xFF;
++ ds1no = call->ds1no & 0xFF;
++ break;
++ default:
++ held_call = 0;
++ channelno = call->channelno;
++ ds1no = call->ds1no;
++ break;
++ }
++ return channelno | (ds1no << 8) | (call->ds1explicit << 16) | (call->cis_call << 17)
++ | held_call;
++}
++
++/*!
++ * \brief Determine if layer 2 is in PTMP mode.
++ *
++ * \param ctrl D channel controller.
++ *
++ * \retval TRUE if in PTMP mode.
++ * \retval FALSE otherwise.
++ */
++int q931_is_ptmp(const struct pri *ctrl)
++{
++ /* Check master control structure */
++ for (; ctrl->master; ctrl = ctrl->master) {
++ }
++ return ctrl->tei == Q921_TEI_GROUP;
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_name
++ *
++ * \param name Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_name_init(struct q931_party_name *name)
++{
++ name->valid = 0;
++ name->presentation = PRI_PRES_UNAVAILABLE;
++ name->char_set = PRI_CHAR_SET_ISO8859_1;
++ name->str[0] = '\0';
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_number
++ *
++ * \param number Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_number_init(struct q931_party_number *number)
++{
++ number->valid = 0;
++ number->presentation = PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED;
++ number->plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
++ number->str[0] = '\0';
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_subaddress
++ *
++ * \param subaddress Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_subaddress_init(struct q931_party_subaddress *subaddress)
++{
++ subaddress->valid = 0;
++ subaddress->type = 0;
++ subaddress->odd_even_indicator = 0;
++ subaddress->length = 0;
++ subaddress->data[0] = '\0';
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_address
++ *
++ * \param address Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_address_init(struct q931_party_address *address)
++{
++ q931_party_number_init(&address->number);
++ q931_party_subaddress_init(&address->subaddress);
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_id
++ *
++ * \param id Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_id_init(struct q931_party_id *id)
++{
++ q931_party_name_init(&id->name);
++ q931_party_number_init(&id->number);
++ q931_party_subaddress_init(&id->subaddress);
++}
++
++/*!
++ * \brief Initialize the given struct q931_party_redirecting
++ *
++ * \param redirecting Structure to initialize
++ *
++ * \return Nothing
++ */
++void q931_party_redirecting_init(struct q931_party_redirecting *redirecting)
++{
++ q931_party_id_init(&redirecting->from);
++ q931_party_id_init(&redirecting->to);
++ q931_party_id_init(&redirecting->orig_called);
++ redirecting->state = Q931_REDIRECTING_STATE_IDLE;
++ redirecting->count = 0;
++ redirecting->orig_reason = PRI_REDIR_UNKNOWN;
++ redirecting->reason = PRI_REDIR_UNKNOWN;
++}
++
++/*!
++ * \brief Compare the left and right party name.
++ *
++ * \param left Left parameter party name.
++ * \param right Right parameter party name.
++ *
++ * \retval < 0 when left < right.
++ * \retval == 0 when left == right.
++ * \retval > 0 when left > right.
++ */
++int q931_party_name_cmp(const struct q931_party_name *left, const struct q931_party_name *right)
++{
++ int cmp;
++
++ if (!left->valid) {
++ if (!right->valid) {
++ return 0;
++ }
++ return -1;
++ } else if (!right->valid) {
++ return 1;
++ }
++ cmp = left->char_set - right->char_set;
++ if (cmp) {
++ return cmp;
++ }
++ cmp = strcmp(left->str, right->str);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = left->presentation - right->presentation;
++ return cmp;
++}
++
++/*!
++ * \brief Compare the left and right party number.
++ *
++ * \param left Left parameter party number.
++ * \param right Right parameter party number.
++ *
++ * \retval < 0 when left < right.
++ * \retval == 0 when left == right.
++ * \retval > 0 when left > right.
++ */
++int q931_party_number_cmp(const struct q931_party_number *left, const struct q931_party_number *right)
++{
++ int cmp;
++
++ if (!left->valid) {
++ if (!right->valid) {
++ return 0;
++ }
++ return -1;
++ } else if (!right->valid) {
++ return 1;
++ }
++ cmp = left->plan - right->plan;
++ if (cmp) {
++ return cmp;
++ }
++ cmp = strcmp(left->str, right->str);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = left->presentation - right->presentation;
++ return cmp;
++}
++
++/*!
++ * \brief Compare the left and right party subaddress.
++ *
++ * \param left Left parameter party subaddress.
++ * \param right Right parameter party subaddress.
++ *
++ * \retval < 0 when left < right.
++ * \retval == 0 when left == right.
++ * \retval > 0 when left > right.
++ */
++int q931_party_subaddress_cmp(const struct q931_party_subaddress *left, const struct q931_party_subaddress *right)
++{
++ int cmp;
++
++ if (!left->valid) {
++ if (!right->valid) {
++ return 0;
++ }
++ return -1;
++ } else if (!right->valid) {
++ return 1;
++ }
++ cmp = left->type - right->type;
++ if (cmp) {
++ return cmp;
++ }
++ cmp = memcmp(left->data, right->data,
++ (left->length < right->length) ? left->length : right->length);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = left->length - right->length;
++ if (cmp) {
++ return cmp;
++ }
++ cmp = left->odd_even_indicator - right->odd_even_indicator;
++ return cmp;
++}
++
++/*!
++ * \brief Compare the left and right party id.
++ *
++ * \param left Left parameter party id.
++ * \param right Right parameter party id.
++ *
++ * \retval < 0 when left < right.
++ * \retval == 0 when left == right.
++ * \retval > 0 when left > right.
++ */
++int q931_party_id_cmp(const struct q931_party_id *left, const struct q931_party_id *right)
++{
++ int cmp;
++
++ cmp = q931_party_number_cmp(&left->number, &right->number);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = q931_party_subaddress_cmp(&left->subaddress, &right->subaddress);
++ if (cmp) {
++ return cmp;
++ }
++ cmp = q931_party_name_cmp(&left->name, &right->name);
++ return cmp;
++}
++
++/*!
++ * \brief Copy the Q.931 party name to the PRI party name structure.
++ *
++ * \param pri_name PRI party name structure
++ * \param q931_name Q.931 party name structure
++ *
++ * \return Nothing
++ */
++void q931_party_name_copy_to_pri(struct pri_party_name *pri_name, const struct q931_party_name *q931_name)
++{
++ if (q931_name->valid) {
++ pri_name->valid = 1;
++ pri_name->presentation = q931_name->presentation;
++ pri_name->char_set = q931_name->char_set;
++ libpri_copy_string(pri_name->str, q931_name->str, sizeof(pri_name->str));
++ } else {
++ pri_name->valid = 0;
++ pri_name->presentation = PRI_PRES_UNAVAILABLE;
++ pri_name->char_set = PRI_CHAR_SET_ISO8859_1;
++ pri_name->str[0] = 0;
++ }
++}
++
++/*!
++ * \brief Copy the Q.931 party number to the PRI party number structure.
++ *
++ * \param pri_number PRI party number structure
++ * \param q931_number Q.931 party number structure
++ *
++ * \return Nothing
++ */
++void q931_party_number_copy_to_pri(struct pri_party_number *pri_number, const struct q931_party_number *q931_number)
++{
++ if (q931_number->valid) {
++ pri_number->valid = 1;
++ pri_number->presentation = q931_number->presentation;
++ pri_number->plan = q931_number->plan;
++ libpri_copy_string(pri_number->str, q931_number->str, sizeof(pri_number->str));
++ } else {
++ pri_number->valid = 0;
++ pri_number->presentation = PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED;
++ pri_number->plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164;
++ pri_number->str[0] = 0;
++ }
++}
++
++/*!
++ * \brief Copy the Q.931 party subaddress to the PRI party subaddress structure.
++ *
++ * \param pri_subaddress PRI party subaddress structure
++ * \param q931_subaddress Q.931 party subaddress structure
++ *
++ * \return Nothing
++ */
++void q931_party_subaddress_copy_to_pri(struct pri_party_subaddress *pri_subaddress, const struct q931_party_subaddress *q931_subaddress)
++{
++ int length;
++
++ /*
++ * The size of pri_subaddress->data[] is not the same as the size of
++ * q931_subaddress->data[].
++ */
++
++ if (!q931_subaddress->valid) {
++ pri_subaddress->valid = 0;
++ pri_subaddress->type = 0;
++ pri_subaddress->odd_even_indicator = 0;
++ pri_subaddress->length = 0;
++ pri_subaddress->data[0] = '\0';
++ return;
++ }
++
++ pri_subaddress->valid = 1;
++ pri_subaddress->type = q931_subaddress->type;
++ pri_subaddress->odd_even_indicator = q931_subaddress->odd_even_indicator;
++
++ length = q931_subaddress->length;
++ pri_subaddress->length = length;
++ memcpy(pri_subaddress->data, q931_subaddress->data, length);
++ pri_subaddress->data[length] = '\0';
++}
++
++/*!
++ * \brief Copy the Q.931 party id to the PRI party id structure.
++ *
++ * \param pri_id PRI party id structure
++ * \param q931_id Q.931 party id structure
++ *
++ * \return Nothing
++ */
++void q931_party_id_copy_to_pri(struct pri_party_id *pri_id, const struct q931_party_id *q931_id)
++{
++ q931_party_name_copy_to_pri(&pri_id->name, &q931_id->name);
++ q931_party_number_copy_to_pri(&pri_id->number, &q931_id->number);
++ q931_party_subaddress_copy_to_pri(&pri_id->subaddress, &q931_id->subaddress);
++}
++
++/*!
++ * \brief Copy the Q.931 redirecting data to the PRI redirecting structure.
++ *
++ * \param pri_redirecting PRI redirecting structure
++ * \param q931_redirecting Q.931 redirecting structure
++ *
++ * \return Nothing
++ */
++void q931_party_redirecting_copy_to_pri(struct pri_party_redirecting *pri_redirecting, const struct q931_party_redirecting *q931_redirecting)
++{
++ q931_party_id_copy_to_pri(&pri_redirecting->from, &q931_redirecting->from);
++ q931_party_id_copy_to_pri(&pri_redirecting->to, &q931_redirecting->to);
++ q931_party_id_copy_to_pri(&pri_redirecting->orig_called,
++ &q931_redirecting->orig_called);
++ pri_redirecting->count = q931_redirecting->count;
++ pri_redirecting->orig_reason = q931_redirecting->orig_reason;
++ pri_redirecting->reason = q931_redirecting->reason;
++}
++
++/*!
++ * \brief Fixup some values in the q931_party_id that may be objectionable by switches.
++ *
++ * \param ctrl D channel controller.
++ * \param id Party ID to tweak.
++ *
++ * \return Nothing
++ */
++void q931_party_id_fixup(const struct pri *ctrl, struct q931_party_id *id)
++{
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_DMS100:
++ case PRI_SWITCH_ATT4ESS:
++ /* Doesn't like certain presentation types */
++ if (id->number.valid && !(id->number.presentation & 0x7c)) {
++ /* i.e., If presentation is allowed it must be a network number */
++ id->number.presentation = PRES_ALLOWED_NETWORK_NUMBER;
++ }
++ break;
++ default:
++ break;
++ }
++}
++
++/*!
++ * \brief Determine the overall presentation value for the given party.
++ *
++ * \param id Party to determine the overall presentation value.
++ *
++ * \return Overall presentation value for the given party.
++ */
++int q931_party_id_presentation(const struct q931_party_id *id)
++{
++ int number_priority;
++ int number_value;
++ int number_screening;
++ int name_priority;
++ int name_value;
++
++ /* Determine name presentation priority. */
++ if (!id->name.valid) {
++ name_value = PRI_PRES_UNAVAILABLE;
++ name_priority = 3;
++ } else {
++ name_value = id->name.presentation & PRI_PRES_RESTRICTION;
++ switch (name_value) {
++ case PRI_PRES_RESTRICTED:
++ name_priority = 0;
++ break;
++ case PRI_PRES_ALLOWED:
++ name_priority = 1;
++ break;
++ case PRI_PRES_UNAVAILABLE:
++ name_priority = 2;
++ break;
++ default:
++ name_value = PRI_PRES_UNAVAILABLE;
++ name_priority = 3;
++ break;
++ }
++ }
++
++ /* Determine number presentation priority. */
++ if (!id->number.valid) {
++ number_screening = PRI_PRES_USER_NUMBER_UNSCREENED;
++ number_value = PRI_PRES_UNAVAILABLE;
++ number_priority = 3;
++ } else {
++ number_screening = id->number.presentation & PRI_PRES_NUMBER_TYPE;
++ number_value = id->number.presentation & PRI_PRES_RESTRICTION;
++ switch (number_value) {
++ case PRI_PRES_RESTRICTED:
++ number_priority = 0;
++ break;
++ case PRI_PRES_ALLOWED:
++ number_priority = 1;
++ break;
++ case PRI_PRES_UNAVAILABLE:
++ number_priority = 2;
++ break;
++ default:
++ number_screening = PRI_PRES_USER_NUMBER_UNSCREENED;
++ number_value = PRI_PRES_UNAVAILABLE;
++ number_priority = 3;
++ break;
++ }
++ }
++
++ /* Select the wining presentation value. */
++ if (name_priority < number_priority) {
++ number_value = name_value;
++ }
++
++ return number_value | number_screening;
++}
++
++static void q931_clr_subcommands(struct pri *ctrl)
++{
++ ctrl->subcmds.counter_subcmd = 0;
++}
++
++struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl)
++{
++ if (ctrl->subcmds.counter_subcmd < PRI_MAX_SUBCOMMANDS) {
++ return &ctrl->subcmds.subcmd[ctrl->subcmds.counter_subcmd++];
++ }
++
++ return NULL;
++}
++
+ static char *code2str(int code, struct msgtype *codes, int max)
+ {
+ int x;
+@@ -258,15 +795,18 @@
+ return "Unknown";
+ }
+
+-static void call_init(struct q931_call *c)
++static char *pritype(int type)
+ {
+- c->forceinvert = -1;
+- c->cr = -1;
+- c->slotmap = -1;
+- c->channelno = -1;
+- c->newcall = 1;
+- c->ourcallstate = Q931_CALL_STATE_NULL;
+- c->peercallstate = Q931_CALL_STATE_NULL;
++ switch (type) {
++ case PRI_CPE:
++ return "CPE";
++ break;
++ case PRI_NETWORK:
++ return "NET";
++ break;
++ default:
++ return "UNKNOWN";
++ }
+ }
+
+ static char *binary(int b, int len) {
+@@ -280,56 +820,85 @@
+ return res;
+ }
+
+-static FUNC_RECV(receive_channel_id)
++static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ int x;
+- int pos=0;
+-#ifdef NO_BRI_SUPPORT
+- if (!ie->data[0] & 0x20) {
+- pri_error(pri, "!! Not PRI type!?\n");
+- return -1;
+- }
+-#endif
+-#ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT
+- if (pri->bri) {
+- if (!(ie->data[0] & 3))
+- call->justsignalling = 1;
+- else
+- call->channelno = ie->data[0] & 3;
++ int pos = 0;
++ int need_extended_channel_octets;/*!< TRUE if octets 3.2 and 3.3 need to be present. */
++
++ if (ie->data[0] & 0x08) {
++ call->chanflags = FLAG_EXCLUSIVE;
+ } else {
+- switch (ie->data[0] & 3) {
+- case 0:
+- call->justsignalling = 1;
+- break;
+- case 1:
+- break;
+- default:
+- pri_error(pri, "!! Unexpected Channel selection %d\n", ie->data[0] & 3);
+- return -1;
++ call->chanflags = FLAG_PREFERRED;
++ }
++
++ need_extended_channel_octets = 0;
++ if (ie->data[0] & 0x20) {
++ /* PRI encoded interface type */
++ switch (ie->data[0] & 0x03) {
++ case 0x00:
++ /* No channel */
++ call->channelno = 0;
++ call->chanflags = FLAG_PREFERRED;
++ break;
++ case 0x01:
++ /* As indicated in following octets */
++ need_extended_channel_octets = 1;
++ break;
++ case 0x03:
++ /* Any channel */
++ call->chanflags = FLAG_PREFERRED;
++ break;
++ default:
++ pri_error(ctrl, "!! Unexpected Channel selection %d\n", ie->data[0] & 0x03);
++ return -1;
+ }
++ } else {
++ /* BRI encoded interface type */
++ switch (ie->data[0] & 0x03) {
++ case 0x00:
++ /* No channel */
++ call->channelno = 0;
++ call->chanflags = FLAG_PREFERRED;
++ break;
++ case 0x03:
++ /* Any channel */
++ call->chanflags = FLAG_PREFERRED;
++ break;
++ default:
++ /* Specified B channel (B1 or B2) */
++ call->channelno = ie->data[0] & 0x03;
++ break;
++ }
+ }
+-#endif
+- if (ie->data[0] & 0x08)
+- call->chanflags = FLAG_EXCLUSIVE;
+- else
+- call->chanflags = FLAG_PREFERRED;
++
+ pos++;
+ if (ie->data[0] & 0x40) {
+ /* DS1 specified -- stop here */
+ call->ds1no = ie->data[1] & 0x7f;
+ call->ds1explicit = 1;
+ pos++;
+- } else
++ } else {
+ call->ds1explicit = 0;
++ }
+
+- if (pos+2 < len) {
++ if (ie->data[0] & 0x04) {
++ /* D channel call. Signaling only. */
++ call->cis_call = 1;
++ call->chanflags = FLAG_EXCLUSIVE;/* For safety mark this channel as exclusive. */
++ call->channelno = 0;
++ return 0;
++ }
++
++ if (need_extended_channel_octets && pos + 2 < len) {
+ /* More coming */
+ if ((ie->data[pos] & 0x0f) != 3) {
+- pri_error(pri, "!! Unexpected Channel Type %d\n", ie->data[1] & 0x0f);
++ /* Channel type/mapping is not for B channel units. */
++ pri_error(ctrl, "!! Unexpected Channel Type %d\n", ie->data[1] & 0x0f);
+ return -1;
+ }
+ if ((ie->data[pos] & 0x60) != 0) {
+- pri_error(pri, "!! Invalid CCITT coding %d\n", (ie->data[1] & 0x60) >> 5);
++ pri_error(ctrl, "!! Invalid CCITT coding %d\n", (ie->data[1] & 0x60) >> 5);
+ return -1;
+ }
+ if (ie->data[pos] & 0x10) {
+@@ -340,136 +909,167 @@
+ call->slotmap <<= 8;
+ call->slotmap |= ie->data[x + pos];
+ }
+- return 0;
+ } else {
+ pos++;
+ /* Only expect a particular channel */
+ call->channelno = ie->data[pos] & 0x7f;
+- if (pri->chan_mapping_logical && call->channelno > 15)
++ if (ctrl->chan_mapping_logical && call->channelno > 15)
+ call->channelno++;
+- return 0;
+ }
+- } else
+- return 0;
+- return -1;
++ }
++ return 0;
+ }
+
+-static FUNC_SEND(transmit_channel_id)
++static int transmit_channel_id(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- int pos=0;
++ int pos = 0;
+
+-
+ /* We are ready to transmit single IE only */
+ if (order > 1)
+ return 0;
+-
+- if (call->justsignalling) {
+- ie->data[pos++] = 0xac; /* Read the standards docs to figure this out
+- ECMA-165 section 7.3 */
++
++ if (call->cis_call) {
++ /*
++ * Read the standards docs to figure this out.
++ * Q.SIG ECMA-165 section 7.3
++ * ITU Q.931 section 4.5.13
++ */
++ ie->data[pos++] = ctrl->bri ? 0x8c : 0xac;
+ return pos + 2;
+ }
+-
++
+ /* Start with standard stuff */
+- if (pri->switchtype == PRI_SWITCH_GR303_TMC)
++ if (ctrl->switchtype == PRI_SWITCH_GR303_TMC)
+ ie->data[pos] = 0x69;
+- else if (pri->bri) {
++ else if (ctrl->bri) {
+ ie->data[pos] = 0x80;
+- if (call->channelno > -1)
+- ie->data[pos] |= (call->channelno & 0x3);
+- } else
+- ie->data[pos] = 0xa1;
+- /* Add exclusive flag if necessary */
+- if (call->chanflags & FLAG_EXCLUSIVE)
++ ie->data[pos] |= (call->channelno & 0x3);
++ } else {
++ /* PRI */
++ if (call->slotmap != -1 || (call->chanflags & FLAG_WHOLE_INTERFACE)) {
++ /* Specified channel */
++ ie->data[pos] = 0xa1;
++ } else if (call->channelno < 0 || call->channelno == 0xff) {
++ /* Any channel */
++ ie->data[pos] = 0xa3;
++ } else if (!call->channelno) {
++ /* No channel */
++ ie->data[pos] = 0xa0;
++ } else {
++ /* Specified channel */
++ ie->data[pos] = 0xa1;
++ }
++ }
++ if (call->chanflags & FLAG_EXCLUSIVE) {
++ /* Channel is exclusive */
+ ie->data[pos] |= 0x08;
+- else if (!(call->chanflags & FLAG_PREFERRED)) {
++ } else if (!call->chanflags) {
+ /* Don't need this IE */
+ return 0;
+ }
+
+- if (((pri->switchtype != PRI_SWITCH_QSIG) && (call->ds1no > 0)) || call->ds1explicit) {
+- /* Note that we are specifying the identifier */
++ if (!ctrl->bri && (((ctrl->switchtype != PRI_SWITCH_QSIG) && (call->ds1no > 0)) || call->ds1explicit)) {
++ /* We are specifying the interface. Octet 3.1 */
+ ie->data[pos++] |= 0x40;
+- /* We need to use the Channel Identifier Present thingy. Just specify it and we're done */
+ ie->data[pos++] = 0x80 | call->ds1no;
+- } else
+- pos++;
++ } else {
++ ++pos;
++ }
+
+- if (pri->bri)
+- return pos + 2;
++ if (!ctrl->bri && (ie->data[0] & 0x03) == 0x01 /* Specified channel */
++ && !(call->chanflags & FLAG_WHOLE_INTERFACE)) {
++ /* The 3.2 and 3.3 octets need to be present */
++ ie->data[pos] = 0x83;
++ if (call->slotmap != -1) {
++ int octet;
+
+- if ((call->channelno > -1) || (call->slotmap != -1)) {
+- /* We'll have the octet 8.2 and 8.3's present */
+- ie->data[pos++] = 0x83;
+- if (call->channelno > -1) {
++ /* We have to send a channel map */
++ ie->data[pos++] |= 0x10;
++ for (octet = 3; octet--;) {
++ ie->data[pos++] = (call->slotmap >> (8 * octet)) & 0xff;
++ }
++ } else {
+ /* Channel number specified */
+- if (pri->chan_mapping_logical && call->channelno > 16)
++ ++pos;
++ if (ctrl->chan_mapping_logical && call->channelno > 16) {
+ ie->data[pos++] = 0x80 | (call->channelno - 1);
+- else
++ } else {
+ ie->data[pos++] = 0x80 | call->channelno;
+- return pos + 2;
++ }
+ }
+- /* We have to send a channel map */
+- if (call->slotmap != -1) {
+- ie->data[pos-1] |= 0x10;
+- ie->data[pos++] = (call->slotmap & 0xff0000) >> 16;
+- ie->data[pos++] = (call->slotmap & 0xff00) >> 8;
+- ie->data[pos++] = (call->slotmap & 0xff);
+- return pos + 2;
+- }
+ }
+- if (call->ds1no > 0) {
+- /* We're done */
+- return pos + 2;
+- }
+- pri_error(pri, "!! No channel map, no channel, and no ds1? What am I supposed to identify?\n");
+- return -1;
++
++ return pos + 2;
+ }
+
+-static FUNC_DUMP(dump_channel_id)
++static void dump_channel_id(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- int pos=0;
++ int pos;
+ int x;
+- int res = 0;
+- static const char* msg_chan_sel[] = {
+- "No channel selected", "B1 channel", "B2 channel","Any channel selected",
+- "No channel selected", "As indicated in following octets", "Reserved","Any channel selected"
++ int res;
++
++ static const char *msg_chan_sel[] = {
++ "No channel selected", "B1 channel", "B2 channel", "Any channel selected",
++ "No channel selected", "As indicated in following octets", "Reserved", "Any channel selected"
+ };
+
+- pri_message(pri, "%c Channel ID (len=%2d) [ Ext: %d IntID: %s %s Spare: %d %s Dchan: %d\n",
+- prefix, len, (ie->data[0] & 0x80) ? 1 : 0, (ie->data[0] & 0x40) ? "Explicit" : "Implicit",
+- (ie->data[0] & 0x20) ? "PRI" : "Other", (ie->data[0] & 0x10) ? 1 : 0,
+- (ie->data[0] & 0x08) ? "Exclusive" : "Preferred", (ie->data[0] & 0x04) ? 1 : 0);
+- pri_message(pri, "%c ChanSel: %s\n",
+- prefix, msg_chan_sel[(ie->data[0] & 0x3) + ((ie->data[0]>>3) & 0x4)]);
+- pos++;
+- len--;
+- if (ie->data[0] & 0x40) {
++ pri_message(ctrl,
++ "%c Channel ID (len=%2d) [ Ext: %d IntID: %s %s Spare: %d %s Dchan: %d\n",
++ prefix, len,
++ (ie->data[0] & 0x80) ? 1 : 0,
++ (ie->data[0] & 0x40) ? "Explicit" : "Implicit",
++ (ie->data[0] & 0x20) ? "Other(PRI)" : "BRI",
++ (ie->data[0] & 0x10) ? 1 : 0,
++ (ie->data[0] & 0x08) ? "Exclusive" : "Preferred",
++ (ie->data[0] & 0x04) ? 1 : 0);
++ pri_message(ctrl, "%c ChanSel: %s\n",
++ prefix, msg_chan_sel[(ie->data[0] & 0x03) | ((ie->data[0] >> 3) & 0x04)]);
++ pos = 1;
++ len -= 2;
++ if (ie->data[0] & 0x40) {
+ /* Explicitly defined DS1 */
+- pri_message(pri, "%c Ext: %d DS1 Identifier: %d \n", prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f);
+- pos++;
++ do {
++ pri_message(ctrl, "%c Ext: %d DS1 Identifier: %d \n",
++ prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f);
++ ++pos;
++ } while (!(ie->data[pos - 1] & 0x80) && pos < len);
+ } else {
+ /* Implicitly defined DS1 */
+ }
+- if (pos+2 < len) {
++ if (pos < len) {
+ /* Still more information here */
+- pri_message(pri, "%c Ext: %d Coding: %d %s Specified Channel Type: %d\n",
+- prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5,
+- (ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f);
+- if (!(ie->data[pos] & 0x10)) {
++ pri_message(ctrl,
++ "%c Ext: %d Coding: %d %s Specified Channel Type: %d\n",
++ prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5,
++ (ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f);
++ ++pos;
++ }
++ if (pos < len) {
++ if (!(ie->data[pos - 1] & 0x10)) {
+ /* Number specified */
+- pos++;
+- pri_message(pri, "%c Ext: %d Channel: %d ]\n", prefix, (ie->data[pos] & 0x80) >> 7,
+- (ie->data[pos]) & 0x7f);
++ do {
++ pri_message(ctrl,
++ "%c Ext: %d Channel: %d Type: %s%c\n",
++ prefix, (ie->data[pos] & 0x80) >> 7,
++ (ie->data[pos]) & 0x7f, pritype(ctrl->localtype),
++ (pos + 1 < len) ? ' ' : ']');
++ ++pos;
++ } while (pos < len);
+ } else {
+- pos++;
+ /* Map specified */
+- for (x=0;x<3;x++) {
++ res = 0;
++ x = 0;
++ do {
+ res <<= 8;
+ res |= ie->data[pos++];
+- }
+- pri_message(pri, "%c Map: %s ]\n", prefix, binary(res, 24));
++ ++x;
++ } while (pos < len);
++ pri_message(ctrl, "%c Map len: %d Map: %s ]\n", prefix,
++ x, binary(res, x << 3));
+ }
+- } else pri_message(pri, " ]\n");
++ } else {
++ pri_message(ctrl, " ]\n");
++ }
+ }
+
+ static char *ri2str(int ri)
+@@ -482,20 +1082,20 @@
+ return code2str(ri, ris, sizeof(ris) / sizeof(ris[0]));
+ }
+
+-static FUNC_DUMP(dump_restart_indicator)
++static void dump_restart_indicator(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Restart Indentifier (len=%2d) [ Ext: %d Spare: %d Resetting %s (%d) ]\n",
++ pri_message(ctrl, "%c Restart Indentifier (len=%2d) [ Ext: %d Spare: %d Resetting %s (%d) ]\n",
+ prefix, len, (ie->data[0] & 0x80) >> 7, (ie->data[0] & 0x78) >> 3, ri2str(ie->data[0] & 0x7), ie->data[0] & 0x7);
+ }
+
+-static FUNC_RECV(receive_restart_indicator)
++static int receive_restart_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ /* Pretty simple */
+ call->ri = ie->data[0] & 0x7;
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_restart_indicator)
++static int transmit_restart_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ /* Pretty simple */
+ switch(call->ri) {
+@@ -509,7 +1109,7 @@
+ ie->data[0] = 0xA0 | (call->ri & 0x7);
+ break;
+ default:
+- pri_error(pri, "!! Invalid restart indicator value %d\n", call->ri);
++ pri_error(ctrl, "!! Invalid restart indicator value %d\n", call->ri);
+ return-1;
+ }
+ return 3;
+@@ -607,16 +1207,16 @@
+ return code2str(proto, protos, sizeof(protos) / sizeof(protos[0]));
+ }
+
+-static FUNC_DUMP(dump_bearer_capability)
++static void dump_bearer_capability(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int pos=2;
+- pri_message(pri, "%c Bearer Capability (len=%2d) [ Ext: %d Q.931 Std: %d Info transfer capability: %s (%d)\n",
++ pri_message(ctrl, "%c Bearer Capability (len=%2d) [ Ext: %d Q.931 Std: %d Info transfer capability: %s (%d)\n",
+ prefix, len, (ie->data[0] & 0x80 ) >> 7, (ie->data[0] & 0x60) >> 5, cap2str(ie->data[0] & 0x1f), (ie->data[0] & 0x1f));
+- pri_message(pri, "%c Ext: %d Trans mode/rate: %s (%d)\n", prefix, (ie->data[1] & 0x80) >> 7, mode2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
++ pri_message(ctrl, "%c Ext: %d Trans mode/rate: %s (%d)\n", prefix, (ie->data[1] & 0x80) >> 7, mode2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
+
+ /* octet 4.1 exists iff mode/rate is multirate */
+ if ((ie->data[1] & 0x7f) == 0x18) {
+- pri_message(pri, "%c Ext: %d Transfer rate multiplier: %d x 64\n", prefix, (ie->data[2] & 0x80) >> 7, ie->data[2] & 0x7f);
++ pri_message(ctrl, "%c Ext: %d Transfer rate multiplier: %d x 64\n", prefix, (ie->data[2] & 0x80) >> 7, ie->data[2] & 0x7f);
+ pos++;
+ }
+
+@@ -632,7 +1232,7 @@
+ too, so we have to do the same for binary compatability */
+ u_int8_t layer1 = ie->data[pos] & 0x7f;
+
+- pri_message(pri, "%c User information layer 1: %s (%d)\n",
++ pri_message(ctrl, "%c User information layer 1: %s (%d)\n",
+ prefix, l12str(layer1), layer1);
+ pos++;
+
+@@ -640,7 +1240,7 @@
+ if (pos < len && !(ie->data[pos-1] & 0x80)) {
+ int ra = ie->data[pos] & 0x7f;
+
+- pri_message(pri, "%c Async: %d, Negotiation: %d, "
++ pri_message(ctrl, "%c Async: %d, Negotiation: %d, "
+ "User rate: %s (%#x)\n",
+ prefix,
+ ra & PRI_RATE_ADAPT_ASYNC ? 1 : 0,
+@@ -654,7 +1254,7 @@
+ if (pos < len && !(ie->data[pos-1] & 0x80)) {
+ u_int8_t data = ie->data[pos];
+ if (layer1 == PRI_LAYER_1_ITU_RATE_ADAPT) {
+- pri_message(pri, "%c Intermediate rate: %s (%d), "
++ pri_message(ctrl, "%c Intermediate rate: %s (%d), "
+ "NIC on Tx: %d, NIC on Rx: %d, "
+ "Flow control on Tx: %d, "
+ "Flow control on Rx: %d\n",
+@@ -665,7 +1265,7 @@
+ (data & 0x04)?1:0,
+ (data & 0x02)?1:0);
+ } else if (layer1 == PRI_LAYER_1_V120_RATE_ADAPT) {
+- pri_message(pri, "%c Hdr: %d, Multiframe: %d, Mode: %d, "
++ pri_message(ctrl, "%c Hdr: %d, Multiframe: %d, Mode: %d, "
+ "LLI negot: %d, Assignor: %d, "
+ "In-band neg: %d\n", prefix,
+ (data & 0x40)?1:0,
+@@ -675,7 +1275,8 @@
+ (data & 0x04)?1:0,
+ (data & 0x02)?1:0);
+ } else {
+- pri_message(pri, "%c Unknown octet 5b: 0x%x\n", data );
++ pri_message(ctrl, "%c Unknown octet 5b: 0x%x\n",
++ prefix, data);
+ }
+ pos++;
+ }
+@@ -688,7 +1289,7 @@
+ const char *parity[] = {"Odd","?","Even","None",
+ "zero","one","?","?"};
+
+- pri_message(pri, "%c Stop bits: %s, data bits: %s, "
++ pri_message(ctrl, "%c Stop bits: %s, data bits: %s, "
+ "parity: %s\n", prefix,
+ stop_bits[(data & 0x60) >> 5],
+ data_bits[(data & 0x18) >> 3],
+@@ -700,7 +1301,7 @@
+ /* octet 5d? */
+ if (pos < len && !(ie->data[pos-1] & 0x80)) {
+ u_int8_t data = ie->data[pos];
+- pri_message(pri, "%c Duplex mode: %d, modem type: %d\n",
++ pri_message(ctrl, "%c Duplex mode: %d, modem type: %d\n",
+ prefix, (data & 0x40) ? 1 : 0,data & 0x3F);
+ pos++;
+ }
+@@ -710,7 +1311,7 @@
+ /* Look for octet 6; this is identified by bits 5,6 == 10 */
+ if (pos < len &&
+ (ie->data[pos] & 0x60) == 0x40) {
+- pri_message(pri, "%c User information layer 2: %s (%d)\n",
++ pri_message(ctrl, "%c User information layer 2: %s (%d)\n",
+ prefix, l22str(ie->data[pos] & 0x1f),
+ ie->data[pos] & 0x1f);
+ pos++;
+@@ -718,7 +1319,7 @@
+
+ /* Look for octet 7; this is identified by bits 5,6 == 11 */
+ if (pos < len && (ie->data[pos] & 0x60) == 0x60) {
+- pri_message(pri, "%c User information layer 3: %s (%d)\n",
++ pri_message(ctrl, "%c User information layer 3: %s (%d)\n",
+ prefix, l32str(ie->data[pos] & 0x1f),
+ ie->data[pos] & 0x1f);
+ pos++;
+@@ -730,18 +1331,18 @@
+ proto = ((ie->data[pos] & 0xF) << 4 ) |
+ (ie->data[pos+1] & 0xF);
+
+- pri_message(pri, "%c Network layer: 0x%x\n", prefix,
++ pri_message(ctrl, "%c Network layer: 0x%x\n", prefix,
+ proto );
+ pos += 2;
+ }
+ }
+ }
+
+-static FUNC_RECV(receive_bearer_capability)
++static int receive_bearer_capability(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ int pos=2;
+ if (ie->data[0] & 0x60) {
+- pri_error(pri, "!! non-standard Q.931 standard field\n");
++ pri_error(ctrl, "!! non-standard Q.931 standard field\n");
+ return -1;
+ }
+ call->transcapability = ie->data[0] & 0x1f;
+@@ -788,7 +1389,7 @@
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_bearer_capability)
++static int transmit_bearer_capability(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ int tc;
+ int pos;
+@@ -797,20 +1398,20 @@
+ if(order > 1)
+ return 0;
+
+- tc = call->transcapability;
+- if (pri->subchannel && !pri->bri) {
++ if (ctrl->subchannel && !ctrl->bri) {
+ /* Bearer capability is *hard coded* in GR-303 */
+ ie->data[0] = 0x88;
+ ie->data[1] = 0x90;
+ return 4;
+ }
+-
+- if (call->justsignalling) {
++
++ if (call->cis_call) {
+ ie->data[0] = 0xa8;
+ ie->data[1] = 0x80;
+ return 4;
+ }
+-
++
++ tc = call->transcapability;
+ ie->data[0] = 0x80 | tc;
+ ie->data[1] = call->transmoderate | 0x80;
+
+@@ -820,7 +1421,7 @@
+ ie->data[pos++] = call->transmultiple | 0x80;
+ }
+
+- if ((tc & PRI_TRANS_CAP_DIGITAL) && (pri->switchtype == PRI_SWITCH_EUROISDN_E1) &&
++ if ((tc & PRI_TRANS_CAP_DIGITAL) && (ctrl->switchtype == PRI_SWITCH_EUROISDN_E1) &&
+ (call->transmoderate == TRANS_MODE_PACKET)) {
+ /* Apparently EuroISDN switches don't seem to like user layer 2/3 */
+ return 4;
+@@ -833,7 +1434,7 @@
+
+ if (call->transmoderate != TRANS_MODE_PACKET) {
+ /* If you have an AT&T 4ESS, you don't send any more info */
+- if ((pri->switchtype != PRI_SWITCH_ATT4ESS) && (call->userl1 > -1)) {
++ if ((ctrl->switchtype != PRI_SWITCH_ATT4ESS) && (call->userl1 > -1)) {
+ ie->data[pos++] = call->userl1 | 0x80; /* XXX Ext bit? XXX */
+ if (call->userl1 == PRI_LAYER_1_ITU_RATE_ADAPT) {
+ ie->data[pos++] = call->rateadaption | 0x80;
+@@ -908,6 +1509,30 @@
+ return code2str(plan, plans, sizeof(plans) / sizeof(plans[0]));
+ }
+
++/* Calling Party Category (Definitions from Q.763) */
++static char *cpc2str(int plan)
++{
++ static struct msgtype plans[] = {
++ { 0, "Unknown Source" },
++ { 1, "Operator French" },
++ { 2, "Operator English" },
++ { 3, "Operator German" },
++ { 4, "Operator Russian" },
++ { 5, "Operator Spanish" },
++ { 6, "Mut Agree Chinese" },
++ { 7, "Mut Agreement" },
++ { 8, "Mut Agree Japanese" },
++ { 9, "National Operator" },
++ { 10, "Ordinary Toll Caller" },
++ { 11, "Priority Toll Caller" },
++ { 12, "Data Call" },
++ { 13, "Test Call" },
++ { 14, "Spare" },
++ { 15, "Pay Phone" },
++ };
++ return code2str(plan, plans, ARRAY_LEN(plans));
++}
++
+ char *pri_pres2str(int pres)
+ {
+ static struct msgtype press[] = {
+@@ -934,51 +1559,134 @@
+ num[len] = 0;
+ }
+
+-static FUNC_DUMP(dump_called_party_number)
++static void q931_get_subaddr_specific(unsigned char *num, int maxlen, unsigned char *src, int len, char oddflag)
+ {
+- unsigned char cnum[256];
++ /* User Specified */
++ int x;
++ char *ptr = (char *) num;
+
+- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+- pri_message(pri, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n",
+- prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum);
++ if (len <= 0) {
++ num[0] = '\0';
++ return;
++ }
++
++ if (((len * 2) + 1) > maxlen) {
++ len = (maxlen / 2) - 1;
++ }
++
++ for (x = 0; x < (len - 1); ++x) {
++ ptr += sprintf(ptr, "%02x", src[x]);
++ }
++
++ if (oddflag) {
++ /* ODD */
++ sprintf(ptr, "%01x", (src[len - 1]) >> 4);
++ } else {
++ /* EVEN */
++ sprintf(ptr, "%02x", src[len - 1]);
++ }
+ }
+
+-static FUNC_DUMP(dump_called_party_subaddr)
++static int transmit_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_party_subaddress *q931_subaddress, int msgtype, q931_ie *ie, int offset, int len, int order)
+ {
++ size_t datalen;
++
++ if (!q931_subaddress->valid) {
++ return 0;
++ }
++
++ datalen = q931_subaddress->length;
++ if (!q931_subaddress->type) {
++ /* 0 = NSAP */
++ /* 0 = Odd/Even indicator */
++ ie->data[0] = 0x80;
++ } else {
++ /* 2 = User Specified */
++ ie->data[0] = q931_subaddress->odd_even_indicator ? 0xA8 : 0xA0;
++ }
++ memcpy(ie->data + offset, q931_subaddress->data, datalen);
++
++ return datalen + (offset + 2);
++}
++
++static int receive_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_party_subaddress *q931_subaddress, int msgtype, q931_ie *ie, int offset, int len)
++{
++ if (len <= 0) {
++ return -1;
++ }
++
++ q931_subaddress->valid = 1;
++ q931_subaddress->length = len;
++ /* type: 0 = NSAP, 2 = User Specified */
++ q931_subaddress->type = ((ie->data[0] & 0x70) >> 4);
++ q931_subaddress->odd_even_indicator = (ie->data[0] & 0x08) ? 1 : 0;
++ q931_get_number(q931_subaddress->data, sizeof(q931_subaddress->data),
++ ie->data + offset, len);
++
++ return 0;
++}
++
++static void dump_subaddr_helper(int full_ie, struct pri *ctrl, q931_ie *ie, int offset, int len, int datalen, char prefix, const char *named)
++{
+ unsigned char cnum[256];
+- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+- pri_message(pri, "%c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
+- prefix, len, ie->data[0] >> 7,
++
++ if (!(ie->data[0] & 0x70)) {
++ /* NSAP */
++ q931_get_number(cnum, sizeof(cnum), ie->data + offset, datalen);
++ } else {
++ /* User Specified */
++ q931_get_subaddr_specific(cnum, sizeof(cnum), ie->data + offset, datalen,
++ ie->data[0] & 0x08);
++ }
++
++ pri_message(ctrl,
++ "%c %s Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
++ prefix, named, len, ie->data[0] >> 7,
+ subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+ (ie->data[0] & 0x08) >> 3, cnum);
+ }
+
+-static FUNC_DUMP(dump_calling_party_number)
++static void dump_called_party_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ unsigned char cnum[256];
++
++ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
++ pri_message(ctrl, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n",
++ prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum);
++}
++
++static void dump_called_party_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ dump_subaddr_helper(full_ie, ctrl, ie, 1 , len, len - 3, prefix, "Called");
++}
++
++static void dump_calling_party_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ unsigned char cnum[256];
+ if (ie->data[0] & 0x80)
+ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+ else
+ q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+- pri_message(pri, "%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
++ pri_message(ctrl, "%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
+ if (ie->data[0] & 0x80)
+- pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum);
++ pri_message(ctrl, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum);
+ else
+- pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
++ pri_message(ctrl, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum);
+ }
+
+-static FUNC_DUMP(dump_calling_party_subaddr)
++static void dump_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- unsigned char cnum[256];
+- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3);
+- pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
+- prefix, len, ie->data[0] >> 7,
+- subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+- (ie->data[0] & 0x08) >> 3, cnum);
++ dump_subaddr_helper(full_ie, ctrl, ie, 1 , len, len - 3, prefix, "Calling");
+ }
+
+-static FUNC_DUMP(dump_redirecting_number)
++static void dump_calling_party_category(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
++ pri_message(ctrl, "%c Calling Party Category (len=%2d) [ Ext: %d Cat: %s (%d) ]\n",
++ prefix, len, ie->data[0] >> 7, cpc2str(ie->data[0] & 0x0F), ie->data[0] & 0x0F);
++}
++
++static void dump_redirecting_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
+ unsigned char cnum[256];
+ int i = 0;
+ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+@@ -986,172 +1694,369 @@
+ do {
+ switch(i) {
+ case 0: /* Octet 3 */
+- pri_message(pri, "%c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
++ pri_message(ctrl, "%c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
+ prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
+ break;
+ case 1: /* Octet 3a */
+- pri_message(pri, "\n%c Ext: %d Presentation: %s (%d)",
++ pri_message(ctrl, "\n%c Ext: %d Presentation: %s (%d)",
+ prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
+ break;
+ case 2: /* Octet 3b */
+- pri_message(pri, "\n%c Ext: %d Reason: %s (%d)",
++ pri_message(ctrl, "\n%c Ext: %d Reason: %s (%d)",
+ prefix, ie->data[2] >> 7, redirection_reason2str(ie->data[2] & 0x7f), ie->data[2] & 0x7f);
+ break;
+ }
+- }
+- while(!(ie->data[i++]& 0x80));
++ } while(!(ie->data[i++]& 0x80));
+ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
+- pri_message(pri, " '%s' ]\n", cnum);
++ pri_message(ctrl, " '%s' ]\n", cnum);
+ }
+
+-static FUNC_DUMP(dump_connected_number)
++static void dump_redirection_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ unsigned char cnum[256];
+ int i = 0;
+ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+ walking through all bytes until one with ext bit (8) set to 1 */
+ do {
++ switch (i) {
++ case 0: /* Octet 3 */
++ pri_message(ctrl,
++ "%c Redirection Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
++ prefix, len, ie->data[0] >> 7,
++ ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07,
++ npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
++ break;
++ case 1: /* Octet 3a */
++ pri_message(ctrl, "\n%c Ext: %d Presentation: %s (%d)",
++ prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
++ break;
++ }
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
++ pri_message(ctrl, " '%s' ]\n", cnum);
++}
++
++static int receive_connected_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ int i = 0;
++
++ call->connected_number_in_message = 1;
++ call->remote_id.number.valid = 1;
++ call->remote_id.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
++ walking through all bytes until one with ext bit (8) set to 1 */
++ do {
++ switch (i) {
++ case 0:
++ call->remote_id.number.plan = ie->data[i] & 0x7f;
++ break;
++ case 1:
++ /* Keep only the presentation and screening fields */
++ call->remote_id.number.presentation =
++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE);
++ break;
++ }
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number((unsigned char *) call->remote_id.number.str, sizeof(call->remote_id.number.str), ie->data + i, ie->len - i);
++
++ return 0;
++}
++
++static int transmit_connected_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
++ size_t datalen;
++
++ if (!call->local_id.number.valid) {
++ return 0;
++ }
++
++ datalen = strlen(call->local_id.number.str);
++ ie->data[0] = call->local_id.number.plan;
++ ie->data[1] = 0x80 | call->local_id.number.presentation;
++ memcpy(ie->data + 2, call->local_id.number.str, datalen);
++ return datalen + (2 + 2);
++}
++
++static void dump_connected_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ unsigned char cnum[256];
++ int i = 0;
++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
++ walking through all bytes until one with ext bit (8) set to 1 */
++ do {
+ switch(i) {
+ case 0: /* Octet 3 */
+- pri_message(pri, "%c Connected Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
++ pri_message(ctrl, "%c Connected Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)",
+ prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f);
+ break;
+ case 1: /* Octet 3a */
+- pri_message(pri, "\n%c Ext: %d Presentation: %s (%d)",
++ pri_message(ctrl, "\n%c Ext: %d Presentation: %s (%d)",
+ prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
+ break;
+ }
+- }
+- while(!(ie->data[i++]& 0x80));
++ } while(!(ie->data[i++]& 0x80));
+ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
+- pri_message(pri, " '%s' ]\n", cnum);
++ pri_message(ctrl, " '%s' ]\n", cnum);
+ }
+
++static int receive_connected_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ if (len < 3) {
++ return -1;
++ }
+
+-static FUNC_RECV(receive_redirecting_number)
++ return receive_subaddr_helper(full_ie, ctrl, &call->remote_id.subaddress, msgtype, ie,
++ 1, len - 3);
++}
++
++static int transmit_connected_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
++ return transmit_subaddr_helper(full_ie, ctrl, &call->local_id.subaddress, msgtype, ie,
++ 1, len, order);
++}
++
++static void dump_connected_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ dump_subaddr_helper(full_ie, ctrl, ie, 1 , len, len - 3, prefix, "Connected");
++}
++
++static int receive_redirecting_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
+ int i = 0;
+
++ call->redirecting_number_in_message = 1;
++ call->redirecting.from.number.valid = 1;
++ call->redirecting.from.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ call->redirecting.reason = PRI_REDIR_UNKNOWN;
+ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
+ walking through all bytes until one with ext bit (8) set to 1 */
+ do {
+- switch(i) {
++ switch (i) {
+ case 0:
+- call->redirectingplan = ie->data[i] & 0x7f;
++ call->redirecting.from.number.plan = ie->data[i] & 0x7f;
+ break;
+ case 1:
+- call->redirectingpres = ie->data[i] & 0x7f;
++ /* Keep only the presentation and screening fields */
++ call->redirecting.from.number.presentation =
++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE);
+ break;
+ case 2:
+- call->redirectingreason = ie->data[i] & 0x0f;
++ call->redirecting.reason = ie->data[i] & 0x0f;
+ break;
+ }
+- }
+- while(!(ie->data[i++] & 0x80));
+- q931_get_number((unsigned char *) call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i);
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number((unsigned char *) call->redirecting.from.number.str, sizeof(call->redirecting.from.number.str), ie->data + i, ie->len - i);
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_redirecting_number)
++static int transmit_redirecting_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
++ size_t datalen;
++
+ if (order > 1)
+ return 0;
+- if (call->redirectingnum && *call->redirectingnum) {
+- ie->data[0] = call->redirectingplan;
+- ie->data[1] = call->redirectingpres;
+- ie->data[2] = (call->redirectingreason & 0x0f) | 0x80;
+- memcpy(ie->data + 3, call->redirectingnum, strlen(call->redirectingnum));
+- return strlen(call->redirectingnum) + 3 + 2;
++ if (!call->redirecting.from.number.valid) {
++ return 0;
+ }
+- return 0;
++
++ datalen = strlen(call->redirecting.from.number.str);
++ ie->data[0] = call->redirecting.from.number.plan;
++#if 1
++ /* ETSI and Q.952 do not define the screening field */
++ ie->data[1] = call->redirecting.from.number.presentation & PRI_PRES_RESTRICTION;
++#else
++ /* Q.931 defines the screening field */
++ ie->data[1] = call->redirecting.from.number.presentation;
++#endif
++ ie->data[2] = (call->redirecting.reason & 0x0f) | 0x80;
++ memcpy(ie->data + 3, call->redirecting.from.number.str, datalen);
++ return datalen + (3 + 2);
+ }
+
+-static FUNC_DUMP(dump_redirecting_subaddr)
++static void dump_redirecting_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- unsigned char cnum[256];
+- q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4);
+- pri_message(pri, "%c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n",
+- prefix, len, ie->data[0] >> 7,
+- subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4,
+- (ie->data[0] & 0x08) >> 3, cnum);
++ dump_subaddr_helper(full_ie, ctrl, ie, 2, len, len - 4, prefix, "Redirecting");
+ }
+
+-static FUNC_RECV(receive_calling_party_subaddr)
++static int receive_redirection_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+- /* copy digits to call->callingsubaddr */
+- q931_get_number((unsigned char *) call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 1, len - 3);
++ int i = 0;
++
++ call->redirection_number.valid = 1;
++ call->redirection_number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
++ walking through all bytes until one with ext bit (8) set to 1 */
++ do {
++ switch (i) {
++ case 0:
++ call->redirection_number.plan = ie->data[i] & 0x7f;
++ break;
++ case 1:
++ /* Keep only the presentation and screening fields */
++ call->redirection_number.presentation =
++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE);
++ break;
++ }
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number((unsigned char *) call->redirection_number.str, sizeof(call->redirection_number.str), ie->data + i, ie->len - i);
+ return 0;
+ }
+
+-static FUNC_RECV(receive_called_party_number)
++static int transmit_redirection_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- /* copy digits to call->callednum */
+- q931_get_number((unsigned char *) call->callednum, sizeof(call->callednum), ie->data + 1, len - 3);
+- call->calledplan = ie->data[0] & 0x7f;
+- return 0;
++ size_t datalen;
++
++ if (order > 1) {
++ return 0;
++ }
++ if (!call->redirection_number.valid) {
++ return 0;
++ }
++
++ datalen = strlen(call->redirection_number.str);
++ ie->data[0] = call->redirection_number.plan;
++ ie->data[1] = (call->redirection_number.presentation & PRI_PRES_RESTRICTION) | 0x80;
++ memcpy(ie->data + 2, call->redirection_number.str, datalen);
++ return datalen + (2 + 2);
+ }
+
+-static FUNC_SEND(transmit_called_party_number)
++static int receive_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+- ie->data[0] = 0x80 | call->calledplan;
+- if (*call->callednum)
+- memcpy(ie->data + 1, call->callednum, strlen(call->callednum));
+- return strlen(call->callednum) + 3;
++ if (len < 3) {
++ return -1;
++ }
++
++ return receive_subaddr_helper(full_ie, ctrl, &call->remote_id.subaddress, msgtype, ie,
++ 1, len - 3);
+ }
+
+-static FUNC_RECV(receive_calling_party_number)
++static int transmit_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- u_int8_t *data;
+- size_t length;
+-
+- if (ie->data[0] & 0x80) {
+- data = ie->data + 1;
+- length = len - 3;
+- call->callerpres = 0; /* PI presentation allowed SI user-provided, not screened */
+- } else {
+- data = ie->data + 2;
+- length = len - 4;
+- call->callerpres = ie->data[1] & 0x7f;
++ return transmit_subaddr_helper(full_ie, ctrl, &call->local_id.subaddress, msgtype, ie,
++ 1, len, order);
++}
++
++static int receive_called_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ if (len < 3) {
++ return -1;
+ }
++ return receive_subaddr_helper(full_ie, ctrl, &call->called.subaddress, msgtype, ie, 1,
++ len - 3);
++}
+
+- if (call->callerpres == PRES_ALLOWED_NETWORK_NUMBER ||
+- call->callerpres == PRES_PROHIB_NETWORK_NUMBER) {
+- q931_get_number((u_int8_t *)call->callerani, sizeof(call->callerani), data, length);
+- call->callerplanani = ie->data[0] & 0x7f;
++static int transmit_called_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
++ return transmit_subaddr_helper(full_ie, ctrl, &call->called.subaddress, msgtype, ie,
++ 1, len, order);
++}
+
+- if (!*call->callernum) { /*Copy ANI to CallerID if CallerID is not already set */
+- libpri_copy_string(call->callernum, call->callerani, sizeof(call->callernum));
+- call->callerplan = call->callerplanani;
++static int receive_called_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ size_t called_len;
++ size_t max_len;
++ char *called_end;
++
++ if (len < 3) {
++ return -1;
++ }
++
++ call->called.number.valid = 1;
++ call->called.number.plan = ie->data[0] & 0x7f;
++ if (msgtype == Q931_SETUP) {
++ q931_get_number((unsigned char *) call->called.number.str,
++ sizeof(call->called.number.str), ie->data + 1, len - 3);
++ } else if (call->ourcallstate == Q931_CALL_STATE_OVERLAP_RECEIVING) {
++ /*
++ * Since we are receiving overlap digits now, we need to append
++ * them to any previously received digits in call->called.number.str.
++ */
++ called_len = strlen(call->called.number.str);
++ called_end = call->called.number.str + called_len;
++ max_len = (sizeof(call->called.number.str) - 1) - called_len;
++ if (max_len < len - 3) {
++ called_len = max_len;
++ } else {
++ called_len = len - 3;
+ }
+-
+- } else {
+- q931_get_number((u_int8_t *)call->callernum, sizeof(call->callernum), data, length);
+- call->callerplan = ie->data[0] & 0x7f;
++ strncat(called_end, (char *) ie->data + 1, called_len);
+ }
+
++ q931_get_number((unsigned char *) call->overlap_digits, sizeof(call->overlap_digits),
++ ie->data + 1, len - 3);
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_calling_party_number)
++static int transmit_called_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- ie->data[0] = call->callerplan;
+- ie->data[1] = 0x80 | call->callerpres;
+- if (*call->callernum)
+- memcpy(ie->data + 2, call->callernum, strlen(call->callernum));
+- return strlen(call->callernum) + 4;
++ size_t datalen;
++
++ if (!call->called.number.valid) {
++ return 0;
++ }
++
++ datalen = strlen(call->overlap_digits);
++ ie->data[0] = 0x80 | call->called.number.plan;
++ memcpy(ie->data + 1, call->overlap_digits, datalen);
++ return datalen + (1 + 2);
+ }
+
+-static FUNC_DUMP(dump_user_user)
++static int receive_calling_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
++ int i = 0;
++
++ call->remote_id.number.valid = 1;
++ call->remote_id.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
++ walking through all bytes until one with ext bit (8) set to 1 */
++ do {
++ switch (i) {
++ case 0:
++ call->remote_id.number.plan = ie->data[i] & 0x7f;
++ break;
++ case 1:
++ /* Keep only the presentation and screening fields */
++ call->remote_id.number.presentation =
++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE);
++ break;
++ }
++ } while (!(ie->data[i++] & 0x80));
++ q931_get_number((unsigned char *) call->remote_id.number.str,
++ sizeof(call->remote_id.number.str), ie->data + i, ie->len - i);
++
++ return 0;
++}
++
++static int transmit_calling_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
++ size_t datalen;
++
++ if (!call->local_id.number.valid) {
++ return 0;
++ }
++
++ datalen = strlen(call->local_id.number.str);
++ ie->data[0] = call->local_id.number.plan;
++ ie->data[1] = 0x80 | call->local_id.number.presentation;
++ memcpy(ie->data + 2, call->local_id.number.str, datalen);
++ return datalen + (2 + 2);
++}
++
++static void dump_user_user(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
+ int x;
+- pri_message(pri, "%c User-User Information (len=%2d) [", prefix, len);
++ pri_message(ctrl, "%c User-User Information (len=%2d) [", prefix, len);
+ for (x=0;x<ie->len;x++)
+- pri_message(pri, " %02x", ie->data[x] & 0x7f);
+- pri_message(pri, " ]\n");
++ pri_message(ctrl, " %02x", ie->data[x] & 0x7f);
++ pri_message(ctrl, " ]\n");
+ }
+
+
+-static FUNC_RECV(receive_user_user)
++static int receive_user_user(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->useruserprotocoldisc = ie->data[0] & 0xff;
+ if (call->useruserprotocoldisc == 4) /* IA5 */
+@@ -1159,7 +2064,7 @@
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_user_user)
++static int transmit_user_user(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ int datalen = strlen(call->useruserinfo);
+ if (datalen > 0) {
+@@ -1180,6 +2085,29 @@
+ return 0;
+ }
+
++static void dump_change_status(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ int x;
++
++ pri_message(ctrl, "%c Change Status Information (len=%2d) [", prefix, len);
++ for (x=0; x<ie->len; x++) {
++ pri_message(ctrl, " %02x", ie->data[x] & 0x7f);
++ }
++ pri_message(ctrl, " ]\n");
++}
++
++static int receive_change_status(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ call->changestatus = ie->data[0] & 0x0f;
++ return 0;
++}
++
++static int transmit_change_status(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
++ ie->data[0] = 0xc0 | call->changestatus;
++ return 3;
++}
++
+ static char *prog2str(int prog)
+ {
+ static struct msgtype progs[] = {
+@@ -1222,47 +2150,83 @@
+ return code2str(loc, locs, sizeof(locs) / sizeof(locs[0]));
+ }
+
+-static FUNC_DUMP(dump_progress_indicator)
++static void dump_progress_indicator(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Progress Indicator (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n",
++ pri_message(ctrl, "%c Progress Indicator (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n",
+ prefix, len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5,
+ (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf);
+- pri_message(pri, "%c Ext: %d Progress Description: %s (%d) ]\n",
++ pri_message(ctrl, "%c Ext: %d Progress Description: %s (%d) ]\n",
+ prefix, ie->data[1] >> 7, prog2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
+ }
+
+-static FUNC_RECV(receive_display)
++static int receive_display(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ unsigned char *data;
++
++ switch (msgtype) {
++ case Q931_SETUP:
++ case Q931_CONNECT:
++ /*
++ * Only keep the display message on SETUP and CONNECT messages
++ * as the remote name.
++ */
++ break;
++ default:
++ return 0;
++ }
++
++ call->remote_id.name.valid = 1;
++
+ data = ie->data;
+ if (data[0] & 0x80) {
+ /* Skip over character set */
+ data++;
+ len--;
+ }
+- q931_get_number((unsigned char *) call->callername, sizeof(call->callername), data, len - 2);
++ call->remote_id.name.char_set = PRI_CHAR_SET_ISO8859_1;
++
++ q931_get_number((unsigned char *) call->remote_id.name.str, sizeof(call->remote_id.name.str), data, len - 2);
++ if (call->remote_id.name.str[0]) {
++ call->remote_id.name.presentation = PRI_PRES_ALLOWED;
++ } else {
++ call->remote_id.name.presentation = PRI_PRES_RESTRICTED;
++ }
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_display)
++static int transmit_display(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
++ size_t datalen;
+ int i;
+-
+- if ((pri->switchtype == PRI_SWITCH_QSIG) ||
+- ((pri->switchtype == PRI_SWITCH_EUROISDN_E1) && (pri->localtype == PRI_CPE)) ||
+- !call->callername[0])
+- return 0;
+
+ i = 0;
+- if(pri->switchtype != PRI_SWITCH_EUROISDN_E1) {
++
++ if (!call->local_id.name.valid || !call->local_id.name.str[0]) {
++ return 0;
++ }
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_QSIG:
++ /* Q.SIG supports names */
++ return 0;
++ case PRI_SWITCH_EUROISDN_E1:
++ case PRI_SWITCH_EUROISDN_T1:
++ if (ctrl->localtype == PRI_CPE) {
++ return 0;
++ }
++ break;
++ default:
++ /* Prefix name with character set indicator. */
+ ie->data[0] = 0xb1;
+ ++i;
++ break;
+ }
+- memcpy(ie->data + i, call->callername, strlen(call->callername));
+- return 2 + i + strlen(call->callername);
++
++ datalen = strlen(call->local_id.name.str);
++ memcpy(ie->data + i, call->local_id.name.str, datalen);
++ return 2 + i + datalen;
+ }
+
+-static FUNC_RECV(receive_progress_indicator)
++static int receive_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->progloc = ie->data[0] & 0xf;
+ call->progcode = (ie->data[0] & 0x60) >> 5;
+@@ -1298,153 +2262,204 @@
+ call->progressmask |= PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER;
+ break;
+ default:
+- pri_error(pri, "XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f));
++ pri_error(ctrl, "XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f));
+ break;
+ }
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_facility)
++static void q931_apdu_timeout(void *data);
++
++static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- struct apdu_event *tmp;
+- int i = 0;
++ struct apdu_event **prev;
++ struct apdu_event *cur;
++ int apdu_len;
+
+- for (tmp = call->apdus; tmp; tmp = tmp->next) {
+- if ((tmp->message == msgtype) && !tmp->sent)
++ for (prev = &call->apdus, cur = call->apdus;
++ cur;
++ prev = &cur->next, cur = cur->next) {
++ if (!cur->sent && cur->message == msgtype) {
+ break;
++ }
+ }
+-
+- if (!tmp) /* No APDU found */
++ if (!cur) {
++ /* No APDU found */
+ return 0;
++ }
+
+- if (tmp->apdu_len > 235) { /* TODO: find out how much space we can use */
+- pri_message(pri, "Requested APDU (%d bytes) is too long\n", tmp->apdu_len);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "Adding facility ie contents to send in %s message:\n",
++ msg2str(msgtype));
++ facility_decode_dump(ctrl, cur->apdu, cur->apdu_len);
++ }
++
++ if (len < cur->apdu_len) {
++ pri_error(ctrl,
++ "Could not fit facility ie in message. Size needed:%d Available space:%d\n",
++ cur->apdu_len + 2, len);
++
++ /* Remove APDU from list. */
++ *prev = cur->next;
++
++ if (cur->response.callback) {
++ /* Indicate to callback that the APDU had a problem getting sent. */
++ cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL);
++ }
++
++ free(cur);
+ return 0;
+ }
+-
+- memcpy(&ie->data[i], tmp->apdu, tmp->apdu_len);
+- i += tmp->apdu_len;
+- tmp->sent = 1;
+
+- return i + 2;
++ memcpy(ie->data, cur->apdu, cur->apdu_len);
++ apdu_len = cur->apdu_len;
++ cur->sent = 1;
++
++ if (cur->response.callback && cur->response.timeout_time) {
++ int duration;
++
++ if (0 < cur->response.timeout_time) {
++ /* Sender specified timeout duration. */
++ duration = cur->response.timeout_time;
++ } else {
++ /* Sender wants to use the typical timeout duration. */
++ duration = ctrl->timers[PRI_TIMER_T_RESPONSE];
++ }
++ cur->timer = pri_schedule_event(ctrl, duration, q931_apdu_timeout, cur);
++ if (!cur->timer) {
++ /* Remove APDU from list. */
++ *prev = cur->next;
++
++ /* Indicate to callback that the APDU had a problem getting sent. */
++ cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL);
++
++ free(cur);
++ }
++ } else if (!cur->timer) {
++ /* Remove APDU from list. */
++ *prev = cur->next;
++ free(cur);
++ }
++
++ return apdu_len + 2;
+ }
+
+-static FUNC_RECV(receive_facility)
++static int receive_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+- int i = 0;
+- int protocol, next_protocol;
+- struct rose_component *comp = NULL;
+- enum {
+- Q932_STATE_NFE, /* Network facility extension */
+- Q932_STATE_NPP, /* Network protocol profile */
+- Q932_STATE_INTERPRETATION, /* Interpretation component */
+- Q932_STATE_SERVICE /* Service component(s) */
+- } state = Q932_STATE_SERVICE;
+-#define Q932_HANDLE_PROC(component, my_state, name, handler) \
+- case component: \
+- if(state > my_state) { \
+- pri_error(pri, "!! %s component received in wrong place\n"); \
+- break; \
+- } \
+- state = my_state; \
+- if (pri->debug) \
+- pri_message(pri, "Handle Q.932 %s component\n", name); \
+- (handler)(pri, call, ie, comp->data, comp->len); \
+- break;
+-#define Q932_HANDLE_NULL(component, my_state, name, handle) \
+- case component: \
+- if(state > my_state) { \
+- pri_error(pri, "!! %s component received in wrong place\n"); \
+- break; \
+- } \
+- state = my_state; \
+- if (pri->debug & PRI_DEBUG_APDU) \
+- pri_message(pri, "Q.932 %s component is not handled\n", name); \
+- break;
+-
+- if (ie->len < 1)
++ /* Delay processing facility ie's till after all other ie's are processed. */
++ if (MAX_FACILITY_IES <= ctrl->facility.count) {
++ pri_message(ctrl, "!! Too many facility ie's to delay.\n");
+ return -1;
++ }
++ /* Make sure we have enough room for the protocol profile ie octet(s) */
++ if (ie->data + ie->len < ie->data + 2) {
++ return -1;
++ }
+
+- switch(next_protocol = protocol = (ie->data[i] & 0x1f)) {
+- case Q932_PROTOCOL_CMIP:
+- case Q932_PROTOCOL_ACSE:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "!! Don't know how to handle Q.932 Protocol Profile of type 0x%X\n", protocol);
++ /* Save the facility ie location for delayed decode. */
++ ctrl->facility.ie[ctrl->facility.count] = ie;
++ ctrl->facility.codeset[ctrl->facility.count] = Q931_IE_CODESET((unsigned) full_ie);
++ ++ctrl->facility.count;
++ return 0;
++}
++
++static int process_facility(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie)
++{
++ struct fac_extension_header header;
++ struct rose_message rose;
++ const unsigned char *pos;
++ const unsigned char *end;
++
++ pos = ie->data;
++ end = ie->data + ie->len;
++
++ /* Make sure we have enough room for the protocol profile ie octet(s) */
++ if (end < pos + 2) {
+ return -1;
++ }
++ switch (*pos & Q932_PROTOCOL_MASK) {
++ case Q932_PROTOCOL_ROSE:
+ case Q932_PROTOCOL_EXTENSIONS:
+- state = Q932_STATE_NFE;
+- next_protocol = Q932_PROTOCOL_ROSE;
+ break;
+- case Q932_PROTOCOL_ROSE:
+- break;
+ default:
+- pri_error(pri, "!! Invalid Q.932 Protocol Profile of type 0x%X received\n", protocol);
++ case Q932_PROTOCOL_CMIP:
++ case Q932_PROTOCOL_ACSE:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl,
++ "!! Don't know how to handle Q.932 Protocol Profile type 0x%X\n",
++ *pos & Q932_PROTOCOL_MASK);
++ }
+ return -1;
+ }
+- /* Service indicator octet - Just ignore for now */
+- if (!(ie->data[i] & 0x80))
+- i++;
+- i++;
++ if (!(*pos & 0x80)) {
++ /* DMS-100 Service indicator octet - Just ignore for now */
++ ++pos;
++ }
++ ++pos;
+
+- if (ie->len < 3)
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ asn1_dump(ctrl, pos, end);
++ }
++
++ pos = fac_dec_extension_header(ctrl, pos, end, &header);
++ if (!pos) {
+ return -1;
+-
+- while ((i+1 < ie->len) && (&ie->data[i])) {
+- comp = (struct rose_component*)&ie->data[i];
+- if (comp->type) {
+- if (protocol == Q932_PROTOCOL_EXTENSIONS) {
+- switch (comp->type) {
+- Q932_HANDLE_NULL(COMP_TYPE_INTERPRETATION, Q932_STATE_INTERPRETATION, "Interpretation", NULL);
+- Q932_HANDLE_NULL(COMP_TYPE_NFE, Q932_STATE_NFE, "Network facility extensions", NULL);
+- Q932_HANDLE_NULL(COMP_TYPE_NETWORK_PROTOCOL_PROFILE, Q932_STATE_NPP, "Network protocol profile", NULL);
+- default:
+- protocol = next_protocol;
+- break;
+- }
+- }
+- switch (protocol) {
+- case Q932_PROTOCOL_ROSE:
+- switch (comp->type) {
+- Q932_HANDLE_PROC(COMP_TYPE_INVOKE, Q932_STATE_SERVICE, "ROSE Invoke", rose_invoke_decode);
+- Q932_HANDLE_PROC(COMP_TYPE_RETURN_RESULT, Q932_STATE_SERVICE, "ROSE return result", rose_return_result_decode);
+- Q932_HANDLE_PROC(COMP_TYPE_RETURN_ERROR, Q932_STATE_SERVICE, "ROSE return error", rose_return_error_decode);
+- Q932_HANDLE_PROC(COMP_TYPE_REJECT, Q932_STATE_SERVICE, "ROSE reject", rose_reject_decode);
+- default:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Don't know how to handle ROSE component of type 0x%X\n", comp->type);
+- break;
+- }
+- break;
+- case Q932_PROTOCOL_CMIP:
+- switch (comp->type) {
+- default:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Don't know how to handle CMIP component of type 0x%X\n", comp->type);
+- break;
+- }
+- break;
+- case Q932_PROTOCOL_ACSE:
+- switch (comp->type) {
+- default:
+- if (pri->debug & PRI_DEBUG_APDU)
+- pri_message(pri, "Don't know how to handle ACSE component of type 0x%X\n", comp->type);
+- break;
+- }
+- break;
+- }
++ }
++ if (header.npp_present) {
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl,
++ "!! Don't know how to handle Network Protocol Profile type 0x%X\n",
++ header.npp);
+ }
+- i += (comp->len + 2);
++ return -1;
+ }
+-#undef Q932_HANDLE
+
++ pos = rose_decode(ctrl, pos, end, &rose);
++ if (!pos) {
++ return -1;
++ }
++ switch (rose.type) {
++ case ROSE_COMP_TYPE_INVOKE:
++ rose_handle_invoke(ctrl, call, msgtype, ie, &header, &rose.component.invoke);
++ break;
++ case ROSE_COMP_TYPE_RESULT:
++ rose_handle_result(ctrl, call, msgtype, ie, &header, &rose.component.result);
++ break;
++ case ROSE_COMP_TYPE_ERROR:
++ rose_handle_error(ctrl, call, msgtype, ie, &header, &rose.component.error);
++ break;
++ case ROSE_COMP_TYPE_REJECT:
++ rose_handle_reject(ctrl, call, msgtype, ie, &header, &rose.component.reject);
++ break;
++ default:
++ return -1;
++ }
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_progress_indicator)
++static void q931_handle_facilities(struct pri *ctrl, q931_call *call, int msgtype)
+ {
++ unsigned idx;
++ unsigned codeset;
++ unsigned full_ie;
++ q931_ie *ie;
++
++ for (idx = 0; idx < ctrl->facility.count; ++idx) {
++ ie = ctrl->facility.ie[idx];
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ codeset = ctrl->facility.codeset[idx];
++ full_ie = Q931_FULL_IE(codeset, ie->ie);
++ pri_message(ctrl, "-- Delayed processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
++ }
++ process_facility(ctrl, call, msgtype, ie);
++ }
++}
++
++static int transmit_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
+ int code, mask;
+ /* Can't send progress indicator on GR-303 -- EVER! */
+- if (pri->subchannel && !pri->bri)
++ if (ctrl->subchannel && !ctrl->bri)
+ return 0;
+ if (call->progressmask > 0) {
+ if (call->progressmask & (mask = PRI_PROG_CALL_NOT_E2E_ISDN))
+@@ -1467,7 +2482,7 @@
+ code = Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER;
+ else {
+ code = 0;
+- pri_error(pri, "XXX Undefined progress bit: %x\n", call->progressmask);
++ pri_error(ctrl, "XXX Undefined progress bit: %x\n", call->progressmask);
+ }
+ if (code) {
+ ie->data[0] = 0x80 | (call->progcode << 5) | (call->progloc);
+@@ -1479,82 +2494,139 @@
+ /* Leave off */
+ return 0;
+ }
+-static FUNC_SEND(transmit_call_state)
++static int transmit_call_state(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- if (call->ourcallstate > -1 ) {
++ ie->data[0] = Q931_CALL_STATE_NULL;
++ switch (call->ourcallstate) {
++ case Q931_CALL_STATE_NULL:
++ case Q931_CALL_STATE_CALL_INITIATED:
++ case Q931_CALL_STATE_OVERLAP_SENDING:
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_CALL_PRESENT:
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_ACTIVE:
++ case Q931_CALL_STATE_DISCONNECT_REQUEST:
++ case Q931_CALL_STATE_DISCONNECT_INDICATION:
++ case Q931_CALL_STATE_SUSPEND_REQUEST:
++ case Q931_CALL_STATE_RESUME_REQUEST:
++ case Q931_CALL_STATE_RELEASE_REQUEST:
++ case Q931_CALL_STATE_CALL_ABORT:
++ case Q931_CALL_STATE_OVERLAP_RECEIVING:
++ case Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE:
++ case Q931_CALL_STATE_RESTART_REQUEST:
++ case Q931_CALL_STATE_RESTART:
+ ie->data[0] = call->ourcallstate;
+- return 3;
++ break;
++ case Q931_CALL_STATE_NOT_SET:
++ break;
+ }
+- return 0;
++ return 3;
+ }
+
+-static FUNC_RECV(receive_call_state)
++static int receive_call_state(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->sugcallstate = ie->data[0] & 0x3f;
+ return 0;
+ }
+
+-static char *callstate2str(int callstate)
++/*!
++ * \brief Convert the internal Q.931 call state to a string.
++ *
++ * \param callstate Internal Q.931 call state.
++ *
++ * \return String equivalent of the given Q.931 call state.
++ */
++const char *q931_call_state_str(enum Q931_CALL_STATE callstate)
+ {
+ static struct msgtype callstates[] = {
+- { 0, "Null" },
+- { 1, "Call Initiated" },
+- { 2, "Overlap sending" },
+- { 3, "Outgoing call Proceeding" },
+- { 4, "Call Delivered" },
+- { 6, "Call Present" },
+- { 7, "Call Received" },
+- { 8, "Connect Request" },
+- { 9, "Incoming Call Proceeding" },
+- { 10, "Active" },
+- { 11, "Disconnect Request" },
+- { 12, "Disconnect Indication" },
+- { 15, "Suspend Request" },
+- { 17, "Resume Request" },
+- { 19, "Release Request" },
+- { 22, "Call Abort" },
+- { 25, "Overlap Receiving" },
+- { 61, "Restart Request" },
+- { 62, "Restart" },
++/* *INDENT-OFF* */
++ { Q931_CALL_STATE_NULL, "Null" },
++ { Q931_CALL_STATE_CALL_INITIATED, "Call Initiated" },
++ { Q931_CALL_STATE_OVERLAP_SENDING, "Overlap Sending" },
++ { Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING, "Outgoing Call Proceeding" },
++ { Q931_CALL_STATE_CALL_DELIVERED, "Call Delivered" },
++ { Q931_CALL_STATE_CALL_PRESENT, "Call Present" },
++ { Q931_CALL_STATE_CALL_RECEIVED, "Call Received" },
++ { Q931_CALL_STATE_CONNECT_REQUEST, "Connect Request" },
++ { Q931_CALL_STATE_INCOMING_CALL_PROCEEDING, "Incoming Call Proceeding" },
++ { Q931_CALL_STATE_ACTIVE, "Active" },
++ { Q931_CALL_STATE_DISCONNECT_REQUEST, "Disconnect Request" },
++ { Q931_CALL_STATE_DISCONNECT_INDICATION, "Disconnect Indication" },
++ { Q931_CALL_STATE_SUSPEND_REQUEST, "Suspend Request" },
++ { Q931_CALL_STATE_RESUME_REQUEST, "Resume Request" },
++ { Q931_CALL_STATE_RELEASE_REQUEST, "Release Request" },
++ { Q931_CALL_STATE_CALL_ABORT, "Call Abort" },
++ { Q931_CALL_STATE_OVERLAP_RECEIVING, "Overlap Receiving" },
++ { Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE, "Call Independent Service" },
++ { Q931_CALL_STATE_RESTART_REQUEST, "Restart Request" },
++ { Q931_CALL_STATE_RESTART, "Restart" },
++ { Q931_CALL_STATE_NOT_SET, "Not set. Internal use only." },
++/* *INDENT-ON* */
+ };
+- return code2str(callstate, callstates, sizeof(callstates) / sizeof(callstates[0]));
++ return code2str(callstate, callstates, ARRAY_LEN(callstates));
+ }
+
+-static FUNC_DUMP(dump_call_state)
++/*!
++ * \internal
++ * \brief Convert the Q.932 supplementary hold state to a string.
++ *
++ * \param state Q.932 supplementary hold state.
++ *
++ * \return String equivalent of the given hold state.
++ */
++static const char *q931_hold_state_str(enum Q931_HOLD_STATE state)
+ {
+- pri_message(pri, "%c Call State (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d)\n",
++ static struct msgtype hold_states[] = {
++/* *INDENT-OFF* */
++ { Q931_HOLD_STATE_IDLE, "Idle" },
++ { Q931_HOLD_STATE_HOLD_REQ, "Hold Request" },
++ { Q931_HOLD_STATE_HOLD_IND, "Hold Indication" },
++ { Q931_HOLD_STATE_CALL_HELD, "Call Held" },
++ { Q931_HOLD_STATE_RETRIEVE_REQ, "Retrieve Request" },
++ { Q931_HOLD_STATE_RETRIEVE_IND, "Retrieve Indication" },
++/* *INDENT-ON* */
++ };
++ return code2str(state, hold_states, ARRAY_LEN(hold_states));
++}
++
++static void dump_call_state(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ pri_message(ctrl, "%c Call State (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d)\n",
+ prefix, len, ie->data[0] >> 7, coding2str((ie->data[0] & 0xC0) >> 6), (ie->data[0] & 0xC0) >> 6,
+- callstate2str(ie->data[0] & 0x3f), ie->data[0] & 0x3f);
++ q931_call_state_str(ie->data[0] & 0x3f), ie->data[0] & 0x3f);
+ }
+
+-static FUNC_DUMP(dump_call_identity)
++static void dump_call_identity(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int x;
+- pri_message(pri, "%c Call Identity (len=%2d) [ ", prefix, len);
++ pri_message(ctrl, "%c Call Identity (len=%2d) [ ", prefix, len);
+ for (x=0;x<ie->len;x++)
+- pri_message(pri, "0x%02X ", ie->data[x]);
+- pri_message(pri, " ]\n");
++ pri_message(ctrl, "0x%02X ", ie->data[x]);
++ pri_message(ctrl, " ]\n");
+ }
+
+-static FUNC_DUMP(dump_time_date)
++static void dump_time_date(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Time Date (len=%2d) [ ", prefix, len);
++ pri_message(ctrl, "%c Time Date (len=%2d) [ ", prefix, len);
+ if (ie->len > 0)
+- pri_message(pri, "%02d", ie->data[0]);
++ pri_message(ctrl, "%02d", ie->data[0]);
+ if (ie->len > 1)
+- pri_message(pri, "-%02d", ie->data[1]);
++ pri_message(ctrl, "-%02d", ie->data[1]);
+ if (ie->len > 2)
+- pri_message(pri, "-%02d", ie->data[2]);
++ pri_message(ctrl, "-%02d", ie->data[2]);
+ if (ie->len > 3)
+- pri_message(pri, " %02d", ie->data[3]);
++ pri_message(ctrl, " %02d", ie->data[3]);
+ if (ie->len > 4)
+- pri_message(pri, ":%02d", ie->data[4]);
++ pri_message(ctrl, ":%02d", ie->data[4]);
+ if (ie->len > 5)
+- pri_message(pri, ":%02d", ie->data[5]);
+- pri_message(pri, " ]\n");
++ pri_message(ctrl, ":%02d", ie->data[5]);
++ pri_message(ctrl, " ]\n");
+ }
+
+-static FUNC_DUMP(dump_keypad_facility)
++static void dump_keypad_facility(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ char tmp[64];
+
+@@ -1563,10 +2635,10 @@
+
+ memcpy(tmp, ie->data, ie->len);
+ tmp[ie->len] = '\0';
+- pri_message(pri, "%c Keypad Facility (len=%2d) [ %s ]\n", prefix, ie->len, tmp );
++ pri_message(ctrl, "%c Keypad Facility (len=%2d) [ %s ]\n", prefix, ie->len, tmp );
+ }
+
+-static FUNC_RECV(receive_keypad_facility)
++static int receive_keypad_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ int mylen;
+
+@@ -1584,27 +2656,19 @@
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_keypad_facility)
++static int transmit_keypad_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ int sublen;
+
+ sublen = strlen(call->keypad_digits);
+-
+- if (sublen > 32) {
+- sublen = 32;
+- call->keypad_digits[32] = '\0';
+- }
+-
+ if (sublen) {
+- libpri_copy_string((char *)ie->data, (char *)call->keypad_digits, sizeof(call->keypad_digits));
+- /* Make sure we clear the field */
+- call->keypad_digits[0] = '\0';
++ libpri_copy_string((char *) ie->data, call->keypad_digits, sizeof(call->keypad_digits));
+ return sublen + 2;
+ } else
+ return 0;
+ }
+
+-static FUNC_DUMP(dump_display)
++static void dump_display(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int x, y;
+ char *buf = malloc(len + 1);
+@@ -1618,7 +2682,7 @@
+ for (y=x; x<ie->len; x++)
+ buf[x] = ie->data[x] & 0x7f;
+ buf[x] = '\0';
+- pri_message(pri, "%c Display (len=%2d) %s[ %s ]\n", prefix, ie->len, tmp, &buf[y]);
++ pri_message(ctrl, "%c Display (len=%2d) %s[ %s ]\n", prefix, ie->len, tmp, &buf[y]);
+ free(buf);
+ }
+ }
+@@ -1626,10 +2690,10 @@
+ #define CHECK_OVERFLOW(limit) \
+ if (tmpptr - tmp + limit >= sizeof(tmp)) { \
+ *tmpptr = '\0'; \
+- pri_message(pri, "%s", tmpptr = tmp); \
++ pri_message(ctrl, "%s", tmpptr = tmp); \
+ }
+
+-static void dump_ie_data(struct pri *pri, unsigned char *c, int len)
++static void dump_ie_data(struct pri *ctrl, unsigned char *c, int len)
+ {
+ static char hexs[16] = "0123456789ABCDEF";
+ char tmp[1024], *tmpptr;
+@@ -1665,47 +2729,54 @@
+ if (lastascii)
+ *tmpptr++ = '\'';
+ *tmpptr = '\0';
+- pri_message(pri, "%s", tmp);
++ pri_message(ctrl, "%s", tmp);
+ }
+
+-static FUNC_DUMP(dump_facility)
++static void dump_facility(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- int dataat = (ie->data[0] & 0x80) ? 1 : 2;
+- pri_message(pri, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie));
+- dump_ie_data(pri, ie->data, ie->len);
+- pri_message(NULL, " ]\n");
++ pri_message(ctrl, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie));
++ dump_ie_data(ctrl, ie->data, ie->len);
++ pri_message(ctrl, " ]\n");
++#if 0 /* Lets not dump parse of facility contents here anymore. */
++ /*
++ * The ASN.1 decode dump has already been done when the facility ie was added to the outgoing
++ * message or the ASN.1 decode dump will be done when the facility ie is processed on incoming
++ * messages. This dump is redundant and very noisy.
++ */
+ if (ie->len > 1) {
+- pri_message(pri, "PROTOCOL %02X\n", ie->data[0] & ASN1_TYPE_MASK);
+- asn1_dump(pri, &ie->data[dataat], ie->len - dataat);
++ int dataat = (ie->data[0] & 0x80) ? 1 : 2;
++
++ pri_message(ctrl, "PROTOCOL %02X\n", ie->data[0] & Q932_PROTOCOL_MASK);
++ asn1_dump(ctrl, ie->data + dataat, ie->data + ie->len);
+ }
+-
++#endif /* Lets not dump parse of facility contents here anymore. */
+ }
+
+-static FUNC_DUMP(dump_network_spec_fac)
++static void dump_network_spec_fac(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Network-Specific Facilities (len=%2d) [ ", prefix, ie->len);
++ pri_message(ctrl, "%c Network-Specific Facilities (len=%2d) [ ", prefix, ie->len);
+ if (ie->data[0] == 0x00) {
+- pri_message(pri, "%s", code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0])));
++ pri_message(ctrl, "%s", code2str(ie->data[1], facilities, ARRAY_LEN(facilities)));
+ }
+ else
+- dump_ie_data(pri, ie->data, ie->len);
+- pri_message(pri, " ]\n");
++ dump_ie_data(ctrl, ie->data, ie->len);
++ pri_message(ctrl, " ]\n");
+ }
+
+-static FUNC_RECV(receive_network_spec_fac)
++static int receive_network_spec_fac(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_network_spec_fac)
++static int transmit_network_spec_fac(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ /* We are ready to transmit single IE only */
+ if (order > 1)
+ return 0;
+
+- if (pri->nsf != PRI_NSF_NONE) {
++ if (ctrl->nsf != PRI_NSF_NONE) {
+ ie->data[0] = 0x00;
+- ie->data[1] = pri->nsf;
++ ie->data[1] = ctrl->nsf;
+ return 4;
+ }
+ /* Leave off */
+@@ -1732,13 +2803,13 @@
+ return code2str(cause, causeclasses, sizeof(causeclasses) / sizeof(causeclasses[0]));
+ }
+
+-static FUNC_DUMP(dump_cause)
++static void dump_cause(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int x;
+- pri_message(pri, "%c Cause (len=%2d) [ Ext: %d Coding: %s (%d) Spare: %d Location: %s (%d)\n",
++ pri_message(ctrl, "%c Cause (len=%2d) [ Ext: %d Coding: %s (%d) Spare: %d Location: %s (%d)\n",
+ prefix, len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5,
+ (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf);
+- pri_message(pri, "%c Ext: %d Cause: %s (%d), class = %s (%d) ]\n",
++ pri_message(ctrl, "%c Ext: %d Cause: %s (%d), class = %s (%d) ]\n",
+ prefix, (ie->data[1] >> 7), pri_cause2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f,
+ pri_causeclass2str((ie->data[1] & 0x7f) >> 4), (ie->data[1] & 0x7f) >> 4);
+ if (ie->len < 3)
+@@ -1747,29 +2818,29 @@
+ switch(ie->data[1] & 0x7f) {
+ case PRI_CAUSE_IE_NONEXIST:
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, "%c Cause data %d: %02x (%d, %s IE)\n", prefix, x-1, ie->data[x], ie->data[x], ie2str(ie->data[x]));
++ pri_message(ctrl, "%c Cause data %d: %02x (%d, %s IE)\n", prefix, x-1, ie->data[x], ie->data[x], ie2str(ie->data[x]));
+ break;
+ case PRI_CAUSE_WRONG_CALL_STATE:
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, "%c Cause data %d: %02x (%d, %s message)\n", prefix, x-1, ie->data[x], ie->data[x], msg2str(ie->data[x]));
++ pri_message(ctrl, "%c Cause data %d: %02x (%d, %s message)\n", prefix, x-1, ie->data[x], ie->data[x], msg2str(ie->data[x]));
+ break;
+ case PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE:
+- pri_message(pri, "%c Cause data:", prefix);
++ pri_message(ctrl, "%c Cause data:", prefix);
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, " %02x", ie->data[x]);
+- pri_message(pri, " (Timer T");
++ pri_message(ctrl, " %02x", ie->data[x]);
++ pri_message(ctrl, " (Timer T");
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, "%c", ((ie->data[x] >= ' ') && (ie->data[x] < 0x7f)) ? ie->data[x] : '.');
+- pri_message(pri, ")\n");
++ pri_message(ctrl, "%c", ((ie->data[x] >= ' ') && (ie->data[x] < 0x7f)) ? ie->data[x] : '.');
++ pri_message(ctrl, ")\n");
+ break;
+ default:
+ for (x=2;x<ie->len;x++)
+- pri_message(pri, "%c Cause data %d: %02x (%d)\n", prefix, x-1, ie->data[x], ie->data[x]);
++ pri_message(ctrl, "%c Cause data %d: %02x (%d)\n", prefix, x-1, ie->data[x], ie->data[x]);
+ break;
+ }
+ }
+
+-static FUNC_RECV(receive_cause)
++static int receive_cause(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->causeloc = ie->data[0] & 0xf;
+ call->causecode = (ie->data[0] & 0x60) >> 5;
+@@ -1777,7 +2848,7 @@
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_cause)
++static int transmit_cause(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ /* We are ready to transmit single IE only */
+ if (order > 1)
+@@ -1793,23 +2864,23 @@
+ }
+ }
+
+-static FUNC_DUMP(dump_sending_complete)
++static void dump_sending_complete(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Sending Complete (len=%2d)\n", prefix, len);
++ pri_message(ctrl, "%c Sending Complete (len=%2d)\n", prefix, len);
+ }
+
+-static FUNC_RECV(receive_sending_complete)
++static int receive_sending_complete(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ /* We've got a "Complete" message: Exect no further digits. */
+ call->complete = 1;
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_sending_complete)
++static int transmit_sending_complete(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+- if ((pri->overlapdial && call->complete) || /* Explicit */
+- (!pri->overlapdial && ((pri->switchtype == PRI_SWITCH_EUROISDN_E1) ||
+- /* Implicit */ (pri->switchtype == PRI_SWITCH_EUROISDN_T1)))) {
++ if ((ctrl->overlapdial && call->complete) || /* Explicit */
++ (!ctrl->overlapdial && ((ctrl->switchtype == PRI_SWITCH_EUROISDN_E1) ||
++ /* Implicit */ (ctrl->switchtype == PRI_SWITCH_EUROISDN_T1)))) {
+ /* Include this single-byte IE */
+ return 1;
+ }
+@@ -1846,18 +2917,18 @@
+ return code2str(info, notifies, sizeof(notifies) / sizeof(notifies[0]));
+ }
+
+-static FUNC_DUMP(dump_notify)
++static void dump_notify(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Notification indicator (len=%2d): Ext: %d %s (%d)\n", prefix, len, ie->data[0] >> 7, notify2str(ie->data[0] & 0x7f), ie->data[0] & 0x7f);
++ pri_message(ctrl, "%c Notification indicator (len=%2d): Ext: %d %s (%d)\n", prefix, len, ie->data[0] >> 7, notify2str(ie->data[0] & 0x7f), ie->data[0] & 0x7f);
+ }
+
+-static FUNC_RECV(receive_notify)
++static int receive_notify(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->notify = ie->data[0] & 0x7F;
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_notify)
++static int transmit_notify(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ if (call->notify >= 0) {
+ ie->data[0] = 0x80 | call->notify;
+@@ -1866,9 +2937,9 @@
+ return 0;
+ }
+
+-static FUNC_DUMP(dump_shift)
++static void dump_shift(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c %sLocking Shift (len=%02d): Requested codeset %d\n", prefix, (full_ie & 8) ? "Non-" : "", len, full_ie & 7);
++ pri_message(ctrl, "%c %sLocking Shift (len=%02d): Requested codeset %d\n", prefix, (full_ie & 8) ? "Non-" : "", len, full_ie & 7);
+ }
+
+ static char *lineinfo2str(int info)
+@@ -1903,21 +2974,21 @@
+ return code2str(info, lineinfo, sizeof(lineinfo) / sizeof(lineinfo[0]));
+ }
+
+-static FUNC_DUMP(dump_line_information)
++static void dump_line_information(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Originating Line Information (len=%02d): %s (%d)\n", prefix, len, lineinfo2str(ie->data[0]), ie->data[0]);
++ pri_message(ctrl, "%c Originating Line Information (len=%02d): %s (%d)\n", prefix, len, lineinfo2str(ie->data[0]), ie->data[0]);
+ }
+
+-static FUNC_RECV(receive_line_information)
++static int receive_line_information(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ call->ani2 = ie->data[0];
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_line_information)
++static int transmit_line_information(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ #if 0 /* XXX Is this IE possible for 4ESS only? XXX */
+- if(pri->switchtype == PRI_SWITCH_ATT4ESS) {
++ if(ctrl->switchtype == PRI_SWITCH_ATT4ESS) {
+ ie->data[0] = 0;
+ return 3;
+ }
+@@ -1953,53 +3024,54 @@
+ return code2str(type, gdtype, sizeof(gdtype) / sizeof(gdtype[0]));
+ }
+
+-static FUNC_DUMP(dump_generic_digits)
++static void dump_generic_digits(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ int encoding;
+ int type;
+ int idx;
+ int value;
+ if (len < 3) {
+- pri_message(pri, "%c Generic Digits (len=%02d): Invalid length\n", prefix, len);
++ pri_message(ctrl, "%c Generic Digits (len=%02d): Invalid length\n", prefix, len);
+ return;
+ }
+ encoding = (ie->data[0] >> 5) & 7;
+ type = ie->data[0] & 0x1F;
+- pri_message(pri, "%c Generic Digits (len=%02d): Encoding %s Type %s\n", prefix, len, gdencoding2str(encoding), gdtype2str(type));
++ pri_message(ctrl, "%c Generic Digits (len=%02d): Encoding %s Type %s\n", prefix, len, gdencoding2str(encoding), gdtype2str(type));
+ if (encoding == 3) { /* Binary */
+- pri_message(pri, "%c Don't know how to handle binary encoding\n");
++ pri_message(ctrl, "%c Don't know how to handle binary encoding\n",
++ prefix);
+ return;
+ }
+ if (len == 3) /* No number information */
+ return;
+- pri_message(pri, "%c Digits: ");
++ pri_message(ctrl, "%c Digits: ", prefix);
+ value = 0;
+ for(idx = 3; idx < len; ++idx) {
+ switch(encoding) {
+ case 0: /* BCD even */
+ case 1: /* BCD odd */
+- pri_message(pri, "%d", ie->data[idx-2] & 0x0f);
++ pri_message(ctrl, "%d", ie->data[idx-2] & 0x0f);
+ value = value * 10 + (ie->data[idx-2] & 0x0f);
+ if(!encoding || (idx+1 < len)) { /* Special handling for BCD odd */
+- pri_message(pri, "%d", (ie->data[idx-2] >> 4) & 0x0f);
++ pri_message(ctrl, "%d", (ie->data[idx-2] >> 4) & 0x0f);
+ value = value * 10 + ((ie->data[idx-2] >> 4) & 0x0f);
+ }
+ break;
+ case 2: /* IA5 */
+- pri_message(pri, "%c", ie->data[idx-2]);
++ pri_message(ctrl, "%c", ie->data[idx-2]);
+ value = value * 10 + ie->data[idx-2] - '0';
+ break;
+ }
+ }
+ switch(type) {
+ case 4: /* Info Digits */
+- pri_message(pri, " - %s", lineinfo2str(value));
++ pri_message(ctrl, " - %s", lineinfo2str(value));
+ break;
+ }
+- pri_message(pri, "\n");
++ pri_message(ctrl, "\n");
+ }
+
+-static FUNC_RECV(receive_generic_digits)
++static int receive_generic_digits(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
+ {
+ int encoding;
+ int type;
+@@ -2009,13 +3081,13 @@
+ char number[260];
+
+ if (len < 3) {
+- pri_error(pri, "Invalid length of Generic Digits IE\n");
++ pri_error(ctrl, "Invalid length of Generic Digits IE\n");
+ return -1;
+ }
+ encoding = (ie->data[0] >> 5) & 7;
+ type = ie->data[0] & 0x1F;
+ if (encoding == 3) { /* Binary */
+- pri_message(pri, "!! Unable to handle binary encoded Generic Digits IE\n");
++ pri_message(ctrl, "!! Unable to handle binary encoded Generic Digits IE\n");
+ return 0;
+ }
+ if (len == 3) /* No number information */
+@@ -2063,10 +3135,13 @@
+ break;
+ #if 0
+ case 5: /* Callid */
+- if (!call->callernum[0]) {
+- memcpy(call->callernum, number, sizeof(call->callernum)-1);
+- call->callerpres = 0;
+- call->callerplan = 0;
++ if (!call->remote_id.number.valid) {
++ call->remote_id.number.valid = 1;
++ call->remote_id.number.presentation =
++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ call->remote_id.number.plan = PRI_UNKNOWN;
++ libpri_copy_string(call->remote_id.number.str, number,
++ sizeof(call->remote_id.number.str));
+ }
+ break;
+ #endif
+@@ -2074,13 +3149,13 @@
+ return 0;
+ }
+
+-static FUNC_SEND(transmit_generic_digits)
++static int transmit_generic_digits(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
+ {
+ #if 0 /* XXX Is this IE possible for other switches? XXX */
+ if (order > 1)
+ return 0;
+
+- if(pri->switchtype == PRI_SWITCH_NI1) {
++ if(ctrl->switchtype == PRI_SWITCH_NI1) {
+ ie->data[0] = 0x04; /* BCD even, Info Digits */
+ ie->data[1] = 0x00; /* POTS */
+ return 4;
+@@ -2119,35 +3194,54 @@
+ }
+
+
+-static FUNC_DUMP(dump_signal)
++static void dump_signal(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+- pri_message(pri, "%c Signal (len=%02d): ", prefix, len);
++ pri_message(ctrl, "%c Signal (len=%02d): ", prefix, len);
+ if (len < 3) {
+- pri_message(pri, "Invalid length\n");
++ pri_message(ctrl, "Invalid length\n");
+ return;
+ }
+- pri_message(pri, "Signal %s (%d)\n", signal2str(ie->data[0]), ie->data[0]);
++ pri_message(ctrl, "Signal %s (%d)\n", signal2str(ie->data[0]), ie->data[0]);
+ }
+
+-static FUNC_DUMP(dump_transit_count)
++static void dump_transit_count(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
+ {
+ /* Defined in ECMA-225 */
+- pri_message(pri, "%c Transit Count (len=%02d): ", prefix, len);
++ pri_message(ctrl, "%c Transit Count (len=%02d): ", prefix, len);
+ if (len < 3) {
+- pri_message(pri, "Invalid length\n");
++ pri_message(ctrl, "Invalid length\n");
+ return;
+ }
+- pri_message(pri, "Count=%d (0x%02x)\n", ie->data[0] & 0x1f, ie->data[0] & 0x1f);
++ pri_message(ctrl, "Count=%d (0x%02x)\n", ie->data[0] & 0x1f, ie->data[0] & 0x1f);
+ }
+
++static void dump_reverse_charging_indication(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
++{
++ pri_message(ctrl, "%c Reverse Charging Indication (len=%02d): %d\n", prefix, len, ie->data[0] & 0x7);
++}
+
++static int receive_reverse_charging_indication(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len)
++{
++ call->reversecharge = ie->data[0] & 0x7;
++ return 0;
++}
++
++static int transmit_reverse_charging_indication(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order)
++{
++ if (call->reversecharge != PRI_REVERSECHARGE_NONE) {
++ ie->data[0] = 0x80 | (call->reversecharge & 0x7);
++ return 3;
++ }
++ return 0;
++}
++
+ static struct ie ies[] = {
+ /* Codeset 0 - Common */
+- { 1, NATIONAL_CHANGE_STATUS, "Change Status" },
++ { 1, NATIONAL_CHANGE_STATUS, "Change Status", dump_change_status, receive_change_status, transmit_change_status },
+ { 0, Q931_LOCKING_SHIFT, "Locking Shift", dump_shift },
+ { 0, Q931_BEARER_CAPABILITY, "Bearer Capability", dump_bearer_capability, receive_bearer_capability, transmit_bearer_capability },
+ { 0, Q931_CAUSE, "Cause", dump_cause, receive_cause, transmit_cause },
+- { 1, Q931_CALL_STATE, "Call State", dump_call_state, receive_call_state, transmit_call_state },
++ { 1, Q931_IE_CALL_STATE, "Call State", dump_call_state, receive_call_state, transmit_call_state },
+ { 0, Q931_CHANNEL_IDENT, "Channel Identification", dump_channel_id, receive_channel_id, transmit_channel_id },
+ { 0, Q931_PROGRESS_INDICATOR, "Progress Indicator", dump_progress_indicator, receive_progress_indicator, transmit_progress_indicator },
+ { 0, Q931_NETWORK_SPEC_FAC, "Network-Specific Facilities", dump_network_spec_fac, receive_network_spec_fac, transmit_network_spec_fac },
+@@ -2157,11 +3251,11 @@
+ { 1, Q931_BINARY_PARAMETERS, "Packet-layer Binary Parameters" },
+ { 1, Q931_WINDOW_SIZE, "Packet-layer Window Size" },
+ { 1, Q931_CLOSED_USER_GROUP, "Closed User Group" },
+- { 1, Q931_REVERSE_CHARGE_INDIC, "Reverse Charging Indication" },
++ { 1, Q931_REVERSE_CHARGE_INDIC, "Reverse Charging Indication", dump_reverse_charging_indication, receive_reverse_charging_indication, transmit_reverse_charging_indication },
+ { 1, Q931_CALLING_PARTY_NUMBER, "Calling Party Number", dump_calling_party_number, receive_calling_party_number, transmit_calling_party_number },
+- { 1, Q931_CALLING_PARTY_SUBADDR, "Calling Party Subaddress", dump_calling_party_subaddr, receive_calling_party_subaddr },
++ { 1, Q931_CALLING_PARTY_SUBADDR, "Calling Party Subaddress", dump_calling_party_subaddr, receive_calling_party_subaddr, transmit_calling_party_subaddr },
+ { 1, Q931_CALLED_PARTY_NUMBER, "Called Party Number", dump_called_party_number, receive_called_party_number, transmit_called_party_number },
+- { 1, Q931_CALLED_PARTY_SUBADDR, "Called Party Subaddress", dump_called_party_subaddr },
++ { 1, Q931_CALLED_PARTY_SUBADDR, "Called Party Subaddress", dump_called_party_subaddr, receive_called_party_subaddr, transmit_called_party_subaddr },
+ { 0, Q931_REDIRECTING_NUMBER, "Redirecting Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number },
+ { 1, Q931_REDIRECTING_SUBADDR, "Redirecting Subaddress", dump_redirecting_subaddr },
+ { 0, Q931_TRANSIT_NET_SELECT, "Transit Network Selection" },
+@@ -2170,7 +3264,7 @@
+ { 0, Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" },
+ { 1, Q931_PACKET_SIZE, "Packet Size" },
+ { 0, Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility },
+- { 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number" },
++ { 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number", dump_redirection_number, receive_redirection_number, transmit_redirection_number },
+ { 1, Q931_IE_REDIRECTION_SUBADDR, "Redirection Subaddress" },
+ { 1, Q931_IE_FEATURE_ACTIVATE, "Feature Activation" },
+ { 1, Q931_IE_INFO_REQUEST, "Feature Request" },
+@@ -2187,15 +3281,18 @@
+ { 1, Q931_IE_USER_USER, "User-User", dump_user_user, receive_user_user, transmit_user_user },
+ { 1, Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" },
+ { 1, Q931_IE_CALL_STATUS, "Call Status" },
+- { 1, Q931_IE_CHANGE_STATUS, "Change Status" },
++ { 1, Q931_IE_CHANGE_STATUS, "Change Status", dump_change_status, receive_change_status, transmit_change_status },
+ { 1, Q931_IE_CONNECTED_ADDR, "Connected Number", dump_connected_number },
+- { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number },
++ { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number, receive_connected_number, transmit_connected_number },
++ { 1, Q931_IE_CONNECTED_SUBADDR, "Connected Subaddress", dump_connected_subaddr, receive_connected_subaddr, transmit_connected_subaddr },
+ { 1, Q931_IE_ORIGINAL_CALLED_NUMBER, "Original Called Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number },
+ { 1, Q931_IE_USER_USER_FACILITY, "User-User Facility" },
+ { 1, Q931_IE_UPDATE, "Update" },
+ { 1, Q931_SENDING_COMPLETE, "Sending Complete", dump_sending_complete, receive_sending_complete, transmit_sending_complete },
+ /* Codeset 4 - Q.SIG specific */
+ { 1, QSIG_IE_TRANSIT_COUNT | Q931_CODESET(4), "Transit Count", dump_transit_count },
++ /* Codeset 5 - National specific (ETSI PISN specific) */
++ { 1, Q931_CALLING_PARTY_CATEGORY, "Calling Party Category", dump_calling_party_category },
+ /* Codeset 6 - Network specific */
+ { 1, Q931_IE_ORIGINATING_LINE_INFO, "Originating Line Information", dump_line_information, receive_line_information, transmit_line_information },
+ { 1, Q931_IE_FACILITY | Q931_CODESET(6), "Facility", dump_facility, receive_facility, transmit_facility },
+@@ -2264,7 +3361,7 @@
+ return 2 + ie->len;
+ }
+
+-static char *msg2str(int msg)
++const char *msg2str(int msg)
+ {
+ unsigned int x;
+ for (x=0;x<sizeof(msgs) / sizeof(msgs[0]); x++)
+@@ -2273,35 +3370,64 @@
+ return "Unknown Message Type";
+ }
+
++static char *maintenance_msg2str(int msg, int pd)
++{
++ unsigned int x, max;
++ struct msgtype *m = NULL;
++
++ if (pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) {
++ m = att_maintenance_msgs;
++ max = ARRAY_LEN(att_maintenance_msgs);
++ } else {
++ m = national_maintenance_msgs;
++ max = ARRAY_LEN(national_maintenance_msgs);
++ }
++
++ for (x = 0; x < max; x++) {
++ if (m[x].msgnum == msg) {
++ return m[x].name;
++ }
++ }
++ return "Unknown Message Type";
++}
++
++/* Decode the call reference */
+ static inline int q931_cr(q931_h *h)
+ {
+- int cr = 0;
++ int cr;
+ int x;
++
+ if (h->crlen > 3) {
+ pri_error(NULL, "Call Reference Length Too long: %d\n", h->crlen);
+- return -1;
++ return Q931_DUMMY_CALL_REFERENCE;
+ }
+ switch (h->crlen) {
+- case 2:
+- for (x=0;x<h->crlen;x++) {
+- cr <<= 8;
+- cr |= h->crv[x];
+- }
+- break;
+- case 1:
+- cr = h->crv[0];
+- if (cr & 0x80) {
+- cr &= ~0x80;
+- cr |= 0x8000;
+- }
+- break;
+- default:
+- pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen);
++ case 2:
++ cr = 0;
++ for (x = 0; x < h->crlen; ++x) {
++ cr <<= 8;
++ cr |= h->crv[x];
++ }
++ break;
++ case 1:
++ cr = h->crv[0];
++ if (cr & 0x80) {
++ cr &= ~0x80;
++ cr |= 0x8000;
++ }
++ break;
++ case 0:
++ cr = Q931_DUMMY_CALL_REFERENCE;
++ break;
++ default:
++ pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen);
++ cr = Q931_DUMMY_CALL_REFERENCE;
++ break;
+ }
+ return cr;
+ }
+
+-static inline void q931_dumpie(struct pri *pri, int codeset, q931_ie *ie, char prefix)
++static inline void q931_dumpie(struct pri *ctrl, int codeset, q931_ie *ie, char prefix)
+ {
+ unsigned int x;
+ int full_ie = Q931_FULL_IE(codeset, ie->ie);
+@@ -2315,7 +3441,7 @@
+ for (x = 0; x + 2 < ielen(ie); ++x)
+ buflen += sprintf(buf + buflen, " %02x", ie->data[x]);
+ }
+- pri_message(pri, "%c [%02x%s]\n", prefix, ie->ie, buf);
++ pri_message(ctrl, "%c [%02x%s]\n", prefix, ie->ie, buf);
+ free(buf);
+
+ /* Special treatment for shifts */
+@@ -2324,130 +3450,306 @@
+
+ base_ie = (((full_ie & ~0x7f) == Q931_FULL_IE(0, 0x80)) && ((full_ie & 0x70) != 0x20)) ? full_ie & ~0x0f : full_ie;
+
+- for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++)
++ for (x = 0; x < ARRAY_LEN(ies); ++x)
+ if (ies[x].ie == base_ie) {
+ if (ies[x].dump)
+- ies[x].dump(full_ie, pri, ie, ielen(ie), prefix);
++ ies[x].dump(full_ie, ctrl, ie, ielen(ie), prefix);
+ else
+- pri_message(pri, "%c IE: %s (len = %d)\n", prefix, ies[x].name, ielen(ie));
++ pri_message(ctrl, "%c IE: %s (len = %d)\n", prefix, ies[x].name, ielen(ie));
+ return;
+ }
+
+- pri_error(pri, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie));
++ pri_error(ctrl, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie));
+ }
+
+-static q931_call *q931_getcall(struct pri *pri, int cr, int outboundnew)
++/*!
++ * \brief Initialize the call record.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ *
++ * \note The call record is assumed to already be memset() to zero.
++ *
++ * \return Nothing
++ */
++void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr)
+ {
+- q931_call *cur, *prev;
++ call->cr = cr;
++ call->slotmap = -1;
++ call->channelno = -1;
++ if (cr != Q931_DUMMY_CALL_REFERENCE) {
++ call->newcall = 1;
++ }
++ call->ourcallstate = Q931_CALL_STATE_NULL;
++ call->peercallstate = Q931_CALL_STATE_NULL;
++ call->sugcallstate = Q931_CALL_STATE_NOT_SET;
++ call->ri = -1;
++ call->transcapability = -1;
++ call->transmoderate = -1;
++ call->transmultiple = -1;
++ call->userl1 = -1;
++ call->userl2 = -1;
++ call->userl3 = -1;
++ call->rateadaption = -1;
++ call->progress = -1;
++ call->causecode = -1;
++ call->causeloc = -1;
++ call->cause = -1;
++ call->useruserprotocoldisc = -1;
++ call->aoc_units = -1;
++ call->changestatus = -1;
++ call->reversecharge = -1;
++ call->pri_winner = -1;
++ call->master_call = call;
++ q931_party_number_init(&call->redirection_number);
++ q931_party_address_init(&call->called);
++ q931_party_id_init(&call->local_id);
++ q931_party_id_init(&call->remote_id);
++ q931_party_redirecting_init(&call->redirecting);
++
++ /* PRI is set to whoever called us */
++ if (BRI_TE_PTMP(ctrl)) {
++ /*
++ * Point to the master to avoid stale pointer problems if
++ * the TEI is removed later.
++ */
++ call->pri = PRI_MASTER(ctrl);
++ } else {
++ call->pri = ctrl;
++ }
++}
++
++static q931_call *q931_getcall(struct pri *ctrl, int cr)
++{
++ q931_call *cur;
++ q931_call *prev;
+ struct pri *master;
+
++ if (cr == Q931_DUMMY_CALL_REFERENCE) {
++ return ctrl->dummy_call;
++ }
++
+ /* Find the master - He has the call pool */
+- if (pri->master)
+- master = pri->master;
+- else
+- master = pri;
+-
++ master = PRI_MASTER(ctrl);
++
+ cur = *master->callpool;
+ prev = NULL;
+- while(cur) {
+- if (cur->cr == cr)
++ while (cur) {
++ if (cur->cr == cr) {
++ /* Found existing call. */
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_GR303_EOC:
++ case PRI_SWITCH_GR303_EOC_PATH:
++ case PRI_SWITCH_GR303_TMC:
++ case PRI_SWITCH_GR303_TMC_SWITCHING:
++ break;
++ default:
++ if (!ctrl->bri) {
++ /* PRI is set to whoever called us */
++ cur->pri = ctrl;
++ }
++ break;
++ }
+ return cur;
++ }
+ prev = cur;
+ cur = cur->next;
+ }
++
+ /* No call exists, make a new one */
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "-- Making new call for cr %d\n", cr);
+-
+- if (!(cur = calloc(1, sizeof(*cur))))
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "-- Making new call for cr %d\n", cr);
++ }
++
++ cur = calloc(1, sizeof(*cur));
++ if (!cur) {
+ return NULL;
++ }
+
+- call_init(cur);
+- /* Call reference */
+- cur->cr = cr;
+- /* PRI is set to whoever called us */
+- if (pri->bri && (pri->localtype == PRI_CPE) && pri->subchannel && outboundnew)
+- cur->pri = pri->subchannel;
+- else
+- cur->pri = pri;
++ /* Initialize call structure. */
++ q931_init_call_record(ctrl, cur, cr);
+
+ /* Append to end of list */
+- if (prev)
++ if (prev) {
+ prev->next = cur;
+- else
++ } else {
+ *master->callpool = cur;
+-
++ }
++
+ return cur;
+ }
+
+-q931_call *q931_new_call(struct pri *pri)
++q931_call *q931_new_call(struct pri *ctrl)
+ {
+ q931_call *cur;
+
+ do {
+- cur = *pri->callpool;
+- pri->cref++;
+- if (!pri->bri) {
+- if (pri->cref > 32767)
+- pri->cref = 1;
++ cur = *ctrl->callpool;
++ ctrl->cref++;
++ if (!ctrl->bri) {
++ if (ctrl->cref > 32767)
++ ctrl->cref = 1;
+ } else {
+- if (pri->cref > 127)
+- pri->cref = 1;
++ if (ctrl->cref > 127)
++ ctrl->cref = 1;
+ }
+ while(cur) {
+- if (cur->cr == (0x8000 | pri->cref))
++ if (cur->cr == (0x8000 | ctrl->cref))
+ break;
+ cur = cur->next;
+ }
+ } while(cur);
+
+- return q931_getcall(pri, pri->cref | 0x8000, 1);
++ return q931_getcall(ctrl, ctrl->cref | 0x8000);
+ }
+
+-static void q931_destroy(struct pri *pri, int cr, q931_call *c)
++static void stop_t303(struct q931_call *call);
++
++static void cleanup_and_free_call(struct q931_call *cur)
+ {
+- q931_call *cur, *prev;
++ stop_t303(cur);
++ pri_schedule_del(cur->pri, cur->retranstimer);
++ pri_call_apdu_queue_cleanup(cur);
++ free(cur);
++}
+
++static void pri_create_fake_clearing(struct q931_call *c, struct pri *master);
++
++void q931_destroycall(struct pri *ctrl, q931_call *c)
++{
++ q931_call *cur;
++ q931_call *prev;
++ q931_call *slave;
++ int i;
++ int slavesleft;
++ int slaveidx;
++
++ if (q931_is_dummy_call(c)) {
++ /* Cannot destroy the dummy call. */
++ return;
++ }
++ if (c->master_call != c) {
++ slave = c;
++ c = slave->master_call;
++ } else {
++ slave = NULL;
++ }
++
+ /* For destroying, make sure we are using the master span, since it maintains the call pool */
+- for (;pri->master; pri = pri->master);
++ ctrl = PRI_MASTER(ctrl);
+
+ prev = NULL;
+- cur = *pri->callpool;
+- while(cur) {
+- if ((c && (cur == c)) || (!c && (cur->cr == cr))) {
++ cur = *ctrl->callpool;
++ while (cur) {
++ if (cur == c) {
++ slaveidx = -1;
++ if (slave) {
++ for (i = 0; i < Q931_MAX_TEI; i++) {
++ if (cur->subcalls[i] == slave) {
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "Destroying subcall %p of call %p at %d\n",
++ slave, cur, i);
++ }
++ cleanup_and_free_call(slave);
++ cur->subcalls[i] = NULL;
++ slaveidx = i;
++ break;
++ }
++ }
++ }
++
++ slavesleft = 0;
++ for (i = 0; i < Q931_MAX_TEI; i++) {
++ if (cur->subcalls[i]) {
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "Subcall still present at %d\n", i);
++ }
++ slavesleft++;
++ }
++ }
++
++ /* We have 3 different phases to deal with:
++ * 1.) Sent outbound call, but no response, indicated by t203 present
++ * 2.) Sent outbound call, with responses, indicated by lack of t203 and subcalls present
++ * 3.) Outbound call connected, indicated by pri_winner > -1
++ *
++ * If chan_dahdi hangs up in phase:
++ * 1.) T303 will be present, and we will fake clear in this case
++ * 2.) pri_winner will be < 0 and subcalls will be present.
++ * 3.) pri_winner will be > -1 and we will free the master when the winner dies.
++ *
++ * If remote ends hang up in phase:
++ * 1.) Impossible, defined by phase.
++ * 2.) When last end hangs up, we should cause a fake clearing.
++ * 3.) Pass events to winner up and be freed when winner is freed
++ *
++ * Exceptional conditions in phase:
++ * 1.) None.
++ * 2.) None.
++ * 3.) We hang up a call so quickly that it hangs up before other competing lines finish hangup sequence
++ * Subcalls present still even though we have hung up the winner.
++ *
++ * So, we could say:
++ * If, when the library user hangs up the master call, and there are more than one subcall up, we fake clear
++ * regardless of whether or not we drop down to one subcall left in the clearing process.
++ *
++ * If there are only one call up, we mirror what it does.
++ *
++ * OR
++ *
++ * Phase 2. them clearing:
++ * For handling of Phase 2 (indicated by not running and pri_winner not present):
++ * We create a fake hangup sequence after all the subcalls have been destroyed and after
++ *
++ * "" us clearing:
++ * For we need to start the fake clearing, but it needs to be half of a fake clearing, not a full one (since we already had a hangup).
++ *
++ * For handling of Phase 3 plus exceptions:
++ *
++ * If pri_winner exists, we mirror him in terms of events (which provides our hangup sequence), and when we have the complete
++ * hangup sequence completed (destroy called on master call), if there still exist non winner subcalls at this time, we declare the master
++ * call as dead and free it when the last subcall clears.
++ */
++
++ if ((slave && !slavesleft) &&
++ ((cur->pri_winner < 0) || (slave && slaveidx != cur->pri_winner))) {
++ pri_create_fake_clearing(cur, ctrl);
++ return;
++ }
++
++ if (slavesleft) {
++ return;
++ }
++
++ /* Master call or normal call destruction. */
++ if ((cur->pri_winner > -1) && cur->outboundbroadcast) {
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl,
++ "Since we already had a winner, we should just be able to kill the call anyways\n");
++ }
++ }
+ if (prev)
+ prev->next = cur->next;
+ else
+- *pri->callpool = cur->next;
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate));
+- if (cur->retranstimer)
+- pri_schedule_del(pri, cur->retranstimer);
+- pri_call_apdu_queue_cleanup(cur);
+- free(cur);
++ *ctrl->callpool = cur->next;
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl,
++ "NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s, hold-state %s\n",
++ q931_call_state_str(cur->ourcallstate),
++ q931_call_state_str(cur->peercallstate),
++ q931_hold_state_str(cur->hold_state));
++ pri_schedule_del(ctrl, cur->hold_timer);
++ cleanup_and_free_call(cur);
+ return;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+- pri_error(pri, "Can't destroy call %d!\n", cr);
++ pri_error(ctrl, "Can't destroy call %p cref:%d!\n", c, c->cr);
+ }
+
+-static void q931_destroycall(struct pri *pri, int cr)
++static int add_ie(struct pri *ctrl, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen, int *codeset)
+ {
+- return q931_destroy(pri, cr, NULL);
+-}
+-
+-
+-void __q931_destroycall(struct pri *pri, q931_call *c)
+-{
+- if (pri && c)
+- q931_destroy(pri,0, c);
+- return;
+-}
+-
+-static int add_ie(struct pri *pri, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen, int *codeset)
+-{
+ unsigned int x;
+ int res, total_res;
+ int have_shift;
+@@ -2473,7 +3775,7 @@
+ total_res = 0;
+ do {
+ iet->ie = ie;
+- res = ies[x].transmit(ie, pri, call, msgtype, iet, maxlen, ++order);
++ res = ies[x].transmit(ie, ctrl, call, msgtype, iet, maxlen, ++order);
+ /* Error if res < 0 or ignored if res == 0 */
+ if (res < 0)
+ return res;
+@@ -2484,8 +3786,7 @@
+ maxlen -= res;
+ iet = (q931_ie *)((char *)iet + res);
+ }
+- }
+- while (res > 0 && order < ies_count);
++ } while (res > 0 && order < ies_count);
+ if (have_shift && total_res) {
+ if (Q931_IE_CODESET(ies[x].ie))
+ *codeset = Q931_IE_CODESET(ies[x].ie);
+@@ -2493,12 +3794,12 @@
+ }
+ return total_res;
+ } else {
+- pri_error(pri, "!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie);
++ pri_error(ctrl, "!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie);
+ return -1;
+ }
+ }
+ }
+- pri_error(pri, "!! Unknown IE %d (%s)\n", ie, ie2str(ie));
++ pri_error(ctrl, "!! Unknown IE %d (%s)\n", ie, ie2str(ie));
+ return -1;
+ }
+
+@@ -2513,25 +3814,37 @@
+ return code2str(disc, discs, sizeof(discs) / sizeof(discs[0]));
+ }
+
+-void q931_dump(struct pri *pri, q931_h *h, int len, int txrx)
++void q931_dump(struct pri *ctrl, q931_h *h, int len, int txrx)
+ {
+ q931_mh *mh;
+ char c;
+ int x=0, r;
+ int cur_codeset;
+ int codeset;
++ int cref;
++
+ c = txrx ? '>' : '<';
+- pri_message(pri, "%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len);
+- pri_message(pri, "%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n", c, h->crlen, q931_cr(h) & 0x7FFF, q931_cr(h) & 0x7FFF, (h->crv[0] & 0x80) ? "Terminator" : "Originator");
++ pri_message(ctrl, "%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len);
++ cref = q931_cr(h);
++ pri_message(ctrl, "%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n",
++ c, h->crlen, cref & 0x7FFF, cref & 0x7FFF,
++ (cref == Q931_DUMMY_CALL_REFERENCE)
++ ? "Dummy"
++ : (cref & 0x8000) ? "Terminator" : "Originator");
++
+ /* Message header begins at the end of the call reference number */
+ mh = (q931_mh *)(h->contents + h->crlen);
+- pri_message(pri, "%c Message type: %s (%d)\n", c, msg2str(mh->msg), mh->msg);
++ if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
++ pri_message(ctrl, "%c Message Type: %s (%d)\n", c, maintenance_msg2str(mh->msg, h->pd), mh->msg);
++ } else {
++ pri_message(ctrl, "%c Message Type: %s (%d)\n", c, msg2str(mh->msg), mh->msg);
++ }
+ /* Drop length of header, including call reference */
+ len -= (h->crlen + 3);
+ codeset = cur_codeset = 0;
+ while(x < len) {
+ r = ielen((q931_ie *)(mh->data + x));
+- q931_dumpie(pri, cur_codeset, (q931_ie *)(mh->data + x), c);
++ q931_dumpie(ctrl, cur_codeset, (q931_ie *)(mh->data + x), c);
+ switch (mh->data[x] & 0xf8) {
+ case Q931_LOCKING_SHIFT:
+ if ((mh->data[x] & 7) > 0)
+@@ -2547,86 +3860,106 @@
+ x += r;
+ }
+ if (x > len)
+- pri_error(pri, "XXX Message longer than it should be?? XXX\n");
++ pri_error(ctrl, "XXX Message longer than it should be?? XXX\n");
+ }
+
+-static int q931_handle_ie(int codeset, struct pri *pri, q931_call *c, int msg, q931_ie *ie)
++static int q931_handle_ie(int codeset, struct pri *ctrl, q931_call *c, int msg, q931_ie *ie)
+ {
+ unsigned int x;
+ int full_ie = Q931_FULL_IE(codeset, ie->ie);
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "-- Processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl, "-- Processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
+ for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) {
+ if (full_ie == ies[x].ie) {
+ if (ies[x].receive)
+- return ies[x].receive(full_ie, pri, c, msg, ie, ielen(ie));
++ return ies[x].receive(full_ie, ctrl, c, msg, ie, ielen(ie));
+ else {
+- if (pri->debug & PRI_DEBUG_Q931_ANOMALY)
+- pri_error(pri, "!! No handler for IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
++ if (ctrl->debug & PRI_DEBUG_Q931_ANOMALY)
++ pri_error(ctrl, "!! No handler for IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
+ return -1;
+ }
+ }
+ }
+- pri_message(pri, "!! Unknown IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
++ pri_message(ctrl, "!! Unknown IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie));
+ return -1;
+ }
+
+-static void init_header(struct pri *pri, q931_call *call, unsigned char *buf, q931_h **hb, q931_mh **mhb, int *len)
++/* Returns header and message header and modifies length in place */
++static void init_header(struct pri *ctrl, q931_call *call, unsigned char *buf, q931_h **hb, q931_mh **mhb, int *len, int protodisc)
+ {
+- /* Returns header and message header and modifies length in place */
+- q931_h *h = (q931_h *)buf;
+- q931_mh * mh;
+- h->pd = pri->protodisc;
++ q931_h *h = (q931_h *) buf;
++ q931_mh *mh;
++ unsigned crv;
++
++ if (protodisc) {
++ h->pd = protodisc;
++ } else {
++ h->pd = ctrl->protodisc;
++ }
+ h->x0 = 0; /* Reserved 0 */
+- if (!pri->bri) {
+- h->crlen = 2; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */
+- if (call->cr || call->forceinvert) {
+- h->crv[0] = ((call->cr ^ 0x8000) & 0xff00) >> 8;
+- h->crv[1] = (call->cr & 0xff);
+- } else {
+- /* Unless of course this has no call reference */
+- h->crv[0] = 0;
+- h->crv[1] = 0;
+- }
+- if (pri->subchannel && !pri->bri) {
++ if (q931_is_dummy_call(call)) {
++ h->crlen = 0;
++ } else if (!ctrl->bri) {
++ /* Two bytes of Call Reference. */
++ h->crlen = 2;
++ /* Invert the top bit to make it from our sense */
++ crv = (unsigned) call->cr;
++ h->crv[0] = ((crv >> 8) ^ 0x80) & 0xff;
++ h->crv[1] = crv & 0xff;
++ if (ctrl->subchannel && !ctrl->bri) {
+ /* On GR-303, top bit is always 0 */
+ h->crv[0] &= 0x7f;
+ }
+ } else {
+ h->crlen = 1;
+- if (call->cr || call->forceinvert) {
+- h->crv[0] = (((call->cr ^ 0x8000) & 0x8000) >> 8) | (call->cr & 0x7f);
+- } else {
+- /* Unless of course this has no call reference */
+- h->crv[0] = 0;
+- }
++ /* Invert the top bit to make it from our sense */
++ crv = (unsigned) call->cr;
++ h->crv[0] = (((crv >> 8) ^ 0x80) & 0x80) | (crv & 0x7f);
+ }
+- mh = (q931_mh *)(h->contents + h->crlen);
++ *hb = h;
++
++ *len -= 3;/* Protocol discriminator, call reference length, message type id */
++ *len -= h->crlen;
++
++ mh = (q931_mh *) (h->contents + h->crlen);
+ mh->f = 0;
+- *hb = h;
+ *mhb = mh;
+- if (h->crlen == 2)
+- *len -= 5;
+- else
+- *len -= 4;
+-
+ }
+
+-static int q931_xmit(struct pri *pri, q931_h *h, int len, int cr)
++static int q931_xmit(struct pri *ctrl, q931_h *h, int len, int cr, int uiframe)
+ {
+- q921_transmit_iframe(pri, h, len, cr);
++ if (uiframe) {
++ q921_transmit_uiframe(ctrl, h, len);
++ } else {
++ q921_transmit_iframe(ctrl, h, len, cr);
++ }
+ /* The transmit operation might dump the q921 header, so logging the q931
+ message body after the transmit puts the sections of the message in the
+ right order in the log */
+- if (pri->debug & PRI_DEBUG_Q931_DUMP)
+- q931_dump(pri, h, len, 1);
++ if (ctrl->debug & PRI_DEBUG_Q931_DUMP)
++ q931_dump(ctrl, h, len, 1);
+ #ifdef LIBPRI_COUNTERS
+- pri->q931_txcount++;
++ ctrl->q931_txcount++;
+ #endif
+ return 0;
+ }
+
+-static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[])
++/*!
++ * \internal
++ * \brief Build and send the requested message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param msgtype Q.931 message type to build.
++ * \param ies List of ie's to put in the message.
++ *
++ * \note The ie's in the ie list must be in numerical order.
++ * See Q.931 section 4.5.1 coding rules.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[])
+ {
+ unsigned char buf[1024];
+ q931_h *h;
+@@ -2636,18 +3969,24 @@
+ int offset=0;
+ int x;
+ int codeset;
+-
++
++ if (call->outboundbroadcast && call->master_call == call && msgtype != Q931_SETUP) {
++ pri_error(ctrl,
++ "Attempting to use master call record to send %s on BRI PTMP NT %p\n",
++ msg2str(msgtype), ctrl);
++ return -1;
++ }
++
+ memset(buf, 0, sizeof(buf));
+ len = sizeof(buf);
+- init_header(pri, c, buf, &h, &mh, &len);
+- mh->msg = msgtype;
++ init_header(ctrl, call, buf, &h, &mh, &len, (msgtype >> 8));
++ mh->msg = msgtype & 0x00ff;
+ x=0;
+ codeset = 0;
+ while(ies[x] > -1) {
+- res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset);
+-
++ res = add_ie(ctrl, call, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset);
+ if (res < 0) {
+- pri_error(pri, "!! Unable to add IE '%s'\n", ie2str(ies[x]));
++ pri_error(ctrl, "!! Unable to add IE '%s'\n", ie2str(ies[x]));
+ return -1;
+ }
+
+@@ -2657,20 +3996,121 @@
+ }
+ /* Invert the logic */
+ len = sizeof(buf) - len;
+- q931_xmit(c->pri, h, len, 1);
+- c->acked = 1;
++
++ ctrl = call->pri;
++ if (BRI_TE_PTMP(ctrl)) {
++ /*
++ * Must use the BRI subchannel structure to send with the correct TEI.
++ * Note: If the subchannel is NULL then there is no TEI assigned and
++ * we should not be sending anything out at this time.
++ */
++ ctrl = ctrl->subchannel;
++ }
++ if (ctrl) {
++ int uiframe;
++
++ switch (msgtype) {
++ case Q931_SETUP:
++ /*
++ * For NT-PTMP mode, we need to check the following:
++ * MODE = NT-PTMP
++ * MESSAGE = SETUP
++ *
++ * If those are true, we need to send the SETUP in a UI frame
++ * instead of an I-frame.
++ */
++ if (BRI_NT_PTMP(ctrl))
++ uiframe = 1;
++ else
++ uiframe = 0;
++ break;
++ case Q931_FACILITY:
++ if (ctrl->tei == Q921_TEI_GROUP) {
++ /* Broadcast TEI. */
++ if (q931_is_dummy_call(call)) {
++ /*
++ * This is a FACILITY message on the dummy call reference
++ * for the broadcast TEI.
++ */
++ uiframe = 1;
++ } else {
++ pri_error(ctrl,
++ "Attempting to broadcast %s on cref %d\n",
++ msg2str(msgtype), call->cr);
++ return -1;
++ }
++ } else {
++ uiframe = 0;
++ }
++ break;
++ default:
++ uiframe = 0;
++ break;
++ }
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl,
++ "Sending message for call %p on %p TEI/SAPI %d/%d, call->pri is %p, TEI/SAPI %d/%d\n",
++ call,
++ ctrl, ctrl->tei, ctrl->sapi,
++ call->pri, call->pri->tei, call->pri->sapi);
++ }
++ q931_xmit(ctrl, h, len, 1, uiframe);
++ }
++ call->acked = 1;
+ return 0;
+ }
+
+-static int status_ies[] = { Q931_CAUSE, Q931_CALL_STATE, -1 };
++static int maintenance_service_ies[] = { Q931_IE_CHANGE_STATUS, Q931_CHANNEL_IDENT, -1 };
+
+-static int q931_status(struct pri *pri, q931_call *c, int cause)
++int maintenance_service_ack(struct pri *ctrl, q931_call *c)
+ {
++ int pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1;
++ int mt = ATT_SERVICE_ACKNOWLEDGE;
++
++ if (ctrl->switchtype == PRI_SWITCH_NI2) {
++ pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2;
++ mt = NATIONAL_SERVICE_ACKNOWLEDGE;
++ }
++ return send_message(ctrl, c, (pd << 8) | mt, maintenance_service_ies);
++}
++
++int maintenance_service(struct pri *ctrl, int span, int channel, int changestatus)
++{
++ struct q931_call *c;
++ int pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1;
++ int mt = ATT_SERVICE;
++
++ c = q931_getcall(ctrl, 0 | 0x8000);
++ if (!c) {
++ return -1;
++ }
++ if (channel > -1) {
++ c->channelno = channel & 0xff;
++ c->chanflags = FLAG_EXCLUSIVE;
++ } else {
++ c->channelno = channel;
++ c->chanflags = FLAG_EXCLUSIVE | FLAG_WHOLE_INTERFACE;
++ }
++ c->ds1no = span;
++ c->ds1explicit = 0;
++ c->changestatus = changestatus;
++
++ if (ctrl->switchtype == PRI_SWITCH_NI2) {
++ pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2;
++ mt = NATIONAL_SERVICE;
++ }
++ return send_message(ctrl, c, (pd << 8) | mt, maintenance_service_ies);
++}
++
++static int status_ies[] = { Q931_CAUSE, Q931_IE_CALL_STATE, -1 };
++
++static int q931_status(struct pri *ctrl, q931_call *c, int cause)
++{
+ q931_call *cur = NULL;
+ if (!cause)
+ cause = PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY;
+ if (c->cr > -1)
+- cur = *pri->callpool;
++ cur = *ctrl->callpool;
+ while(cur) {
+ if (cur->cr == c->cr) {
+ cur->cause=cause;
+@@ -2681,79 +4121,156 @@
+ cur = cur->next;
+ }
+ if (!cur) {
+- pri_message(pri, "YYY Here we get reset YYY\n");
++ pri_message(ctrl, "YYY Here we get reset YYY\n");
+ /* something went wrong, respond with "no such call" */
+ c->ourcallstate = Q931_CALL_STATE_NULL;
+ c->peercallstate = Q931_CALL_STATE_NULL;
+ cur=c;
+ }
+- return send_message(pri, cur, Q931_STATUS, status_ies);
++ return send_message(ctrl, cur, Q931_STATUS, status_ies);
+ }
+
+-static int information_ies[] = { Q931_IE_KEYPAD_FACILITY, Q931_CALLED_PARTY_NUMBER, -1 };
++static int information_ies[] = { Q931_CALLED_PARTY_NUMBER, -1 };
+
+-int q931_information(struct pri *pri, q931_call *c, char digit)
++int q931_information(struct pri *ctrl, q931_call *c, char digit)
+ {
+- c->callednum[0] = digit;
+- c->callednum[1] = '\0';
+- return send_message(pri, c, Q931_INFORMATION, information_ies);
++ c->overlap_digits[0] = digit;
++ c->overlap_digits[1] = '\0';
++
++ /*
++ * Since we are doing overlap dialing now, we need to accumulate
++ * the digits into call->called.number.str.
++ */
++ c->called.number.valid = 1;
++ if (strlen(c->called.number.str) < sizeof(c->called.number.str) - 1) {
++ /* There is enough room for the new digit. */
++ strcat(c->called.number.str, c->overlap_digits);
++ }
++
++ return send_message(ctrl, c, Q931_INFORMATION, information_ies);
+ }
+
+ static int keypad_facility_ies[] = { Q931_IE_KEYPAD_FACILITY, -1 };
+
+-int q931_keypad_facility(struct pri *pri, q931_call *call, char *digits)
++int q931_keypad_facility(struct pri *ctrl, q931_call *call, const char *digits)
+ {
+ libpri_copy_string(call->keypad_digits, digits, sizeof(call->keypad_digits));
+- return send_message(pri, call, Q931_INFORMATION, keypad_facility_ies);
++ return send_message(ctrl, call, Q931_INFORMATION, keypad_facility_ies);
+ }
+
+ static int restart_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
+
+-static int restart_ack(struct pri *pri, q931_call *c)
++static int restart_ack(struct pri *ctrl, q931_call *c)
+ {
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
+ c->peercallstate = Q931_CALL_STATE_NULL;
+- return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies);
++ return send_message(ctrl, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies);
+ }
+
+ static int facility_ies[] = { Q931_IE_FACILITY, -1 };
+
+-int q931_facility(struct pri*pri, q931_call *c)
++int q931_facility(struct pri*ctrl, q931_call *c)
+ {
+- return send_message(pri, c, Q931_FACILITY, facility_ies);
++ return send_message(ctrl, c, Q931_FACILITY, facility_ies);
+ }
+
+-static int notify_ies[] = { Q931_IE_NOTIFY_IND, -1 };
++static int notify_ies[] = { Q931_IE_NOTIFY_IND, Q931_IE_REDIRECTION_NUMBER, -1 };
+
+-int q931_notify(struct pri *pri, q931_call *c, int channel, int info)
++/*!
++ * \internal
++ * \brief Actually send a NOTIFY message with optional redirection number.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param notify Notification indicator
++ * \param number Redirection number to send if not NULL.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int q931_notify_redirection_helper(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number)
+ {
+- if ((pri->switchtype == PRI_SWITCH_EUROISDN_T1) || (pri->switchtype != PRI_SWITCH_EUROISDN_E1)) {
+- if ((info > 0x2) || (info < 0x00))
++ if (number) {
++ call->redirection_number = *number;
++ } else {
++ q931_party_number_init(&call->redirection_number);
++ }
++ call->notify = notify;
++ return send_message(ctrl, call, Q931_NOTIFY, notify_ies);
++}
++
++/*!
++ * \brief Send a NOTIFY message with optional redirection number.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg
++ * \param notify Notification indicator
++ * \param number Redirection number to send if not NULL.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number)
++{
++ int status;
++ unsigned idx;
++ struct q931_call *subcall;
++
++ if (call->outboundbroadcast && call->master_call == call) {
++ status = 0;
++ for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
++ subcall = call->subcalls[idx];
++ if (subcall) {
++ /* Send to all subcalls that have given a positive response. */
++ switch (subcall->ourcallstate) {
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_ACTIVE:
++ if (q931_notify_redirection_helper(ctrl, subcall, notify, number)) {
++ status = -1;
++ }
++ break;
++ default:
++ break;
++ }
++ }
++ }
++ } else {
++ status = q931_notify_redirection_helper(ctrl, call, notify, number);
++ }
++ return status;
++}
++
++int q931_notify(struct pri *ctrl, q931_call *c, int channel, int info)
++{
++ if ((ctrl->switchtype == PRI_SWITCH_EUROISDN_T1) || (ctrl->switchtype != PRI_SWITCH_EUROISDN_E1)) {
++ if ((info > 0x2) || (info < 0x00)) {
+ return 0;
++ }
+ }
+
+- if (info >= 0)
+- c->notify = info & 0x7F;
+- else
+- c->notify = -1;
+- return send_message(pri, c, Q931_NOTIFY, notify_ies);
++ if (info >= 0) {
++ info = info & 0x7F;
++ } else {
++ info = -1;
++ }
++ return q931_notify_redirection(ctrl, c, info, NULL);
+ }
+
+ #ifdef ALERTING_NO_PROGRESS
+ static int call_progress_ies[] = { -1 };
+ #else
+-static int call_progress_with_cause_ies[] = { Q931_PROGRESS_INDICATOR, Q931_CAUSE, -1 };
++static int call_progress_with_cause_ies[] = { Q931_CAUSE, Q931_PROGRESS_INDICATOR, -1 };
+
+ static int call_progress_ies[] = { Q931_PROGRESS_INDICATOR, -1 };
+ #endif
+
+-int q931_call_progress(struct pri *pri, q931_call *c, int channel, int info)
++int q931_call_progress(struct pri *ctrl, q931_call *c, int channel, int info)
+ {
+ if (channel) {
+ c->ds1no = (channel & 0xff00) >> 8;
+ c->ds1explicit = (channel & 0x10000) >> 16;
+- channel &= 0xff;
+- c->channelno = channel;
++ c->channelno = channel & 0xff;
+ }
+
+ if (info) {
+@@ -2762,21 +4279,20 @@
+ c->progressmask = PRI_PROG_INBAND_AVAILABLE;
+ } else {
+ /* PI is mandatory IE for PROGRESS message - Q.931 3.1.8 */
+- pri_error(pri, "XXX Progress message requested but no information is provided\n");
++ pri_error(ctrl, "XXX Progress message requested but no information is provided\n");
+ c->progressmask = 0;
+ }
+
+ c->alive = 1;
+- return send_message(pri, c, Q931_PROGRESS, call_progress_ies);
++ return send_message(ctrl, c, Q931_PROGRESS, call_progress_ies);
+ }
+
+-int q931_call_progress_with_cause(struct pri *pri, q931_call *c, int channel, int info, int cause)
++int q931_call_progress_with_cause(struct pri *ctrl, q931_call *c, int channel, int info, int cause)
+ {
+ if (channel) {
+ c->ds1no = (channel & 0xff00) >> 8;
+ c->ds1explicit = (channel & 0x10000) >> 16;
+- channel &= 0xff;
+- c->channelno = channel;
++ c->channelno = channel & 0xff;
+ }
+
+ if (info) {
+@@ -2785,7 +4301,7 @@
+ c->progressmask = PRI_PROG_INBAND_AVAILABLE;
+ } else {
+ /* PI is mandatory IE for PROGRESS message - Q.931 3.1.8 */
+- pri_error(pri, "XXX Progress message requested but no information is provided\n");
++ pri_error(ctrl, "XXX Progress message requested but no information is provided\n");
+ c->progressmask = 0;
+ }
+
+@@ -2794,7 +4310,7 @@
+ c->causeloc = LOC_PRIV_NET_LOCAL_USER;
+
+ c->alive = 1;
+- return send_message(pri, c, Q931_PROGRESS, call_progress_with_cause_ies);
++ return send_message(ctrl, c, Q931_PROGRESS, call_progress_with_cause_ies);
+ }
+
+ #ifdef ALERTING_NO_PROGRESS
+@@ -2803,17 +4319,16 @@
+ static int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };
+ #endif
+
+-int q931_call_proceeding(struct pri *pri, q931_call *c, int channel, int info)
++int q931_call_proceeding(struct pri *ctrl, q931_call *c, int channel, int info)
+ {
+ if (channel) {
+ c->ds1no = (channel & 0xff00) >> 8;
+ c->ds1explicit = (channel & 0x10000) >> 16;
+- channel &= 0xff;
+- c->channelno = channel;
++ c->channelno = channel & 0xff;
+ }
+ c->chanflags &= ~FLAG_PREFERRED;
+ c->chanflags |= FLAG_EXCLUSIVE;
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_INCOMING_CALL_PROCEEDING);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_INCOMING_CALL_PROCEEDING);
+ c->peercallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING;
+ if (info) {
+ c->progloc = LOC_PRIV_NET_LOCAL_USER;
+@@ -2823,62 +4338,73 @@
+ c->progressmask = 0;
+ c->proc = 1;
+ c->alive = 1;
+- return send_message(pri, c, Q931_CALL_PROCEEDING, call_proceeding_ies);
++ return send_message(ctrl, c, Q931_CALL_PROCEEDING, call_proceeding_ies);
+ }
+ #ifndef ALERTING_NO_PROGRESS
+-static int alerting_ies[] = { Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, -1 };
++static int alerting_ies[] = { Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, -1 };
+ #else
+-static int alerting_ies[] = { -1 };
++static int alerting_ies[] = { Q931_IE_FACILITY, -1 };
+ #endif
+
+-int q931_alerting(struct pri *pri, q931_call *c, int channel, int info)
++int q931_alerting(struct pri *ctrl, q931_call *c, int channel, int info)
+ {
+ if (!c->proc)
+- q931_call_proceeding(pri, c, channel, 0);
++ q931_call_proceeding(ctrl, c, channel, 0);
+ if (info) {
+ c->progloc = LOC_PRIV_NET_LOCAL_USER;
+ c->progcode = CODE_CCITT;
+ c->progressmask = PRI_PROG_INBAND_AVAILABLE;
+ } else
+ c->progressmask = 0;
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_RECEIVED);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_RECEIVED);
+ c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED;
+ c->alive = 1;
+- return send_message(pri, c, Q931_ALERTING, alerting_ies);
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_QSIG:
++ if (c->local_id.name.valid) {
++ /* Send calledName with ALERTING */
++ rose_called_name_encode(ctrl, c, Q931_ALERTING);
++ }
++ break;
++ default:
++ break;
++ }
++
++ return send_message(ctrl, c, Q931_ALERTING, alerting_ies);
+ }
+
+-static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };
++static int setup_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, -1 };
+
+-int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn)
++int q931_setup_ack(struct pri *ctrl, q931_call *c, int channel, int nonisdn)
+ {
+ if (channel) {
+ c->ds1no = (channel & 0xff00) >> 8;
+ c->ds1explicit = (channel & 0x10000) >> 16;
+- channel &= 0xff;
+- c->channelno = channel;
++ c->channelno = channel & 0xff;
+ }
+ c->chanflags &= ~FLAG_PREFERRED;
+ c->chanflags |= FLAG_EXCLUSIVE;
+- if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) {
++ if (nonisdn && (ctrl->switchtype != PRI_SWITCH_DMS100)) {
+ c->progloc = LOC_PRIV_NET_LOCAL_USER;
+ c->progcode = CODE_CCITT;
+ c->progressmask = PRI_PROG_CALLED_NOT_ISDN;
+ } else
+ c->progressmask = 0;
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OVERLAP_RECEIVING);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OVERLAP_RECEIVING);
+ c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
+ c->alive = 1;
+- return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies);
++ return send_message(ctrl, c, Q931_SETUP_ACKNOWLEDGE, setup_ack_ies);
+ }
+
+ /* T313 expiry, first time */
+ static void pri_connect_timeout(void *data)
+ {
+ struct q931_call *c = data;
+- struct pri *pri = c->pri;
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "Timed out looking for connect acknowledge\n");
+- q931_disconnect(pri, c, PRI_CAUSE_NORMAL_CLEARING);
++ struct pri *ctrl = c->pri;
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl, "Timed out looking for connect acknowledge\n");
++ q931_disconnect(ctrl, c, PRI_CAUSE_NORMAL_CLEARING);
+
+ }
+
+@@ -2886,85 +4412,120 @@
+ static void pri_release_timeout(void *data)
+ {
+ struct q931_call *c = data;
+- struct pri *pri = c->pri;
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "Timed out looking for release complete\n");
++ struct pri *ctrl = c->pri;
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl, "Timed out looking for release complete\n");
+ c->t308_timedout++;
+ c->alive = 1;
+
+ /* The call to q931_release will re-schedule T308 */
+- q931_release(pri, c, c->cause);
++ q931_release(ctrl, c, c->cause);
+ }
+
+ /* T308 expiry, second time */
+ static void pri_release_finaltimeout(void *data)
+ {
+ struct q931_call *c = data;
+- struct pri *pri = c->pri;
++ struct pri *ctrl = c->pri;
+ c->alive = 1;
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "Final time-out looking for release complete\n");
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl, "Final time-out looking for release complete\n");
+ c->t308_timedout++;
+ c->ourcallstate = Q931_CALL_STATE_NULL;
+ c->peercallstate = Q931_CALL_STATE_NULL;
+- pri->schedev = 1;
+- pri->ev.e = PRI_EVENT_HANGUP_ACK;
+- pri->ev.hangup.channel = c->channelno;
+- pri->ev.hangup.cause = c->cause;
+- pri->ev.hangup.cref = c->cr;
+- pri->ev.hangup.call = c;
+- pri->ev.hangup.aoc_units = c->aoc_units;
+- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
+- q931_hangup(pri, c, c->cause);
++ q931_clr_subcommands(ctrl);
++ ctrl->schedev = 1;
++ ctrl->ev.e = PRI_EVENT_HANGUP_ACK;
++ ctrl->ev.hangup.subcmds = &ctrl->subcmds;
++ ctrl->ev.hangup.channel = q931_encode_channel(c);
++ ctrl->ev.hangup.cause = c->cause;
++ ctrl->ev.hangup.cref = c->cr;
++ ctrl->ev.hangup.call = c->master_call;
++ ctrl->ev.hangup.aoc_units = c->aoc_units;
++ ctrl->ev.hangup.call_held = NULL;
++ ctrl->ev.hangup.call_active = NULL;
++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
++ pri_hangup(ctrl, c, c->cause);
+ }
+
+ /* T305 expiry, first time */
+ static void pri_disconnect_timeout(void *data)
+ {
+ struct q931_call *c = data;
+- struct pri *pri = c->pri;
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "Timed out looking for release\n");
++ struct pri *ctrl = c->pri;
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl, "Timed out looking for release\n");
+ c->alive = 1;
+- q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);
++ q931_release(ctrl, c, PRI_CAUSE_NORMAL_CLEARING);
+ }
+
+-int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn)
++static int connect_ies[] = {
++ Q931_CHANNEL_IDENT,
++ Q931_IE_FACILITY,
++ Q931_PROGRESS_INDICATOR,
++ Q931_DISPLAY,
++ Q931_IE_CONNECTED_NUM,
++ Q931_IE_CONNECTED_SUBADDR,
++ -1
++};
++
++int q931_connect(struct pri *ctrl, q931_call *c, int channel, int nonisdn)
+ {
+ if (channel) {
+ c->ds1no = (channel & 0xff00) >> 8;
+ c->ds1explicit = (channel & 0x10000) >> 16;
+- channel &= 0xff;
+- c->channelno = channel;
++ c->channelno = channel & 0xff;
+ }
+ c->chanflags &= ~FLAG_PREFERRED;
+ c->chanflags |= FLAG_EXCLUSIVE;
+- if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) {
++ if (nonisdn && (ctrl->switchtype != PRI_SWITCH_DMS100)) {
+ c->progloc = LOC_PRIV_NET_LOCAL_USER;
+ c->progcode = CODE_CCITT;
+ c->progressmask = PRI_PROG_CALLED_NOT_ISDN;
+ } else
+ c->progressmask = 0;
+- if(pri->localtype == PRI_NETWORK || pri->switchtype == PRI_SWITCH_QSIG)
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE);
++ if(ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG)
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
+ else
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CONNECT_REQUEST);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CONNECT_REQUEST);
+ c->peercallstate = Q931_CALL_STATE_ACTIVE;
+ c->alive = 1;
+ /* Connect request timer */
+- if (c->retranstimer)
+- pri_schedule_del(pri, c->retranstimer);
++ pri_schedule_del(ctrl, c->retranstimer);
+ c->retranstimer = 0;
+- if ((c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && (pri->bri || (!pri->subchannel)))
+- c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T313], pri_connect_timeout, c);
+- return send_message(pri, c, Q931_CONNECT, connect_ies);
++ if ((c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && (ctrl->bri || (!ctrl->subchannel)))
++ c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T313], pri_connect_timeout, c);
++
++ if (c->redirecting.state == Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3) {
++ c->redirecting.state = Q931_REDIRECTING_STATE_IDLE;
++ /* Send DivertingLegInformation3 with CONNECT. */
++ c->redirecting.to = c->local_id;
++ if (!c->redirecting.to.number.valid) {
++ q931_party_number_init(&c->redirecting.to.number);
++ c->redirecting.to.number.valid = 1;
++ c->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ }
++ rose_diverting_leg_information3_encode(ctrl, c, Q931_CONNECT);
++ }
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_QSIG:
++ if (c->local_id.name.valid) {
++ /* Send connectedName with CONNECT */
++ rose_connected_name_encode(ctrl, c, Q931_CONNECT);
++ }
++ break;
++ default:
++ break;
++ }
++ return send_message(ctrl, c, Q931_CONNECT, connect_ies);
+ }
+
+ static int release_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 };
+
+-int q931_release(struct pri *pri, q931_call *c, int cause)
++int q931_release(struct pri *ctrl, q931_call *c, int cause)
+ {
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RELEASE_REQUEST);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RELEASE_REQUEST);
+ /* c->peercallstate stays the same */
+ if (c->alive) {
+ c->alive = 0;
+@@ -2972,26 +4533,26 @@
+ c->causecode = CODE_CCITT;
+ c->causeloc = LOC_PRIV_NET_LOCAL_USER;
+ if (c->acked) {
+- if (c->retranstimer)
+- pri_schedule_del(pri, c->retranstimer);
++ pri_schedule_del(ctrl, c->retranstimer);
+ if (!c->t308_timedout) {
+- c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T308], pri_release_timeout, c);
++ c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T308], pri_release_timeout, c);
+ } else {
+- c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T308], pri_release_finaltimeout, c);
++ c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T308], pri_release_finaltimeout, c);
+ }
+- return send_message(pri, c, Q931_RELEASE, release_ies);
++ return send_message(ctrl, c, Q931_RELEASE, release_ies);
+ } else
+- return send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies); /* Yes, release_ies, not release_complete_ies */
++ return send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_ies); /* Yes, release_ies, not release_complete_ies */
+ } else
+ return 0;
+ }
+
+ static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
+
+-int q931_restart(struct pri *pri, int channel)
++int q931_restart(struct pri *ctrl, int channel)
+ {
+ struct q931_call *c;
+- c = q931_getcall(pri, 0 | 0x8000, 1);
++
++ c = q931_getcall(ctrl, 0 | 0x8000);
+ if (!c)
+ return -1;
+ if (!channel)
+@@ -2999,20 +4560,19 @@
+ c->ri = 0;
+ c->ds1no = (channel & 0xff00) >> 8;
+ c->ds1explicit = (channel & 0x10000) >> 16;
+- channel &= 0xff;
+- c->channelno = channel;
++ c->channelno = channel & 0xff;
+ c->chanflags &= ~FLAG_PREFERRED;
+ c->chanflags |= FLAG_EXCLUSIVE;
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RESTART);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RESTART);
+ c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
+- return send_message(pri, c, Q931_RESTART, restart_ies);
++ return send_message(ctrl, c, Q931_RESTART, restart_ies);
+ }
+
+-static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 };
++static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_FACILITY, Q931_IE_USER_USER, -1 };
+
+-int q931_disconnect(struct pri *pri, q931_call *c, int cause)
++int q931_disconnect(struct pri *ctrl, q931_call *c, int cause)
+ {
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_DISCONNECT_REQUEST);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_DISCONNECT_REQUEST);
+ c->peercallstate = Q931_CALL_STATE_DISCONNECT_INDICATION;
+ if (c->alive) {
+ c->alive = 0;
+@@ -3020,27 +4580,125 @@
+ c->causecode = CODE_CCITT;
+ c->causeloc = LOC_PRIV_NET_LOCAL_USER;
+ c->sendhangupack = 1;
+- if (c->retranstimer)
+- pri_schedule_del(pri, c->retranstimer);
+- c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T305], pri_disconnect_timeout, c);
+- return send_message(pri, c, Q931_DISCONNECT, disconnect_ies);
++ pri_schedule_del(ctrl, c->retranstimer);
++ c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T305], pri_disconnect_timeout, c);
++ return send_message(ctrl, c, Q931_DISCONNECT, disconnect_ies);
+ } else
+ return 0;
+ }
+
+-static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_NETWORK_SPEC_FAC, Q931_DISPLAY,
+- Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_REDIRECTING_NUMBER, Q931_IE_USER_USER, Q931_SENDING_COMPLETE,
+- Q931_IE_ORIGINATING_LINE_INFO, Q931_IE_GENERIC_DIGITS, -1 };
++static int setup_ies[] = {
++ Q931_BEARER_CAPABILITY,
++ Q931_CHANNEL_IDENT,
++ Q931_IE_FACILITY,
++ Q931_PROGRESS_INDICATOR,
++ Q931_NETWORK_SPEC_FAC,
++ Q931_DISPLAY,
++ Q931_IE_KEYPAD_FACILITY,
++ Q931_REVERSE_CHARGE_INDIC,
++ Q931_CALLING_PARTY_NUMBER,
++ Q931_CALLING_PARTY_SUBADDR,
++ Q931_CALLED_PARTY_NUMBER,
++ Q931_CALLED_PARTY_SUBADDR,
++ Q931_REDIRECTING_NUMBER,
++ Q931_IE_USER_USER,
++ Q931_SENDING_COMPLETE,
++ Q931_IE_ORIGINATING_LINE_INFO,
++ Q931_IE_GENERIC_DIGITS,
++ -1
++};
+
+-static int gr303_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, -1 };
++static int gr303_setup_ies[] = {
++ Q931_BEARER_CAPABILITY,
++ Q931_CHANNEL_IDENT,
++ -1
++};
+
+-static int cis_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLED_PARTY_NUMBER, -1 };
++/*! Call Independent Signalling SETUP ie's */
++static int cis_setup_ies[] = {
++ Q931_BEARER_CAPABILITY,
++ Q931_CHANNEL_IDENT,
++ Q931_IE_FACILITY,
++ Q931_IE_KEYPAD_FACILITY,
++ Q931_CALLING_PARTY_NUMBER,
++ Q931_CALLING_PARTY_SUBADDR,
++ Q931_CALLED_PARTY_NUMBER,
++ Q931_CALLED_PARTY_SUBADDR,
++ Q931_SENDING_COMPLETE,
++ -1
++};
+
+-int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
++static void stop_t303(struct q931_call *call)
+ {
++ /* T303 should only be running on the master call */
++ pri_schedule_del(call->master_call->pri, call->master_call->t303_timer);
++ call->master_call->t303_timer = 0;
++}
++
++static void t303_expiry(void *data);
++
++static void start_t303(struct q931_call *call)
++{
++ if (call->t303_timer) {
++ pri_error(call->pri, "Should not have T303 set when starting again. Stopping first\n");
++ stop_t303(call);
++ }
++
++ //pri_error(call->pri, "T303 should be %d\n", call->pri->timers[PRI_TIMER_T303]);
++ call->t303_timer = pri_schedule_event(call->pri, call->pri->timers[PRI_TIMER_T303], t303_expiry, call);
++}
++
++static void pri_fake_clearing(void *data);
++
++static void t303_expiry(void *data)
++{
++ struct q931_call *c = data;
++ struct pri *ctrl = c->pri;
+ int res;
+-
+-
++
++ c->t303_expirycnt++;
++ c->t303_timer = 0;
++
++ if (c->cause != -1) {
++ /* We got a DISCONNECT, RELEASE, or RELEASE_COMPLETE and no other responses. */
++ pri_fake_clearing(c);
++ } else if (c->t303_expirycnt < 2) {
++ if (ctrl->subchannel && !ctrl->bri)
++ res = send_message(ctrl, c, Q931_SETUP, gr303_setup_ies);
++ else if (c->cis_call)
++ res = send_message(ctrl, c, Q931_SETUP, cis_setup_ies);
++ else
++ res = send_message(ctrl, c, Q931_SETUP, setup_ies);
++
++ if (res) {
++ pri_error(c->pri, "Error resending setup message!\n");
++ }
++ start_t303(c);
++ } else {
++ c->cause = PRI_CAUSE_NO_USER_RESPONSE;
++ pri_fake_clearing(c);
++ }
++}
++
++int q931_setup(struct pri *ctrl, q931_call *c, struct pri_sr *req)
++{
++ int res;
++
++ if (!req->called.number.valid && (!req->keypad_digits || !req->keypad_digits[0])) {
++ /* No called number or keypad digits to send. */
++ return -1;
++ }
++
++ c->called = req->called;
++ libpri_copy_string(c->overlap_digits, req->called.number.str, sizeof(c->overlap_digits));
++
++ if (req->keypad_digits) {
++ libpri_copy_string(c->keypad_digits, req->keypad_digits,
++ sizeof(c->keypad_digits));
++ } else {
++ c->keypad_digits[0] = '\0';
++ }
++
+ c->transcapability = req->transmode;
+ c->transmoderate = TRANS_MODE_64_CIRCUIT;
+ if (!req->userl1)
+@@ -3050,89 +4708,68 @@
+ c->userl3 = -1;
+ c->ds1no = (req->channel & 0xff00) >> 8;
+ c->ds1explicit = (req->channel & 0x10000) >> 16;
+- req->channel &= 0xff;
+- if ((pri->localtype == PRI_CPE) && pri->subchannel && !pri->bri) {
+- req->channel = 0;
+- req->exclusive = 0;
++ if ((ctrl->localtype == PRI_CPE) && ctrl->subchannel && !ctrl->bri) {
++ c->channelno = 0;
++ c->chanflags = 0;
++ } else {
++ c->channelno = req->channel & 0xff;
++ if (req->exclusive) {
++ c->chanflags = FLAG_EXCLUSIVE;
++ } else {
++ c->chanflags = FLAG_PREFERRED;
++ }
+ }
+-
+- c->channelno = req->channel;
++
+ c->slotmap = -1;
+ c->nonisdn = req->nonisdn;
+ c->newcall = 0;
+- c->justsignalling = req->justsignalling;
++ c->cis_call = req->cis_call;
++ c->cis_auto_disconnect = req->cis_auto_disconnect;
+ c->complete = req->numcomplete;
+- if (req->exclusive)
+- c->chanflags = FLAG_EXCLUSIVE;
+- else if (c->channelno)
+- c->chanflags = FLAG_PREFERRED;
+- if (req->caller) {
+- libpri_copy_string(c->callernum, req->caller, sizeof(c->callernum));
+- c->callerplan = req->callerplan;
+- if (req->callername)
+- libpri_copy_string(c->callername, req->callername, sizeof(c->callername));
+- else
+- c->callername[0] = '\0';
+- if ((pri->switchtype == PRI_SWITCH_DMS100) ||
+- (pri->switchtype == PRI_SWITCH_ATT4ESS)) {
+- /* Doesn't like certain presentation types */
+- if (!(req->callerpres & 0x7c))
+- req->callerpres = PRES_ALLOWED_NETWORK_NUMBER;
+- }
+- c->callerpres = req->callerpres;
+- } else {
+- c->callernum[0] = '\0';
+- c->callername[0] = '\0';
+- c->callerplan = PRI_UNKNOWN;
+- c->callerpres = PRES_NUMBER_NOT_AVAILABLE;
++
++ if (req->caller.number.valid) {
++ c->local_id = req->caller;
++ q931_party_id_fixup(ctrl, &c->local_id);
+ }
+- if (req->redirectingnum) {
+- libpri_copy_string(c->redirectingnum, req->redirectingnum, sizeof(c->redirectingnum));
+- c->redirectingplan = req->redirectingplan;
+- if ((pri->switchtype == PRI_SWITCH_DMS100) ||
+- (pri->switchtype == PRI_SWITCH_ATT4ESS)) {
+- /* Doesn't like certain presentation types */
+- if (!(req->redirectingpres & 0x7c))
+- req->redirectingpres = PRES_ALLOWED_NETWORK_NUMBER;
+- }
+- c->redirectingpres = req->redirectingpres;
+- c->redirectingreason = req->redirectingreason;
+- } else {
+- c->redirectingnum[0] = '\0';
+- c->redirectingplan = PRI_UNKNOWN;
+- c->redirectingpres = PRES_NUMBER_NOT_AVAILABLE;
+- c->redirectingreason = PRI_REDIR_UNKNOWN;
++
++ if (req->redirecting.from.number.valid) {
++ c->redirecting = req->redirecting;
++ q931_party_id_fixup(ctrl, &c->redirecting.from);
++ q931_party_id_fixup(ctrl, &c->redirecting.to);
++ q931_party_id_fixup(ctrl, &c->redirecting.orig_called);
+ }
+- if (req->called) {
+- libpri_copy_string(c->callednum, req->called, sizeof(c->callednum));
+- c->calledplan = req->calledplan;
+- } else
+- return -1;
+
+ if (req->useruserinfo)
+ libpri_copy_string(c->useruserinfo, req->useruserinfo, sizeof(c->useruserinfo));
+ else
+ c->useruserinfo[0] = '\0';
+
+- if (req->nonisdn && (pri->switchtype == PRI_SWITCH_NI2))
++ if (req->nonisdn && (ctrl->switchtype == PRI_SWITCH_NI2))
+ c->progressmask = PRI_PROG_CALLER_NOT_ISDN;
+ else
+ c->progressmask = 0;
+
+- pri_call_add_standard_apdus(pri, c);
++ c->reversecharge = req->reversecharge;
+
+- if (pri->subchannel && !pri->bri)
+- res = send_message(pri, c, Q931_SETUP, gr303_setup_ies);
+- else if (c->justsignalling)
+- res = send_message(pri, c, Q931_SETUP, cis_setup_ies);
++ pri_call_add_standard_apdus(ctrl, c);
++
++ if (ctrl->subchannel && !ctrl->bri)
++ res = send_message(ctrl, c, Q931_SETUP, gr303_setup_ies);
++ else if (c->cis_call)
++ res = send_message(ctrl, c, Q931_SETUP, cis_setup_ies);
+ else
+- res = send_message(pri, c, Q931_SETUP, setup_ies);
++ res = send_message(ctrl, c, Q931_SETUP, setup_ies);
+ if (!res) {
+ c->alive = 1;
+ /* make sure we call PRI_EVENT_HANGUP_ACK once we send/receive RELEASE_COMPLETE */
+ c->sendhangupack = 1;
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_INITIATED);
+- c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_INITIATED);
++ c->peercallstate = Q931_CALL_STATE_CALL_PRESENT;
++ c->t303_expirycnt = 0;
++ if (BRI_NT_PTMP(ctrl)) {
++ c->outboundbroadcast = 1;
++ }
++ start_t303(c);
+ }
+ return res;
+
+@@ -3140,22 +4777,22 @@
+
+ static int release_complete_ies[] = { Q931_IE_USER_USER, -1 };
+
+-static int q931_release_complete(struct pri *pri, q931_call *c, int cause)
++static int q931_release_complete(struct pri *ctrl, q931_call *c, int cause)
+ {
+ int res = 0;
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
+ c->peercallstate = Q931_CALL_STATE_NULL;
+ if (cause > -1) {
+ c->cause = cause;
+ c->causecode = CODE_CCITT;
+ c->causeloc = LOC_PRIV_NET_LOCAL_USER;
+ /* release_ies has CAUSE in it */
+- res = send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies);
++ res = send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_ies);
+ } else
+- res = send_message(pri, c, Q931_RELEASE_COMPLETE, release_complete_ies);
++ res = send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_complete_ies);
+ c->alive = 0;
+ /* release the structure */
+- res += q931_hangup(pri,c,cause);
++ res += pri_hangup(ctrl, c, cause);
+ return res;
+ }
+
+@@ -3163,46 +4800,553 @@
+
+ static int gr303_connect_acknowledge_ies[] = { Q931_CHANNEL_IDENT, -1 };
+
+-static int q931_connect_acknowledge(struct pri *pri, q931_call *c)
++static int q931_connect_acknowledge(struct pri *ctrl, q931_call *c)
+ {
+- if (pri->subchannel && !pri->bri) {
+- if (pri->localtype == PRI_CPE)
+- return send_message(pri, c, Q931_CONNECT_ACKNOWLEDGE, gr303_connect_acknowledge_ies);
++ if (ctrl->subchannel && !ctrl->bri) {
++ if (ctrl->localtype == PRI_CPE)
++ return send_message(ctrl, c, Q931_CONNECT_ACKNOWLEDGE, gr303_connect_acknowledge_ies);
+ } else
+- return send_message(pri, c, Q931_CONNECT_ACKNOWLEDGE, connect_acknowledge_ies);
++ return send_message(ctrl, c, Q931_CONNECT_ACKNOWLEDGE, connect_acknowledge_ies);
+ return 0;
+ }
+
+-int q931_hangup(struct pri *pri, q931_call *c, int cause)
++/*!
++ * \internal
++ * \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
++ *
++ * \param call Starting Q.931 call record of search.
++ *
++ * \retval winning-call or given call if not outboundbroadcast.
++ * \retval NULL if no winning call yet.
++ */
++static struct q931_call *q931_find_winning_call(struct q931_call *call)
+ {
++ struct q931_call *master;
++
++ master = call->master_call;
++ if (master->outboundbroadcast) {
++ /* We have potential subcalls. Now get the winning call if declared yet. */
++ if (master->pri_winner < 0) {
++ /* Winner not declared yet.*/
++ call = NULL;
++ } else {
++ call = master->subcalls[master->pri_winner];
++ }
++ }
++ return call;
++}
++
++/*!
++ * \internal
++ * \brief Send HOLD message response wait timeout.
++ *
++ * \param data Q.931 call leg. (Master Q.931 subcall structure)
++ *
++ * \return Nothing
++ */
++static void q931_hold_timeout(void *data)
++{
++ struct q931_call *call = data;
++ struct pri *ctrl = call->pri;
++
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "Time-out waiting for HOLD response\n");
++ }
++
++ /* Ensure that the timer is deleted. */
++ pri_schedule_del(ctrl, call->hold_timer);
++ call->hold_timer = 0;
++
++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE);
++
++ q931_clr_subcommands(ctrl);
++ ctrl->schedev = 1;
++ ctrl->ev.e = PRI_EVENT_HOLD_REJ;
++ ctrl->ev.hold_rej.channel = q931_encode_channel(call);
++ ctrl->ev.hold_rej.call = call;
++ ctrl->ev.hold_rej.cause = PRI_CAUSE_MESSAGE_TYPE_NONEXIST;
++ ctrl->ev.hold_rej.subcmds = &ctrl->subcmds;
++}
++
++/*!
++ * \internal
++ * \brief Determine if a hold request is allowed now.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (Master Q.931 subcall structure)
++ *
++ * \retval TRUE if we can send a HOLD request.
++ * \retval FALSE if not allowed.
++ */
++static int q931_is_hold_allowed(const struct pri *ctrl, const struct q931_call *call)
++{
++ int allowed;
++
++ allowed = 0;
++ switch (call->ourcallstate) {
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ if (q931_is_ptmp(ctrl)) {
++ /* HOLD request only allowed in these states if point-to-point mode. */
++ break;
++ }
++ /* Fall through */
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_ACTIVE:
++ switch (call->hold_state) {
++ case Q931_HOLD_STATE_IDLE:
++ allowed = 1;
++ break;
++ default:
++ break;
++ }
++ break;
++ case Q931_CALL_STATE_DISCONNECT_INDICATION:
++ case Q931_CALL_STATE_RELEASE_REQUEST:
++ /* Ignore HOLD request in these states. */
++ break;
++ default:
++ break;
++ }
++
++ return allowed;
++}
++
++static int hold_ies[] = {
++ -1
++};
++
++/*!
++ * \brief Send the HOLD message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (Master Q.931 subcall structure)
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int q931_send_hold(struct pri *ctrl, struct q931_call *call)
++{
++ struct q931_call *winner;
++
++ winner = q931_find_winning_call(call);
++ if (!winner || !q931_is_hold_allowed(ctrl, call)) {
++ return -1;
++ }
++ pri_schedule_del(ctrl, call->hold_timer);
++ call->hold_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T_HOLD],
++ q931_hold_timeout, call);
++ if (send_message(ctrl, winner, Q931_HOLD, hold_ies)) {
++ pri_schedule_del(ctrl, call->hold_timer);
++ call->hold_timer = 0;
++ return -1;
++ }
++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_HOLD_REQ);
++ return 0;
++}
++
++static int hold_ack_ies[] = {
++ -1
++};
++
++/*!
++ * \brief Send the HOLD ACKNOWLEDGE message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (Master Q.931 subcall structure)
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call)
++{
++ struct q931_call *winner;
++
++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD);
++
++ winner = q931_find_winning_call(call);
++ if (!winner) {
++ return -1;
++ }
++
++ /* Call is now on hold so forget the channel. */
++ winner->channelno = 0;/* No channel */
++ winner->ds1no = 0;
++ winner->ds1explicit = 0;
++ winner->chanflags = 0;
++
++ return send_message(ctrl, winner, Q931_HOLD_ACKNOWLEDGE, hold_ack_ies);
++}
++
++static int hold_reject_ies[] = {
++ Q931_CAUSE,
++ -1
++};
++
++/*!
++ * \internal
++ * \brief Send the HOLD REJECT message only.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (subcall)
++ * \param cause Q.931 cause code for rejecting the hold request.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int q931_send_hold_rej_msg(struct pri *ctrl, struct q931_call *call, int cause)
++{
++ call->cause = cause;
++ call->causecode = CODE_CCITT;
++ call->causeloc = LOC_PRIV_NET_LOCAL_USER;
++ return send_message(ctrl, call, Q931_HOLD_REJECT, hold_reject_ies);
++}
++
++/*!
++ * \brief Send the HOLD REJECT message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (Master Q.931 subcall structure)
++ * \param cause Q.931 cause code for rejecting the hold request.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int q931_send_hold_rej(struct pri *ctrl, struct q931_call *call, int cause)
++{
++ struct q931_call *winner;
++
++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE);
++
++ winner = q931_find_winning_call(call);
++ if (!winner) {
++ return -1;
++ }
++
++ return q931_send_hold_rej_msg(ctrl, winner, cause);
++}
++
++/*!
++ * \internal
++ * \brief Send RETRIEVE message response wait timeout.
++ *
++ * \param data Q.931 call leg. (Master Q.931 subcall structure)
++ *
++ * \return Nothing
++ */
++static void q931_retrieve_timeout(void *data)
++{
++ struct q931_call *call = data;
++ struct pri *ctrl = call->pri;
++ struct q931_call *winner;
++
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "Time-out waiting for RETRIEVE response\n");
++ }
++
++ /* Ensure that the timer is deleted. */
++ pri_schedule_del(ctrl, call->hold_timer);
++ call->hold_timer = 0;
++
++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD);
++
++ winner = q931_find_winning_call(call);
++ if (winner) {
++ /* Call is still on hold so forget the channel. */
++ winner->channelno = 0;/* No channel */
++ winner->ds1no = 0;
++ winner->ds1explicit = 0;
++ winner->chanflags = 0;
++ }
++
++ q931_clr_subcommands(ctrl);
++ ctrl->schedev = 1;
++ ctrl->ev.e = PRI_EVENT_RETRIEVE_REJ;
++ ctrl->ev.retrieve_rej.channel = q931_encode_channel(call);
++ ctrl->ev.retrieve_rej.call = call;
++ ctrl->ev.retrieve_rej.cause = PRI_CAUSE_MESSAGE_TYPE_NONEXIST;
++ ctrl->ev.retrieve_rej.subcmds = &ctrl->subcmds;
++}
++
++/*!
++ * \internal
++ * \brief Determine if a retrieve request is allowed now.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (Master Q.931 subcall structure)
++ *
++ * \retval TRUE if we can send a RETRIEVE request.
++ * \retval FALSE if not allowed.
++ */
++static int q931_is_retrieve_allowed(const struct pri *ctrl, const struct q931_call *call)
++{
++ int allowed;
++
++ allowed = 0;
++ switch (call->ourcallstate) {
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ if (q931_is_ptmp(ctrl)) {
++ /* RETRIEVE request only allowed in these states if point-to-point mode. */
++ break;
++ }
++ /* Fall through */
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_ACTIVE:
++ switch (call->hold_state) {
++ case Q931_HOLD_STATE_CALL_HELD:
++ allowed = 1;
++ break;
++ default:
++ break;
++ }
++ break;
++ case Q931_CALL_STATE_DISCONNECT_INDICATION:
++ case Q931_CALL_STATE_RELEASE_REQUEST:
++ /* Ignore RETRIEVE request in these states. */
++ break;
++ default:
++ break;
++ }
++
++ return allowed;
++}
++
++static int retrieve_ies[] = {
++ Q931_CHANNEL_IDENT,
++ -1
++};
++
++/*!
++ * \brief Send the RETRIEVE message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (Master Q.931 subcall structure)
++ * \param channel Encoded channel id to use. If zero do not send channel id.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int q931_send_retrieve(struct pri *ctrl, struct q931_call *call, int channel)
++{
++ struct q931_call *winner;
++
++ winner = q931_find_winning_call(call);
++ if (!winner || !q931_is_retrieve_allowed(ctrl, call)) {
++ return -1;
++ }
++
++ if (channel) {
++ winner->ds1no = (channel & 0xff00) >> 8;
++ winner->ds1explicit = (channel & 0x10000) >> 16;
++ winner->channelno = channel & 0xff;
++ if (ctrl->localtype == PRI_NETWORK) {
++ winner->chanflags = FLAG_EXCLUSIVE;
++ } else {
++ winner->chanflags = FLAG_PREFERRED;
++ }
++ } else {
++ /* Do not send Q931_CHANNEL_IDENT */
++ winner->chanflags = 0;
++ }
++
++ pri_schedule_del(ctrl, call->hold_timer);
++ call->hold_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T_RETRIEVE],
++ q931_retrieve_timeout, call);
++ if (send_message(ctrl, winner, Q931_RETRIEVE, retrieve_ies)) {
++ pri_schedule_del(ctrl, call->hold_timer);
++ call->hold_timer = 0;
++
++ /* Call is still on hold so forget the channel. */
++ winner->channelno = 0;/* No channel */
++ winner->ds1no = 0;
++ winner->ds1explicit = 0;
++ winner->chanflags = 0;
++ return -1;
++ }
++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_RETRIEVE_REQ);
++ return 0;
++}
++
++static int retrieve_ack_ies[] = {
++ Q931_CHANNEL_IDENT,
++ -1
++};
++
++/*!
++ * \brief Send the RETRIEVE ACKNOWLEDGE message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (Master Q.931 subcall structure)
++ * \param channel Encoded channel id to use.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int q931_send_retrieve_ack(struct pri *ctrl, struct q931_call *call, int channel)
++{
++ struct q931_call *winner;
++
++ winner = q931_find_winning_call(call);
++ if (!winner) {
++ return -1;
++ }
++
++ winner->ds1no = (channel & 0xff00) >> 8;
++ winner->ds1explicit = (channel & 0x10000) >> 16;
++ winner->channelno = channel & 0xff;
++ winner->chanflags = FLAG_EXCLUSIVE;
++
++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE);
++
++ return send_message(ctrl, winner, Q931_RETRIEVE_ACKNOWLEDGE, retrieve_ack_ies);
++}
++
++static int retrieve_reject_ies[] = {
++ Q931_CAUSE,
++ -1
++};
++
++/*!
++ * \internal
++ * \brief Send the RETRIEVE REJECT message only.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (subcall)
++ * \param cause Q.931 cause code for rejecting the retrieve request.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++static int q931_send_retrieve_rej_msg(struct pri *ctrl, struct q931_call *call, int cause)
++{
++ call->cause = cause;
++ call->causecode = CODE_CCITT;
++ call->causeloc = LOC_PRIV_NET_LOCAL_USER;
++ return send_message(ctrl, call, Q931_RETRIEVE_REJECT, retrieve_reject_ies);
++}
++
++/*!
++ * \brief Send the RETRIEVE REJECT message.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg. (Master Q.931 subcall structure)
++ * \param cause Q.931 cause code for rejecting the retrieve request.
++ *
++ * \retval 0 on success.
++ * \retval -1 on error.
++ */
++int q931_send_retrieve_rej(struct pri *ctrl, struct q931_call *call, int cause)
++{
++ struct q931_call *winner;
++
++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD);
++
++ winner = q931_find_winning_call(call);
++ if (!winner) {
++ return -1;
++ }
++
++ /* Call is still on hold so forget the channel. */
++ winner->channelno = 0;/* No channel */
++ winner->ds1no = 0;
++ winner->ds1explicit = 0;
++ winner->chanflags = 0;
++
++ return q931_send_retrieve_rej_msg(ctrl, winner, cause);
++}
++
++static int pri_internal_clear(void *data);
++
++/* Fake RELEASE for NT-PTMP initiated SETUPs w/o response */
++static void pri_fake_clearing(void *data)
++{
++ struct q931_call *c = data;
++ struct pri *ctrl = c->pri;
++
++ c->performing_fake_clearing = 1;
++ if (pri_internal_clear(c) == Q931_RES_HAVEEVENT)
++ ctrl->schedev = 1;
++}
++
++static void pri_create_fake_clearing(struct q931_call *c, struct pri *master)
++{
++ c->pri = master;
++
++ pri_schedule_del(master, c->retranstimer);
++ c->retranstimer = pri_schedule_event(master, 0, pri_fake_clearing, c);
++}
++
++//static int q931_get_subcall_count(struct q931_call *call);
++
++static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause)
++{
+ int disconnect = 1;
+ int release_compl = 0;
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "NEW_HANGUP DEBUG: Calling q931_hangup, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
+- if (!pri || !c)
++ int t303_was_running = c->master_call->t303_timer;
++
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl,
++ "NEW_HANGUP DEBUG: Calling q931_hangup, ourstate %s, peerstate %s, hold-state %s\n",
++ q931_call_state_str(c->ourcallstate),
++ q931_call_state_str(c->peercallstate),
++ q931_hold_state_str(c->master_call->hold_state));
++ if (!ctrl || !c)
+ return -1;
+ /* If mandatory IE was missing, insist upon that cause code */
+ if (c->cause == PRI_CAUSE_MANDATORY_IE_MISSING)
+ cause = c->cause;
+- if (cause == 34 || cause == 44 || cause == 82 || cause == 1 || cause == 81) {
++ switch (cause) {
++ case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
++ case PRI_CAUSE_REQUESTED_CHAN_UNAVAIL:
++ case PRI_CAUSE_IDENTIFIED_CHANNEL_NOTEXIST:
++ case PRI_CAUSE_UNALLOCATED:
++ case PRI_CAUSE_INVALID_CALL_REFERENCE:
+ /* We'll send RELEASE_COMPLETE with these causes */
+ disconnect = 0;
+ release_compl = 1;
+- }
+- if (cause == 6 || cause == 7 || cause == 26) {
++ break;
++ case PRI_CAUSE_CHANNEL_UNACCEPTABLE:
++ case PRI_CAUSE_CALL_AWARDED_DELIVERED:
++ case PRI_CAUSE_NONSELECTED_USER_CLEARING:
+ /* We'll send RELEASE with these causes */
+ disconnect = 0;
++ break;
++ default:
++ break;
+ }
++ if (c->cis_call) {
++ disconnect = 0;
++ }
++
++ c->hangupinitiated = 1;
++ stop_t303(c);
++
+ /* All other causes we send with DISCONNECT */
+ switch(c->ourcallstate) {
+ case Q931_CALL_STATE_NULL:
+ if (c->peercallstate == Q931_CALL_STATE_NULL)
+ /* free the resources if we receive or send REL_COMPL */
+- q931_destroycall(pri, c->cr);
++ pri_destroycall(ctrl, c);
+ else if (c->peercallstate == Q931_CALL_STATE_RELEASE_REQUEST)
+- q931_release_complete(pri,c,cause);
++ q931_release_complete(ctrl,c,cause);
+ break;
+ case Q931_CALL_STATE_CALL_INITIATED:
++ if (c->outboundbroadcast && c->master_call == c && t303_was_running) {
++ //c->fakeclearing = 1;
++ //c->alive = 0;
++ /* We need to fake a received clearing sequence in this case... */
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "Faking clearing\n");
++ }
++ pri_create_fake_clearing(c, PRI_MASTER(ctrl));
++ /* This means that we never got a response from a TEI */
++ return 0;
++ }
+ /* we sent SETUP */
+ case Q931_CALL_STATE_OVERLAP_SENDING:
+ /* received SETUP_ACKNOWLEDGE */
+@@ -3221,29 +5365,45 @@
+ case Q931_CALL_STATE_OVERLAP_RECEIVING:
+ /* received SETUP_ACKNOWLEDGE */
+ /* send DISCONNECT in general */
+- if (c->peercallstate != Q931_CALL_STATE_NULL && c->peercallstate != Q931_CALL_STATE_DISCONNECT_REQUEST && c->peercallstate != Q931_CALL_STATE_DISCONNECT_INDICATION && c->peercallstate != Q931_CALL_STATE_RELEASE_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART) {
++ switch (c->peercallstate) {
++ default:
+ if (disconnect)
+- q931_disconnect(pri,c,cause);
++ q931_disconnect(ctrl,c,cause);
+ else if (release_compl)
+- q931_release_complete(pri,c,cause);
++ q931_release_complete(ctrl,c,cause);
+ else
+- q931_release(pri,c,cause);
+- } else
+- pri_error(pri, "Wierd, doing nothing but this shouldn't happen, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
++ q931_release(ctrl,c,cause);
++ break;
++ case Q931_CALL_STATE_NULL:
++ case Q931_CALL_STATE_DISCONNECT_REQUEST:
++ case Q931_CALL_STATE_DISCONNECT_INDICATION:
++ case Q931_CALL_STATE_RELEASE_REQUEST:
++ case Q931_CALL_STATE_RESTART_REQUEST:
++ case Q931_CALL_STATE_RESTART:
++ pri_error(ctrl,
++ "Wierd, doing nothing but this shouldn't happen, ourstate %s, peerstate %s\n",
++ q931_call_state_str(c->ourcallstate),
++ q931_call_state_str(c->peercallstate));
++ break;
++ }
+ break;
+ case Q931_CALL_STATE_ACTIVE:
+ /* received CONNECT */
+- q931_disconnect(pri,c,cause);
++ if (c->cis_call) {
++ q931_release(ctrl, c, cause);
++ break;
++ }
++ q931_disconnect(ctrl,c,cause);
+ break;
+ case Q931_CALL_STATE_DISCONNECT_REQUEST:
+ /* sent DISCONNECT */
+- q931_release(pri,c,cause);
++ q931_release(ctrl,c,cause);
+ break;
+ case Q931_CALL_STATE_DISCONNECT_INDICATION:
+ /* received DISCONNECT */
+ if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST) {
+ c->alive = 1;
+- q931_release(pri,c,cause);
++ q931_release(ctrl,c,cause);
+ }
+ break;
+ case Q931_CALL_STATE_RELEASE_REQUEST:
+@@ -3253,75 +5413,129 @@
+ case Q931_CALL_STATE_RESTART:
+ case Q931_CALL_STATE_RESTART_REQUEST:
+ /* sent RESTART */
+- pri_error(pri, "q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate));
++ pri_error(ctrl,
++ "q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s\n",
++ q931_call_state_str(c->ourcallstate),
++ q931_call_state_str(c->peercallstate));
+ break;
+ default:
+- pri_error(pri, "We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s\n",
+- c->ourcallstate,
+- callstate2str(c->ourcallstate),
+- callstate2str(c->peercallstate));
++ pri_error(ctrl,
++ "We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s\n",
++ c->ourcallstate,
++ q931_call_state_str(c->ourcallstate),
++ q931_call_state_str(c->peercallstate));
+ return -1;
+ }
+ /* we did handle hangup properly at this point */
+ return 0;
+ }
+
+-int q931_receive(struct pri *pri, q931_h *h, int len)
++static void initiate_hangup_if_needed(struct pri *pri, q931_call *call, int cause);
++
++int q931_hangup(struct pri *ctrl, q931_call *call, int cause)
+ {
+- q931_mh *mh;
+- q931_call *c;
+- q931_ie *ie;
+- unsigned int x;
+- int y;
+- int res;
+- int r;
+- int mandies[MAX_MAND_IES];
+- int missingmand;
+- int codeset, cur_codeset;
+- int last_ie[8];
+- struct apdu_event *cur = NULL;
++ int i;
+
+- memset(last_ie, 0, sizeof(last_ie));
+- if (pri->debug & PRI_DEBUG_Q931_DUMP)
+- q931_dump(pri, h, len, 0);
+-#ifdef LIBPRI_COUNTERS
+- pri->q931_rxcount++;
+-#endif
+- mh = (q931_mh *)(h->contents + h->crlen);
+- if ((h->pd == 0x3) || (h->pd == 0x43)) {
+- /* This is the weird maintenance stuff. We majorly
+- KLUDGE this by changing byte 4 from a 0xf (SERVICE)
+- to a 0x7 (SERVICE ACKNOWLEDGE) */
+- h->raw[h->crlen + 2] -= 0x8;
+- q931_xmit(pri, h, len, 1);
+- return 0;
+- } else if (h->pd != pri->protodisc) {
+- pri_error(pri, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd);
+- return 0;
++ if (call->master_call->outboundbroadcast) {
++ if (call->master_call == call) {
++ int slaves = 0;
++
++ /* Master is called with hangup - initiate hangup with slaves */
++ for (i = 0; i < Q931_MAX_TEI; i++) {
++ if (call->subcalls[i]) {
++ slaves++;
++ if (i == call->master_call->pri_winner) {
++ __q931_hangup(call->subcalls[i]->pri, call->subcalls[i], cause);
++ } else {
++ initiate_hangup_if_needed(call->subcalls[i]->pri, call->subcalls[i], cause);
++ }
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "%s: Hanging up %d, winner %d\n", __FUNCTION__,
++ i, call->master_call->pri_winner);
++ }
++ }
++ }
++
++ call->hangupinitiated = 1;
++
++ if ((!slaves && (call->master_call->pri_winner < 0)) || (call->performing_fake_clearing)) {
++ __q931_hangup(ctrl, call, cause);
++ }
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "%s: Slaves %d\n", __FUNCTION__, slaves);
++ }
++ return 0;
++ } else {
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "%s: Slave hangup\n", __FUNCTION__);
++ }
++ return __q931_hangup(ctrl, call, cause);
++ }
++ } else {
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "%s: other hangup\n", __FUNCTION__);
++ }
++ return __q931_hangup(ctrl, call, cause);
+ }
+- c = q931_getcall(pri, q931_cr(h), 0);
+- if (!c) {
+- pri_error(pri, "Unable to locate call %d\n", q931_cr(h));
++ return 0;
++}
++
++static int prepare_to_handle_maintenance_message(struct pri *ctrl, q931_mh *mh, q931_call *c)
++{
++ if ((!ctrl) || (!mh) || (!c)) {
+ return -1;
+ }
+- /* Preliminary handling */
++ /* SERVICE messages are a superset of messages that can take b-channels
++ * or entire d-channels in and out of service */
+ switch(mh->msg) {
++ /* the ATT_SERVICE/ATT_SERVICE_ACKNOWLEDGE and NATIONAL_SERVICE/NATIONAL_SERVICE_ACKNOWLEDGE
++ * are mirrors of each other. We only have to check for one type because they are pre-handled
++ * the same way as each other */
++ case ATT_SERVICE:
++ case ATT_SERVICE_ACKNOWLEDGE:
++ c->channelno = -1;
++ c->slotmap = -1;
++ c->chanflags = 0;
++ c->ds1explicit = 0;
++ c->ds1no = 0;
++ c->cis_call = 0;
++ c->ri = -1;
++ c->changestatus = -1;
++ break;
++ default:
++ pri_error(ctrl, "!! Don't know how to pre-handle maintenance message type '%d'\n", mh->msg);
++ return -1;
++ }
++ return 0;
++}
++
++static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_call *c)
++{
++ if ((!ctrl) || (!mh) || (!c)) {
++ return -1;
++ }
++
++ switch(mh->msg) {
+ case Q931_RESTART:
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "-- Processing Q.931 Restart\n");
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl, "-- Processing Q.931 Restart\n");
+ /* Reset information */
+ c->channelno = -1;
+ c->slotmap = -1;
+ c->chanflags = 0;
+ c->ds1no = 0;
++ c->ds1explicit = 0;
++ c->cis_call = 0;
+ c->ri = -1;
+ break;
+ case Q931_FACILITY:
+- c->callername[0] = '\0';
++ if (q931_is_dummy_call(c)) {
++ q931_party_address_init(&c->called);
++ }
+ break;
+ case Q931_SETUP:
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, "-- Processing Q.931 Call Setup\n");
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl, "-- Processing Q.931 Call Setup\n");
+ c->channelno = -1;
+ c->slotmap = -1;
+ c->chanflags = 0;
+@@ -3334,29 +5548,25 @@
+ c->userl2 = -1;
+ c->userl3 = -1;
+ c->rateadaption = -1;
+- c->calledplan = -1;
+- c->callerplan = -1;
+- c->callerpres = -1;
+- c->callernum[0] = '\0';
+- c->callednum[0] = '\0';
+- c->callername[0] = '\0';
+- c->callerani[0] = '\0';
+- c->callerplanani = -1;
+- c->redirectingplan = -1;
+- c->redirectingpres = -1;
+- c->redirectingreason = -1;
+- c->origcalledplan = -1;
+- c->origcalledpres = -1;
+- c->origredirectingreason = -1;
+- c->redirectingnum[0] = '\0';
+- c->origcallednum[0] = '\0';
+- c->redirectingname[0] = '\0';
+- c->origcalledname[0] = '\0';
++
++ q931_party_address_init(&c->called);
++ q931_party_id_init(&c->local_id);
++ q931_party_id_init(&c->remote_id);
++ q931_party_redirecting_init(&c->redirecting);
++
++ /*
++ * Make sure that keypad and overlap digit buffers are empty in
++ * case they are not in the message.
++ */
++ c->keypad_digits[0] = '\0';
++ c->overlap_digits[0] = '\0';
++
+ c->useruserprotocoldisc = -1;
+ c->useruserinfo[0] = '\0';
+ c->complete = 0;
+ c->nonisdn = 0;
+ c->aoc_units = -1;
++ c->reversecharge = -1;
+ /* Fall through */
+ case Q931_CONNECT:
+ case Q931_ALERTING:
+@@ -3369,8 +5579,7 @@
+ c->progressmask = 0;
+ break;
+ case Q931_CONNECT_ACKNOWLEDGE:
+- if (c->retranstimer)
+- pri_schedule_del(pri, c->retranstimer);
++ pri_schedule_del(ctrl, c->retranstimer);
+ c->retranstimer = 0;
+ break;
+ case Q931_RELEASE:
+@@ -3379,14 +5588,12 @@
+ c->causecode = -1;
+ c->causeloc = -1;
+ c->aoc_units = -1;
+- if (c->retranstimer)
+- pri_schedule_del(pri, c->retranstimer);
++ pri_schedule_del(ctrl, c->retranstimer);
+ c->retranstimer = 0;
+ c->useruserinfo[0] = '\0';
+ break;
+ case Q931_RELEASE_COMPLETE:
+- if (c->retranstimer)
+- pri_schedule_del(pri, c->retranstimer);
++ pri_schedule_del(ctrl, c->retranstimer);
+ c->retranstimer = 0;
+ c->useruserinfo[0] = '\0';
+ /* Fall through */
+@@ -3394,45 +5601,252 @@
+ c->cause = -1;
+ c->causecode = -1;
+ c->causeloc = -1;
+- c->sugcallstate = -1;
++ c->sugcallstate = Q931_CALL_STATE_NOT_SET;
+ c->aoc_units = -1;
+ break;
+ case Q931_RESTART_ACKNOWLEDGE:
+ c->channelno = -1;
++ c->ds1no = 0;
++ c->ds1explicit = 0;
++ c->cis_call = 0;
+ break;
+ case Q931_INFORMATION:
+- c->callednum[0] = '\0';
++ /*
++ * Make sure that keypad and overlap digit buffers are empty in
++ * case they are not in the message.
++ */
++ c->keypad_digits[0] = '\0';
++ c->overlap_digits[0] = '\0';
+ break;
+ case Q931_STATUS_ENQUIRY:
+ break;
+ case Q931_SETUP_ACKNOWLEDGE:
+ break;
+ case Q931_NOTIFY:
++ q931_party_number_init(&c->redirection_number);
+ break;
+- case Q931_USER_INFORMATION:
+- case Q931_SEGMENT:
+- case Q931_CONGESTION_CONTROL:
+ case Q931_HOLD:
++ break;
+ case Q931_HOLD_ACKNOWLEDGE:
++ break;
+ case Q931_HOLD_REJECT:
++ c->cause = -1;
++ break;
+ case Q931_RETRIEVE:
++ c->channelno = 0xFF;
++ c->ds1no = 0;
++ c->ds1explicit = 0;
++ break;
+ case Q931_RETRIEVE_ACKNOWLEDGE:
++ break;
+ case Q931_RETRIEVE_REJECT:
++ c->cause = -1;
++ break;
++ case Q931_USER_INFORMATION:
++ case Q931_SEGMENT:
++ case Q931_CONGESTION_CONTROL:
+ case Q931_RESUME:
+ case Q931_RESUME_ACKNOWLEDGE:
+ case Q931_RESUME_REJECT:
+ case Q931_SUSPEND:
+ case Q931_SUSPEND_ACKNOWLEDGE:
+ case Q931_SUSPEND_REJECT:
+- pri_error(pri, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
++ pri_error(ctrl, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+ /* Fall through */
+ default:
+- pri_error(pri, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+- q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
++ pri_error(ctrl, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
++ q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
+ if (c->newcall)
+- q931_destroycall(pri,c->cr);
++ pri_destroycall(ctrl, c);
+ return -1;
+ }
++ return 0;
++}
++
++static struct q931_call *q931_get_subcall_winner(struct q931_call *master)
++{
++ if (master->pri_winner < 0) {
++ return NULL;
++ } else {
++ return master->subcalls[master->pri_winner];
++ }
++}
++
++static void initiate_hangup_if_needed(struct pri *pri, q931_call *call, int cause)
++{
++ if (!call->hangupinitiated) {
++ q931_hangup(pri, call, cause);
++ call->alive = 0;
++ }
++}
++
++#if 0
++static int q931_get_subcall_count(struct q931_call *call)
++{
++ int count = 0;
++ int i;
++
++ call = call->master_call;
++ for (i = 0; i < Q931_MAX_TEI; i++) {
++ if (call->subcalls[i])
++ count++;
++ }
++
++ return count;
++}
++#endif
++
++static void q931_set_subcall_winner(struct q931_call *subcall)
++{
++ struct q931_call *realcall = subcall->master_call;
++ int i;
++
++ /* Set the winner first */
++ for (i = 0; i < Q931_MAX_TEI; i++) {
++ if (realcall->subcalls[i] && realcall->subcalls[i] == subcall) {
++ realcall->pri_winner = i;
++ }
++ }
++ if (realcall->pri_winner < 0) {
++ pri_error(subcall->pri, "We should always find the winner in the list!\n");
++ return;
++ }
++
++ /* Start tear down of calls that were not chosen */
++ for (i = 0; i < Q931_MAX_TEI; i++) {
++ if (realcall->subcalls[i] && realcall->subcalls[i] != subcall) {
++ initiate_hangup_if_needed(realcall->subcalls[i]->pri, realcall->subcalls[i],
++ PRI_CAUSE_NONSELECTED_USER_CLEARING);
++ }
++ }
++}
++
++static struct q931_call *q931_get_subcall(struct pri *ctrl, struct q931_call *master_call)
++{
++ int i;
++ struct q931_call *cur;
++ int firstfree = -1;
++
++ /* First try to locate our subcall */
++ for (i = 0; i < Q931_MAX_TEI; i++) {
++ if (master_call->subcalls[i]) {
++ if (master_call->subcalls[i]->pri == ctrl) {
++ return master_call->subcalls[i];
++ }
++ } else if (firstfree == -1) {
++ firstfree = i;
++ }
++ }
++ if (firstfree < 0) {
++ pri_error(ctrl, "Tried to add more than %d TEIs to call and failed\n",
++ Q931_MAX_TEI);
++ return NULL;
++ }
++
++ /* Create new subcall. */
++ cur = malloc(sizeof(*cur));
++ if (!cur) {
++ pri_error(ctrl, "Unable to allocate call\n");
++ return NULL;
++ }
++ *cur = *master_call;
++ cur->pri = ctrl;
++ cur->next = NULL;
++ cur->apdus = NULL;
++ cur->bridged_call = NULL;
++ //cur->master_call = master_call; /* We get this assignment for free. */
++ for (i = 0; i < Q931_MAX_TEI; ++i) {
++ cur->subcalls[i] = NULL;
++ }
++ cur->t303_timer = 0;/* T303 should only be on on the master call */
++ cur->hold_timer = 0;
++ cur->retranstimer = 0;
++
++ /* Assume we sent a SETUP and this is the first response to it from this peer. */
++ cur->ourcallstate = Q931_CALL_STATE_CALL_INITIATED;
++ cur->peercallstate = Q931_CALL_STATE_CALL_PRESENT;
++
++ master_call->subcalls[firstfree] = cur;
++
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "Adding subcall %p for TEI %d to call %p at position %d\n",
++ cur, ctrl->tei, master_call, firstfree);
++ }
++ /* Should only get here if the TEI is not found */
++ return cur;
++}
++
++int q931_receive(struct pri *ctrl, q931_h *h, int len)
++{
++ q931_mh *mh;
++ q931_call *c;
++ q931_ie *ie;
++ unsigned int x;
++ int y;
++ int res;
++ int r;
++ int mandies[MAX_MAND_IES];
++ int missingmand;
++ int codeset, cur_codeset;
++ int last_ie[8];
++ int cref;
++
++ memset(last_ie, 0, sizeof(last_ie));
++ if (ctrl->debug & PRI_DEBUG_Q931_DUMP)
++ q931_dump(ctrl, h, len, 0);
++#ifdef LIBPRI_COUNTERS
++ ctrl->q931_rxcount++;
++#endif
++ mh = (q931_mh *)(h->contents + h->crlen);
++ if ((h->pd != ctrl->protodisc) && (h->pd != MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) && (h->pd != MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
++ pri_error(ctrl, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd);
++ return 0;
++ }
++ if (((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) && (!ctrl->service_message_support)) {
++ /* Real service message support has not been enabled (and is OFF in libpri by default),
++ * so we have to revert to the 'traditional' KLUDGE of changing byte 4 from a 0xf (SERVICE)
++ * to a 0x7 (SERVICE ACKNOWLEDGE) */
++ /* This is the weird maintenance stuff. We majorly
++ KLUDGE this by changing byte 4 from a 0xf (SERVICE)
++ to a 0x7 (SERVICE ACKNOWLEDGE) */
++ h->raw[h->crlen + 2] -= 0x8;
++ q931_xmit(ctrl, h, len, 1, 0);
++ return 0;
++ }
++
++ cref = q931_cr(h);
++ c = q931_getcall(ctrl, cref);
++ if (!c) {
++ pri_error(ctrl, "Unable to locate call %d\n", cref);
++ return -1;
++ }
++ if (c->master_call->outboundbroadcast && ctrl != PRI_MASTER(ctrl)) {
++ c = q931_get_subcall(ctrl, c->master_call);
++ if (!c) {
++ pri_error(ctrl, "Unable to locate subcall for %d\n", cref);
++ return -1;
++ }
++ }
++
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl,
++ "Received message for call %p on %p TEI/SAPI %d/%d, call->pri is %p TEI/SAPI %d/%d\n",
++ c,
++ ctrl, ctrl->tei, ctrl->sapi,
++ c->pri, c->pri->tei, c->pri->sapi);
++ }
++
++ /* Preliminary handling */
++ ctrl->facility.count = 0;
++ c->connected_number_in_message = 0;
++ c->redirecting_number_in_message = 0;
++ if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
++ prepare_to_handle_maintenance_message(ctrl, mh, c);
++ } else {
++ prepare_to_handle_q931_message(ctrl, mh, c);
++ }
++ q931_clr_subcommands(ctrl);
++
+ /* Handle IEs */
+ memset(mandies, 0, sizeof(mandies));
+ missingmand = 0;
+@@ -3453,7 +5867,7 @@
+ }
+ r = ielen(ie);
+ if (r > len) {
+- pri_error(pri, "XXX Message longer than it should be?? XXX\n");
++ pri_error(ctrl, "XXX Message longer than it should be?? XXX\n");
+ return -1;
+ }
+ /* Special processing for codeset shifts */
+@@ -3461,16 +5875,16 @@
+ case Q931_LOCKING_SHIFT:
+ y = ie->ie & 7; /* Requested codeset */
+ /* Locking shifts couldn't go to lower codeset, and couldn't follows non-locking shifts - verify this */
+- if ((cur_codeset != codeset) && (pri->debug & PRI_DEBUG_Q931_ANOMALY))
+- pri_message(pri, "XXX Locking shift immediately follows non-locking shift (from %d through %d to %d) XXX\n", codeset, cur_codeset, y);
++ if ((cur_codeset != codeset) && (ctrl->debug & PRI_DEBUG_Q931_ANOMALY))
++ pri_message(ctrl, "XXX Locking shift immediately follows non-locking shift (from %d through %d to %d) XXX\n", codeset, cur_codeset, y);
+ if (y > 0) {
+- if ((y < codeset) && (pri->debug & PRI_DEBUG_Q931_ANOMALY))
+- pri_error(pri, "!! Trying to locked downshift codeset from %d to %d !!\n", codeset, y);
++ if ((y < codeset) && (ctrl->debug & PRI_DEBUG_Q931_ANOMALY))
++ pri_error(ctrl, "!! Trying to locked downshift codeset from %d to %d !!\n", codeset, y);
+ codeset = cur_codeset = y;
+ }
+ else {
+ /* Locking shift to codeset 0 is forbidden by all specifications */
+- pri_error(pri, "!! Invalid locking shift to codeset 0 !!\n");
++ pri_error(ctrl, "!! Invalid locking shift to codeset 0 !!\n");
+ }
+ break;
+ case Q931_NON_LOCKING_SHIFT:
+@@ -3480,24 +5894,24 @@
+ /* Sanity check for IE code order */
+ if (!(ie->ie & 0x80)) {
+ if (last_ie[cur_codeset] > ie->ie) {
+- if ((pri->debug & PRI_DEBUG_Q931_ANOMALY))
+- pri_message(pri, "XXX Out-of-order IE %d at codeset %d (last was %d)\n", ie->ie, cur_codeset, last_ie[cur_codeset]);
++ if ((ctrl->debug & PRI_DEBUG_Q931_ANOMALY))
++ pri_message(ctrl, "XXX Out-of-order IE %d at codeset %d (last was %d)\n", ie->ie, cur_codeset, last_ie[cur_codeset]);
+ }
+ else
+ last_ie[cur_codeset] = ie->ie;
+ }
+ /* Ignore non-locking shifts for TR41459-based signalling */
+- switch (pri->switchtype) {
++ switch (ctrl->switchtype) {
+ case PRI_SWITCH_LUCENT5E:
+ case PRI_SWITCH_ATT4ESS:
+ if (cur_codeset != codeset) {
+- if ((pri->debug & PRI_DEBUG_Q931_DUMP))
+- pri_message(pri, "XXX Ignoring IE %d for temporary codeset %d XXX\n", ie->ie, cur_codeset);
++ if ((ctrl->debug & PRI_DEBUG_Q931_DUMP))
++ pri_message(ctrl, "XXX Ignoring IE %d for temporary codeset %d XXX\n", ie->ie, cur_codeset);
+ break;
+ }
+ /* Fall through */
+ default:
+- y = q931_handle_ie(cur_codeset, pri, c, mh->msg, ie);
++ y = q931_handle_ie(cur_codeset, ctrl, c, mh->msg, ie);
+ /* XXX Applicable to codeset 0 only? XXX */
+ if (!cur_codeset && !(ie->ie & 0xf0) && (y < 0))
+ mandies[MAX_MAND_IES - 1] = Q931_FULL_IE(cur_codeset, ie->ie);
+@@ -3512,33 +5926,562 @@
+ for (x=0;x<MAX_MAND_IES;x++) {
+ if (mandies[x]) {
+ /* check if there is no channel identification when we're configured as network -> that's not an error */
+- if (((pri->localtype != PRI_NETWORK) || (mh->msg != Q931_SETUP) || (mandies[x] != Q931_CHANNEL_IDENT)) &&
++ if (((ctrl->localtype != PRI_NETWORK) || (mh->msg != Q931_SETUP) || (mandies[x] != Q931_CHANNEL_IDENT)) &&
+ ((mh->msg != Q931_PROGRESS) || (mandies[x] != Q931_PROGRESS_INDICATOR))) {
+- pri_error(pri, "XXX Missing handling for mandatory IE %d (cs%d, %s) XXX\n", Q931_IE_IE(mandies[x]), Q931_IE_CODESET(mandies[x]), ie2str(mandies[x]));
++ pri_error(ctrl, "XXX Missing handling for mandatory IE %d (cs%d, %s) XXX\n", Q931_IE_IE(mandies[x]), Q931_IE_CODESET(mandies[x]), ie2str(mandies[x]));
+ missingmand++;
+ }
+ }
+ }
+-
++
++ /* Now handle the facility ie's after all the other ie's were processed. */
++ q931_handle_facilities(ctrl, c, mh->msg);
++
+ /* Post handling */
++ if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
++ res = post_handle_maintenance_message(ctrl, h->pd, mh, c);
++ } else {
++ int allow_event = 1, allow_posthandle = 1;
++
++ if (c->master_call->outboundbroadcast) {
++ nt_ptmp_handle_q931_message(ctrl, mh, c, &allow_event, &allow_posthandle);
++ }
++
++ if (allow_posthandle) {
++ res = post_handle_q931_message(ctrl, mh, c, missingmand);
++
++ if (res == Q931_RES_HAVEEVENT && !allow_event) {
++ res = 0;
++ }
++ } else {
++ res = 0;
++ }
++ }
++ return res;
++}
++
++static int post_handle_maintenance_message(struct pri *ctrl, int protodisc, struct q931_mh *mh, struct q931_call *c)
++{
++ /* Do some maintenance stuff */
++ if (((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) && (mh->msg == ATT_SERVICE))
++ || ((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2) && (mh->msg == NATIONAL_SERVICE))) {
++ if (c->channelno > 0) {
++ ctrl->ev.e = PRI_EVENT_SERVICE;
++ ctrl->ev.service.channel = q931_encode_channel(c);
++ ctrl->ev.service.changestatus = 0x0f & c->changestatus;
++ } else {
++ switch (0x0f & c->changestatus) {
++ case SERVICE_CHANGE_STATUS_INSERVICE:
++ ctrl->ev.e = PRI_EVENT_DCHAN_UP;
++ q921_dchannel_up(ctrl);
++ break;
++ case SERVICE_CHANGE_STATUS_OUTOFSERVICE:
++ ctrl->ev.e = PRI_EVENT_DCHAN_DOWN;
++ q921_dchannel_down(ctrl);
++ break;
++ default:
++ pri_error(ctrl, "!! Don't know how to handle span service change status '%d'\n", (0x0f & c->changestatus));
++ return -1;
++ }
++ }
++ maintenance_service_ack(ctrl, c);
++ return Q931_RES_HAVEEVENT;
++ }
++ if (((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) && (mh->msg == ATT_SERVICE_ACKNOWLEDGE))
++ || ((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2) && (mh->msg == NATIONAL_SERVICE_ACKNOWLEDGE))) {
++ if (c->channelno > 0) {
++ ctrl->ev.e = PRI_EVENT_SERVICE_ACK;
++ ctrl->ev.service_ack.channel = q931_encode_channel(c);
++ ctrl->ev.service_ack.changestatus = 0x0f & c->changestatus;
++ } else {
++ switch (0x0f & c->changestatus) {
++ case SERVICE_CHANGE_STATUS_INSERVICE:
++ ctrl->ev.e = PRI_EVENT_DCHAN_UP;
++ q921_dchannel_up(ctrl);
++ break;
++ case SERVICE_CHANGE_STATUS_OUTOFSERVICE:
++ ctrl->ev.e = PRI_EVENT_DCHAN_DOWN;
++ q921_dchannel_down(ctrl);
++ break;
++ default:
++ pri_error(ctrl, "!! Don't know how to handle span service change status '%d'\n", (0x0f & c->changestatus));
++ return -1;
++ }
++ }
++ return Q931_RES_HAVEEVENT;
++ }
++
++ pri_error(ctrl, "!! Don't know how to post-handle maintenance message type %d\n", mh->msg);
++ return -1;
++}
++
++/*!
++ * \internal
++ * \brief Rank the given Q.931 call state for call etablishment.
++ *
++ * \param state Q.931 call state to rank for competing PTMP NT calls.
++ *
++ * \return Call establishment state ranking.
++ */
++static enum Q931_RANKED_CALL_STATE q931_rank_state(enum Q931_CALL_STATE state)
++{
++ enum Q931_RANKED_CALL_STATE rank;
++
++ switch (state) {
++ case Q931_CALL_STATE_CALL_INITIATED:
++ case Q931_CALL_STATE_CALL_PRESENT:
++ rank = Q931_RANKED_CALL_STATE_PRESENT;
++ break;
++ case Q931_CALL_STATE_OVERLAP_SENDING:
++ case Q931_CALL_STATE_OVERLAP_RECEIVING:
++ rank = Q931_RANKED_CALL_STATE_OVERLAP;
++ break;
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ rank = Q931_RANKED_CALL_STATE_PROCEEDING;
++ break;
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ rank = Q931_RANKED_CALL_STATE_ALERTING;
++ break;
++ case Q931_CALL_STATE_ACTIVE:
++ case Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE:
++ rank = Q931_RANKED_CALL_STATE_CONNECT;
++ break;
++ default:
++ rank = Q931_RANKED_CALL_STATE_OTHER;
++ break;
++ }
++
++ return rank;
++}
++
++/*!
++ * \brief Determine if the master will pass an event to the upper layer.
++ *
++ * \param ctrl D channel controller.
++ * \param subcall Q.931 call leg.
++ * \param msg_type Current message type being processed.
++ *
++ * \note This function must parallel nt_ptmp_handle_q931_message().
++ *
++ * \retval TRUE if the master will pass an event to the upper layer.
++ * \retval FALSE if the event will be blocked.
++ */
++int q931_master_pass_event(struct pri *ctrl, struct q931_call *subcall, int msg_type)
++{
++ struct q931_call *winner;
++ struct q931_call *master;
++ enum Q931_RANKED_CALL_STATE master_rank;
++ enum Q931_RANKED_CALL_STATE subcall_rank;
++ int will_pass; /*!< TRUE if the master will pass an event to the upper layer. */
++
++ master = subcall->master_call;
++ if (subcall == master) {
++ /* We are the master call so of course the master will pass an event. */
++ return 1;
++ }
++
++ winner = q931_get_subcall_winner(master);
++ if (winner && subcall == winner) {
++ /* We are the winner so of course the master will pass an event. */
++ return 1;
++ }
++
++ master_rank = q931_rank_state(master->ourcallstate);
++ will_pass = 0;
++ switch (msg_type) {
++ case Q931_SETUP_ACKNOWLEDGE:
++#if 0 /* Overlap dialing in PTMP NT mode not supported at the present time. */
++ if (master_rank < Q931_RANKED_CALL_STATE_OVERLAP) {
++ will_pass = 1;
++ }
++#endif /* Overlap dialing in PTMP NT mode not supported at the present time. */
++ break;
++ case Q931_CALL_PROCEEDING:
++ if (master_rank < Q931_RANKED_CALL_STATE_PROCEEDING) {
++ will_pass = 1;
++ }
++ break;
++ case Q931_PROGRESS:
++ /*
++ * We will just ignore this message since there could be multiple devices
++ * competing for this call. Who has access to the B channel at this time
++ * to give in-band signals anyway?
++ */
++ break;
++ case Q931_ALERTING:
++ if (master_rank < Q931_RANKED_CALL_STATE_ALERTING) {
++ will_pass = 1;
++ }
++ break;
++ case Q931_CONNECT:
++ if (master_rank < Q931_RANKED_CALL_STATE_CONNECT) {
++ /* We are expected to be the winner for the next message. */
++ will_pass = 1;
++ }
++ break;
++ case Q931_DISCONNECT:
++ case Q931_RELEASE:
++ case Q931_RELEASE_COMPLETE:
++ /* Only deal with the winner. */
++ break;
++ case Q931_FACILITY:
++ case Q931_NOTIFY:
++ if (!winner) {
++ /* The overlap rank does not count here. */
++ if (master_rank == Q931_RANKED_CALL_STATE_OVERLAP) {
++ master_rank = Q931_RANKED_CALL_STATE_PRESENT;
++ }
++ subcall_rank = q931_rank_state(subcall->ourcallstate);
++ if (subcall_rank == Q931_RANKED_CALL_STATE_OVERLAP) {
++ subcall_rank = Q931_RANKED_CALL_STATE_PRESENT;
++ }
++ if (master_rank == subcall_rank) {
++ /*
++ * No winner yet but the subcall is as advanced as the master.
++ * Allow the supplementary service event to pass.
++ */
++ will_pass = 1;
++ }
++ }
++ break;
++ default:
++ /* Only deal with the winner. */
++ break;
++ }
++
++ return will_pass;
++}
++
++/*!
++ * \internal
++ * \brief Handle outboundbroadcast incoming messages for the master_call's state.
++ *
++ * \param ctrl D channel controller.
++ * \param mh Q.931 message type header.
++ * \param subcall Q.931 call leg.
++ * \param allow_event Where to set the allow event to upper layer flag.
++ * \param allow_posthandle Where to set the allow post handle event flag.
++ *
++ * \details
++ * This is where we interact the subcalls state with the master_call's state.
++ *
++ * \note This function must parallel q931_master_pass_event().
++ *
++ * \return Nothing
++ */
++static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *subcall, int *allow_event, int *allow_posthandle)
++{
++ struct q931_call *master = subcall->master_call;
++ struct q931_call *winner = q931_get_subcall_winner(master);
++ enum Q931_RANKED_CALL_STATE master_rank;
++ enum Q931_RANKED_CALL_STATE subcall_rank;
++ enum Q931_CALL_STATE newstate;
++
++ /* For broadcast calls, we default to not allowing events to keep events received to a minimum
++ * and to allow post processing, since that is where hangup and subcall state handling and other processing is done */
++ *allow_event = 0;
++ *allow_posthandle = 1;
++
++ master_rank = q931_rank_state(master->ourcallstate);
++
++ switch (mh->msg) {
++ case Q931_SETUP_ACKNOWLEDGE:
++#if 0 /* Overlap dialing in PTMP NT mode not supported at the present time. */
++ if (master_rank < Q931_RANKED_CALL_STATE_OVERLAP) {
++ *allow_event = 1;
++ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_OVERLAP_SENDING);
++ }
++#endif /* Overlap dialing in PTMP NT mode not supported at the present time. */
++ break;
++ case Q931_CALL_PROCEEDING:
++ if (master_rank < Q931_RANKED_CALL_STATE_PROCEEDING) {
++ *allow_event = 1;
++ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING);
++ }
++ break;
++ case Q931_PROGRESS:
++ /*
++ * We will just ignore this message since there could be multiple devices
++ * competing for this call. Who has access to the B channel at this time
++ * to give in-band signals anyway?
++ */
++ break;
++ case Q931_ALERTING:
++ if (master_rank < Q931_RANKED_CALL_STATE_ALERTING) {
++ *allow_event = 1;
++ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_CALL_DELIVERED);
++ }
++ break;
++ case Q931_CONNECT:
++ if (master_rank < Q931_RANKED_CALL_STATE_CONNECT) {
++ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_ACTIVE);
++ q931_set_subcall_winner(subcall);
++ *allow_event = 1;
++ } else {
++ /* Call clearing of non selected calls occurs in
++ * q931_set_subcall_winner() - All we need to do is make sure
++ * that this connect is not acknowledged */
++ *allow_posthandle = 0;
++ }
++ break;
++ case Q931_DISCONNECT:
++ newstate = Q931_CALL_STATE_DISCONNECT_INDICATION;
++ goto process_hangup;
++ case Q931_RELEASE:
++ case Q931_RELEASE_COMPLETE:
++ newstate = Q931_CALL_STATE_NULL;
++process_hangup:
++ if (!winner) {
++ /* If there's not a winner, we just take the cause and pass it up to the
++ * master_call */
++ master->cause = subcall->cause;
++ } else {
++ /* There *is* a winner */
++ if (subcall == winner) {
++ /* .. and we're it: */
++ *allow_event = 1;
++ UPDATE_OURCALLSTATE(ctrl, master, newstate);
++ }
++ }
++ break;
++ case Q931_FACILITY:
++ case Q931_NOTIFY:
++ if (winner) {
++ if (subcall == winner) {
++ /* Only deal with the winner. */
++ *allow_event = 1;
++ }
++ } else {
++ /* The overlap rank does not count here. */
++ if (master_rank == Q931_RANKED_CALL_STATE_OVERLAP) {
++ master_rank = Q931_RANKED_CALL_STATE_PRESENT;
++ }
++ subcall_rank = q931_rank_state(subcall->ourcallstate);
++ if (subcall_rank == Q931_RANKED_CALL_STATE_OVERLAP) {
++ subcall_rank = Q931_RANKED_CALL_STATE_PRESENT;
++ }
++ if (master_rank == subcall_rank) {
++ /*
++ * No winner yet but the subcall is as advanced as the master.
++ * Allow the supplementary service event to pass.
++ */
++ *allow_event = 1;
++ }
++ }
++ break;
++ default:
++ if (winner && subcall == winner) {
++ /* Only deal with the winner. */
++ *allow_event = 1;
++ }
++ break;
++ }
++}
++
++/*!
++ * \internal
++ * \brief Fill in the FACILITY event fields.
++ *
++ * \param ctrl D channel controller.
++ * \param call Q.931 call leg.
++ *
++ * \return Nothing
++ */
++static void q931_fill_facility_event(struct pri *ctrl, struct q931_call *call)
++{
++ ctrl->ev.e = PRI_EVENT_FACILITY;
++ ctrl->ev.facility.subcmds = &ctrl->subcmds;
++ ctrl->ev.facility.channel = q931_encode_channel(call);
++ ctrl->ev.facility.cref = call->cr;
++ ctrl->ev.facility.call = call->master_call;
++ ctrl->ev.facility.subcall = call;
++
++ /* Need to do this for backward compatibility with struct pri_event_facname */
++ libpri_copy_string(ctrl->ev.facility.callingname, call->remote_id.name.str,
++ sizeof(ctrl->ev.facility.callingname));
++ libpri_copy_string(ctrl->ev.facility.callingnum, call->remote_id.number.str,
++ sizeof(ctrl->ev.facility.callingnum));
++ ctrl->ev.facility.callingpres = q931_party_id_presentation(&call->remote_id);
++ ctrl->ev.facility.callingplan = call->remote_id.number.plan;
++}
++
++/*!
++ * \internal
++ * \brief APDU wait for response message timeout.
++ *
++ * \param data Callback data pointer.
++ *
++ * \return Nothing
++ */
++static void q931_apdu_timeout(void *data)
++{
++ struct apdu_event *apdu;
++ struct pri *ctrl;
++ struct q931_call *call;
++
++ apdu = data;
++ call = apdu->call;
++ ctrl = call->pri;
++
++ q931_clr_subcommands(ctrl);
++ apdu->response.callback(APDU_CALLBACK_REASON_TIMEOUT, ctrl, call, apdu, NULL);
++ if (ctrl->subcmds.counter_subcmd) {
++ q931_fill_facility_event(ctrl, call);
++ ctrl->schedev = 1;
++ }
++
++ pri_call_apdu_delete(call, apdu);
++}
++
++/*!
++ * \internal
++ * \brief Find the active call given the held call.
++ *
++ * \param ctrl D channel controller.
++ * \param held_call Held call to help locate a compatible active call.
++ *
++ * \retval master-active-call on success.
++ * \retval NULL on error.
++ */
++static struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call)
++{
++ struct pri *master;
++ struct q931_call *cur;
++ struct q931_call *winner;
++ struct q931_call *match;
++
++ match = NULL;
++ master = PRI_MASTER(ctrl);
++ for (cur = *master->callpool; cur; cur = cur->next) {
++ if (cur->hold_state == Q931_HOLD_STATE_IDLE) {
++ /* Found an active call. */
++ winner = q931_find_winning_call(cur);
++ if (!winner || (BRI_NT_PTMP(ctrl) && winner->pri != held_call->pri)) {
++ /* There is no winner or the active call does not go to the same TEI. */
++ continue;
++ }
++ switch (winner->ourcallstate) {
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_ACTIVE:
++ break;
++ default:
++ /* Active call not in a good state to transfer. */
++ continue;
++ }
++ if (q931_party_number_cmp(&winner->remote_id.number,
++ &held_call->remote_id.number)) {
++ /* The remote party number does not match. This is a weak match. */
++ match = cur;
++ continue;
++ }
++ /* Found an exact match. */
++ match = cur;
++ break;
++ }
++ }
++
++ return match;
++}
++
++/*!
++ * \internal
++ * \brief Find the held call given the active call.
++ *
++ * \param ctrl D channel controller.
++ * \param active_call Active call to help locate a compatible held call.
++ *
++ * \retval master-held-call on success.
++ * \retval NULL on error.
++ */
++static struct q931_call *q931_find_held_call(struct pri *ctrl, struct q931_call *active_call)
++{
++ struct pri *master;
++ struct q931_call *cur;
++ struct q931_call *winner;
++ struct q931_call *match;
++
++ match = NULL;
++ master = PRI_MASTER(ctrl);
++ for (cur = *master->callpool; cur; cur = cur->next) {
++ if (cur->hold_state == Q931_HOLD_STATE_CALL_HELD) {
++ /* Found a held call. */
++ winner = q931_find_winning_call(cur);
++ if (!winner || (BRI_NT_PTMP(ctrl) && winner->pri != active_call->pri)) {
++ /* There is no winner or the held call does not go to the same TEI. */
++ continue;
++ }
++ switch (winner->ourcallstate) {
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_ACTIVE:
++ break;
++ default:
++ /* Held call not in a good state to transfer. */
++ continue;
++ }
++ if (q931_party_number_cmp(&winner->remote_id.number,
++ &active_call->remote_id.number)) {
++ /* The remote party number does not match. This is a weak match. */
++ match = cur;
++ continue;
++ }
++ /* Found an exact match. */
++ match = cur;
++ break;
++ }
++ }
++
++ return match;
++}
++
++/*!
++ * \internal
++ * \brief Process the decoded information in the Q.931 message.
++ *
++ * \param ctrl D channel controller.
++ * \param mh Q.931 message header.
++ * \param c Q.931 call leg.
++ * \param missingmand Number of missing mandatory ie's.
++ *
++ * \retval 0 if no error or event.
++ * \retval Q931_RES_HAVEEVENT if have an event.
++ * \retval -1 on error.
++ */
++static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand)
++{
++ int res;
++ struct apdu_event *cur = NULL;
++ struct pri_subcommand *subcmd;
++ struct q931_call *master_call;
++
+ switch(mh->msg) {
+ case Q931_RESTART:
+ if (missingmand) {
+- q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+- q931_destroycall(pri, c->cr);
++ q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
++ pri_destroycall(ctrl, c);
+ break;
+ }
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RESTART);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RESTART);
+ c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST;
+ /* Send back the Restart Acknowledge */
+- restart_ack(pri, c);
++ restart_ack(ctrl, c);
+ /* Notify user of restart event */
+- pri->ev.e = PRI_EVENT_RESTART;
+- pri->ev.restart.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
++ ctrl->ev.e = PRI_EVENT_RESTART;
++ ctrl->ev.restart.channel = q931_encode_channel(c);
+ return Q931_RES_HAVEEVENT;
+ case Q931_SETUP:
+ if (missingmand) {
+- q931_release_complete(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
++ q931_release_complete(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+ break;
+ }
+ /* Must be new call */
+@@ -3548,185 +6491,279 @@
+ if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN)
+ c->nonisdn = 1;
+ c->newcall = 0;
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_PRESENT);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_PRESENT);
+ c->peercallstate = Q931_CALL_STATE_CALL_INITIATED;
+ /* it's not yet a call since higher level can respond with RELEASE or RELEASE_COMPLETE */
+ c->alive = 0;
+ if (c->transmoderate != TRANS_MODE_64_CIRCUIT) {
+- q931_release_complete(pri, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL);
++ q931_release_complete(ctrl, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL);
+ break;
+ }
+- pri->ev.e = PRI_EVENT_RING;
+- pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.ring.callingpres = c->callerpres;
+- pri->ev.ring.callingplan = c->callerplan;
+- pri->ev.ring.callingplanani = c->callerplanani;
+- pri->ev.ring.callingplanrdnis = c->redirectingplan;
+- pri->ev.ring.callingplanorigcalled = c->origcalledplan;
+- pri->ev.ring.ani2 = c->ani2;
+- libpri_copy_string(pri->ev.ring.callingani, c->callerani, sizeof(pri->ev.ring.callingani));
+- libpri_copy_string(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum));
+- libpri_copy_string(pri->ev.ring.callingname, c->callername, sizeof(pri->ev.ring.callingname));
+- pri->ev.ring.calledplan = c->calledplan;
+- libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr));
+- libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum));
+- libpri_copy_string(pri->ev.ring.origcalledname, c->origcalledname, sizeof(pri->ev.ring.origcalledname));
+- libpri_copy_string(pri->ev.ring.origcallednum, c->origcallednum, sizeof(pri->ev.ring.origcallednum));
+- libpri_copy_string(pri->ev.ring.redirectingnum, c->redirectingnum, sizeof(pri->ev.ring.redirectingnum));
+- libpri_copy_string(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname));
+- libpri_copy_string(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo));
++
++ if (c->redirecting.from.number.valid && !c->redirecting.count) {
++ /*
++ * This is most likely because the redirecting number came in
++ * with the redirecting ie only and not a DivertingLegInformation2.
++ */
++ c->redirecting.count = 1;
++ }
++ if (c->redirecting.state == Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3) {
++ /*
++ * Valid for Q.SIG and ETSI PRI/BRI-PTP modes:
++ * Setup the redirecting.to informtion so we can identify
++ * if the user wants to manually supply the COLR for this
++ * redirected to number if further redirects could happen.
++ *
++ * All the user needs to do is set the REDIRECTING(to-pres)
++ * to the COLR and REDIRECTING(to-num) = complete-dialed-number
++ * (i.e. CALLERID(dnid)) to be safe after determining that the
++ * incoming call was redirected by checking if the
++ * REDIRECTING(count) is nonzero.
++ */
++ c->redirecting.to.number = c->called.number;
++ c->redirecting.to.number.presentation =
++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
++ }
++
++ ctrl->ev.e = PRI_EVENT_RING;
++ ctrl->ev.ring.subcmds = &ctrl->subcmds;
++ ctrl->ev.ring.channel = q931_encode_channel(c);
++
++ /* Calling party information */
++ ctrl->ev.ring.callingpres = q931_party_id_presentation(&c->remote_id);
++ ctrl->ev.ring.callingplan = c->remote_id.number.plan;
++ if (c->remote_id.number.valid
++ && (c->remote_id.number.presentation == PRES_ALLOWED_NETWORK_NUMBER
++ || c->remote_id.number.presentation == PRES_PROHIB_NETWORK_NUMBER)) {
++ ctrl->ev.ring.callingplanani = c->remote_id.number.plan;
++ libpri_copy_string(ctrl->ev.ring.callingani, c->remote_id.number.str, sizeof(ctrl->ev.ring.callingani));
++ } else {
++ ctrl->ev.ring.callingplanani = -1;
++ ctrl->ev.ring.callingani[0] = '\0';
++ }
++ libpri_copy_string(ctrl->ev.ring.callingnum, c->remote_id.number.str, sizeof(ctrl->ev.ring.callingnum));
++ libpri_copy_string(ctrl->ev.ring.callingname, c->remote_id.name.str, sizeof(ctrl->ev.ring.callingname));
++ q931_party_id_copy_to_pri(&ctrl->ev.ring.calling, &c->remote_id);
++ /* for backwards compatibility, still need ctrl->ev.ring.callingsubaddr */
++ if (!c->remote_id.subaddress.type) { /* NSAP: Type = 0 */
++ libpri_copy_string(ctrl->ev.ring.callingsubaddr, (char *) c->remote_id.subaddress.data, sizeof(ctrl->ev.ring.callingsubaddr));
++ } else {
++ ctrl->ev.ring.callingsubaddr[0] = '\0';
++ }
++
++ ctrl->ev.ring.ani2 = c->ani2;
++
++ /* Called party information */
++ ctrl->ev.ring.calledplan = c->called.number.plan;
++ libpri_copy_string(ctrl->ev.ring.callednum, c->called.number.str, sizeof(ctrl->ev.ring.callednum));
++ q931_party_subaddress_copy_to_pri(&ctrl->ev.ring.called_subaddress, &c->called.subaddress);
++
++ /* Original called party information (For backward compatibility) */
++ libpri_copy_string(ctrl->ev.ring.origcalledname, c->redirecting.orig_called.name.str, sizeof(ctrl->ev.ring.origcalledname));
++ libpri_copy_string(ctrl->ev.ring.origcallednum, c->redirecting.orig_called.number.str, sizeof(ctrl->ev.ring.origcallednum));
++ ctrl->ev.ring.callingplanorigcalled = c->redirecting.orig_called.number.plan;
++ if (c->redirecting.orig_called.number.valid
++ || c->redirecting.orig_called.name.valid) {
++ ctrl->ev.ring.origredirectingreason = c->redirecting.orig_reason;
++ } else {
++ ctrl->ev.ring.origredirectingreason = -1;
++ }
++
++ /* Redirecting from party information (For backward compatibility) */
++ ctrl->ev.ring.callingplanrdnis = c->redirecting.from.number.plan;
++ libpri_copy_string(ctrl->ev.ring.redirectingnum, c->redirecting.from.number.str, sizeof(ctrl->ev.ring.redirectingnum));
++ libpri_copy_string(ctrl->ev.ring.redirectingname, c->redirecting.from.name.str, sizeof(ctrl->ev.ring.redirectingname));
++
++ ctrl->ev.ring.redirectingreason = c->redirecting.reason;
++
++ libpri_copy_string(ctrl->ev.ring.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.ring.useruserinfo));
+ c->useruserinfo[0] = '\0';
+- pri->ev.ring.redirectingreason = c->redirectingreason;
+- pri->ev.ring.origredirectingreason = c->origredirectingreason;
+- pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE);
+- pri->ev.ring.cref = c->cr;
+- pri->ev.ring.call = c;
+- pri->ev.ring.layer1 = c->userl1;
+- pri->ev.ring.complete = c->complete;
+- pri->ev.ring.ctype = c->transcapability;
+- pri->ev.ring.redirectingreason = c->redirectingreason;
+- pri->ev.ring.progress = c->progress;
+- pri->ev.ring.progressmask = c->progressmask;
++
++ libpri_copy_string(ctrl->ev.ring.keypad_digits, c->keypad_digits,
++ sizeof(ctrl->ev.ring.keypad_digits));
++
++ ctrl->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE);
++ ctrl->ev.ring.cref = c->cr;
++ ctrl->ev.ring.call = c->master_call;
++ ctrl->ev.ring.layer1 = c->userl1;
++ ctrl->ev.ring.complete = c->complete;
++ ctrl->ev.ring.ctype = c->transcapability;
++ ctrl->ev.ring.progress = c->progress;
++ ctrl->ev.ring.progressmask = c->progressmask;
++ ctrl->ev.ring.reversecharge = c->reversecharge;
++
++ if (c->redirecting.count) {
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (subcmd) {
++ /* Setup redirecting subcommand */
++ subcmd->cmd = PRI_SUBCMD_REDIRECTING;
++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting,
++ &c->redirecting);
++ }
++ }
++
+ return Q931_RES_HAVEEVENT;
+ case Q931_ALERTING:
++ stop_t303(c);
+ if (c->newcall) {
+- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_DELIVERED);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_DELIVERED);
+ c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED;
+- pri->ev.e = PRI_EVENT_RINGING;
+- pri->ev.ringing.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.ringing.cref = c->cr;
+- pri->ev.ringing.call = c;
+- pri->ev.ringing.progress = c->progress;
+- pri->ev.ringing.progressmask = c->progressmask;
+- libpri_copy_string(pri->ev.ringing.useruserinfo, c->useruserinfo, sizeof(pri->ev.ringing.useruserinfo));
++ ctrl->ev.e = PRI_EVENT_RINGING;
++ ctrl->ev.ringing.subcmds = &ctrl->subcmds;
++ ctrl->ev.ringing.channel = q931_encode_channel(c);
++ ctrl->ev.ringing.cref = c->cr;
++ ctrl->ev.ringing.call = c->master_call;
++ ctrl->ev.ringing.progress = c->progress;
++ ctrl->ev.ringing.progressmask = c->progressmask;
++
++ libpri_copy_string(ctrl->ev.ringing.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.ringing.useruserinfo));
+ c->useruserinfo[0] = '\0';
+
+- cur = c->apdus;
+- while (cur) {
++ for (cur = c->apdus; cur; cur = cur->next) {
+ if (!cur->sent && cur->message == Q931_FACILITY) {
+- q931_facility(pri, c);
++ q931_facility(ctrl, c);
+ break;
+ }
+- cur = cur->next;
+ }
+
+ return Q931_RES_HAVEEVENT;
+ case Q931_CONNECT:
++ stop_t303(c);
+ if (c->newcall) {
+- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+ if (c->ourcallstate == Q931_CALL_STATE_ACTIVE) {
+- q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE);
++ q931_status(ctrl, c, PRI_CAUSE_WRONG_MESSAGE);
+ break;
+ }
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
+ c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
+- pri->ev.e = PRI_EVENT_ANSWER;
+- pri->ev.answer.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.answer.cref = c->cr;
+- pri->ev.answer.call = c;
+- pri->ev.answer.progress = c->progress;
+- pri->ev.answer.progressmask = c->progressmask;
+- libpri_copy_string(pri->ev.answer.useruserinfo, c->useruserinfo, sizeof(pri->ev.answer.useruserinfo));
++
++ ctrl->ev.e = PRI_EVENT_ANSWER;
++ ctrl->ev.answer.subcmds = &ctrl->subcmds;
++ ctrl->ev.answer.channel = q931_encode_channel(c);
++ ctrl->ev.answer.cref = c->cr;
++ ctrl->ev.answer.call = c->master_call;
++ ctrl->ev.answer.progress = c->progress;
++ ctrl->ev.answer.progressmask = c->progressmask;
++ libpri_copy_string(ctrl->ev.answer.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.answer.useruserinfo));
+ c->useruserinfo[0] = '\0';
+- q931_connect_acknowledge(pri, c);
+- if (c->justsignalling) { /* Make sure WE release when we initiatie a signalling only connection */
+- q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);
++
++ q931_connect_acknowledge(ctrl, c);
++
++ if (c->cis_auto_disconnect && c->cis_call) {
++ /* Make sure WE release when we initiate a signalling only connection */
++ q931_hangup(ctrl, c, PRI_CAUSE_NORMAL_CLEARING);
+ break;
+- } else
++ } else {
++ c->incoming_ct_state = INCOMING_CT_STATE_IDLE;
++
++ /* Setup connected line subcommand */
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (subcmd) {
++ subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE;
++ q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &c->remote_id);
++ }
++
+ return Q931_RES_HAVEEVENT;
++ }
+ case Q931_FACILITY:
+ if (c->newcall) {
+- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+- pri->ev.e = PRI_EVENT_FACNAME;
+- libpri_copy_string(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname));
+- libpri_copy_string(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingnum));
+- pri->ev.facname.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.facname.callingpres = c->callerpres;
+- pri->ev.facname.callingplan = c->callerplan;
+- pri->ev.facname.cref = c->cr;
+- pri->ev.facname.call = c;
+-#if 0
+- pri_message(pri, "Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum);
+-#endif
+- return Q931_RES_HAVEEVENT;
++ switch (c->incoming_ct_state) {
++ case INCOMING_CT_STATE_POST_CONNECTED_LINE:
++ c->incoming_ct_state = INCOMING_CT_STATE_IDLE;
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (subcmd) {
++ subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE;
++ q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &c->remote_id);
++ }
++ break;
++ default:
++ break;
++ }
++ if (ctrl->subcmds.counter_subcmd) {
++ q931_fill_facility_event(ctrl, c);
++ return Q931_RES_HAVEEVENT;
++ }
++ break;
+ case Q931_PROGRESS:
+ if (missingmand) {
+- q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+- q931_destroycall(pri, c->cr);
++ q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
++ pri_destroycall(ctrl, c);
+ break;
+ }
+- pri->ev.e = PRI_EVENT_PROGRESS;
+- pri->ev.proceeding.cause = c->cause;
++ ctrl->ev.e = PRI_EVENT_PROGRESS;
++ ctrl->ev.proceeding.cause = c->cause;
+ /* Fall through */
+ case Q931_CALL_PROCEEDING:
++ stop_t303(c);
++ ctrl->ev.proceeding.subcmds = &ctrl->subcmds;
+ if (c->newcall) {
+- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+ if ((c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED) &&
+ (c->ourcallstate != Q931_CALL_STATE_OVERLAP_SENDING) &&
+ (c->ourcallstate != Q931_CALL_STATE_CALL_DELIVERED) &&
+ (c->ourcallstate != Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING)) {
+- q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE);
++ q931_status(ctrl,c,PRI_CAUSE_WRONG_MESSAGE);
+ break;
+ }
+- pri->ev.proceeding.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
++ ctrl->ev.proceeding.channel = q931_encode_channel(c);
+ if (mh->msg == Q931_CALL_PROCEEDING) {
+- pri->ev.e = PRI_EVENT_PROCEEDING;
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING);
++ ctrl->ev.e = PRI_EVENT_PROCEEDING;
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING);
+ c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING;
+ }
+- pri->ev.proceeding.progress = c->progress;
+- pri->ev.proceeding.progressmask = c->progressmask;
+- pri->ev.proceeding.cref = c->cr;
+- pri->ev.proceeding.call = c;
++ ctrl->ev.proceeding.progress = c->progress;
++ ctrl->ev.proceeding.progressmask = c->progressmask;
++ ctrl->ev.proceeding.cref = c->cr;
++ ctrl->ev.proceeding.call = c->master_call;
+
+- cur = c->apdus;
+- while (cur) {
++ for (cur = c->apdus; cur; cur = cur->next) {
+ if (!cur->sent && cur->message == Q931_FACILITY) {
+- q931_facility(pri, c);
++ q931_facility(ctrl, c);
+ break;
+ }
+- cur = cur->next;
+ }
+ return Q931_RES_HAVEEVENT;
+ case Q931_CONNECT_ACKNOWLEDGE:
+ if (c->newcall) {
+- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+ if (!(c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) &&
+ !(c->ourcallstate == Q931_CALL_STATE_ACTIVE &&
+- (pri->localtype == PRI_NETWORK || pri->switchtype == PRI_SWITCH_QSIG))) {
+- q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE);
++ (ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG))) {
++ q931_status(ctrl,c,PRI_CAUSE_WRONG_MESSAGE);
+ break;
+ }
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
+ c->peercallstate = Q931_CALL_STATE_ACTIVE;
+ break;
+ case Q931_STATUS:
+ if (missingmand) {
+- q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
+- q931_destroycall(pri, c->cr);
++ q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
++ pri_destroycall(ctrl, c);
+ break;
+ }
+ if (c->newcall) {
+ if (c->cr & 0x7fff)
+- q931_release_complete(pri,c,PRI_CAUSE_WRONG_CALL_STATE);
++ q931_release_complete(ctrl,c,PRI_CAUSE_WRONG_CALL_STATE);
+ break;
+ }
+ /* Do nothing */
+ /* Also when the STATUS asks for the call of an unexisting reference send RELEASE_COMPL */
+- if ((pri->debug & PRI_DEBUG_Q931_ANOMALY) &&
++ if ((ctrl->debug & PRI_DEBUG_Q931_ANOMALY) &&
+ (c->cause != PRI_CAUSE_INTERWORKING))
+- pri_error(pri, "Received unsolicited status: %s\n", pri_cause2str(c->cause));
++ pri_error(ctrl, "Received unsolicited status: %s\n", pri_cause2str(c->cause));
+ /* Workaround for S-12 ver 7.3 - it responds for invalid/non-implemented IEs at SETUP with null call state */
+ #if 0
+ if (!c->sugcallstate && (c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED)) {
+@@ -3737,25 +6774,28 @@
+
+ if (!c->sugcallstate) {
+ #endif
+- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.hangup.cause = c->cause;
+- pri->ev.hangup.cref = c->cr;
+- pri->ev.hangup.call = c;
+- pri->ev.hangup.aoc_units = c->aoc_units;
+- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
++ ctrl->ev.hangup.subcmds = &ctrl->subcmds;
++ ctrl->ev.hangup.channel = q931_encode_channel(c);
++ ctrl->ev.hangup.cause = c->cause;
++ ctrl->ev.hangup.cref = c->cr;
++ ctrl->ev.hangup.call = c->master_call;
++ ctrl->ev.hangup.aoc_units = c->aoc_units;
++ ctrl->ev.hangup.call_held = NULL;
++ ctrl->ev.hangup.call_active = NULL;
++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
+ /* Free resources */
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
+ c->peercallstate = Q931_CALL_STATE_NULL;
+ if (c->alive) {
+- pri->ev.e = PRI_EVENT_HANGUP;
++ ctrl->ev.e = PRI_EVENT_HANGUP;
+ res = Q931_RES_HAVEEVENT;
+ c->alive = 0;
+ } else if (c->sendhangupack) {
+ res = Q931_RES_HAVEEVENT;
+- pri->ev.e = PRI_EVENT_HANGUP_ACK;
+- q931_hangup(pri, c, c->cause);
++ ctrl->ev.e = PRI_EVENT_HANGUP_ACK;
++ pri_hangup(ctrl, c, c->cause);
+ } else {
+- q931_hangup(pri, c, c->cause);
++ pri_hangup(ctrl, c, c->cause);
+ res = 0;
+ }
+ if (res)
+@@ -3763,32 +6803,38 @@
+ }
+ break;
+ case Q931_RELEASE_COMPLETE:
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
++ c->hangupinitiated = 1;
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
+ c->peercallstate = Q931_CALL_STATE_NULL;
+- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.hangup.cause = c->cause;
+- pri->ev.hangup.cref = c->cr;
+- pri->ev.hangup.call = c;
+- pri->ev.hangup.aoc_units = c->aoc_units;
+- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
++ ctrl->ev.hangup.subcmds = &ctrl->subcmds;
++ ctrl->ev.hangup.channel = q931_encode_channel(c);
++ ctrl->ev.hangup.cause = c->cause;
++ ctrl->ev.hangup.cref = c->cr;
++ ctrl->ev.hangup.call = c->master_call;
++ ctrl->ev.hangup.aoc_units = c->aoc_units;
++ ctrl->ev.hangup.call_held = NULL;
++ ctrl->ev.hangup.call_active = NULL;
++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
+ c->useruserinfo[0] = '\0';
+ /* Free resources */
+ if (c->alive) {
+- pri->ev.e = PRI_EVENT_HANGUP;
++ ctrl->ev.e = PRI_EVENT_HANGUP;
+ res = Q931_RES_HAVEEVENT;
+ c->alive = 0;
+ } else if (c->sendhangupack) {
+ res = Q931_RES_HAVEEVENT;
+- pri->ev.e = PRI_EVENT_HANGUP_ACK;
+- pri_hangup(pri, c, c->cause);
++ ctrl->ev.e = PRI_EVENT_HANGUP_ACK;
++ pri_hangup(ctrl, c, c->cause);
+ } else
+ res = 0;
++
+ if (res)
+ return res;
+ else
+- q931_hangup(pri,c,c->cause);
++ pri_hangup(ctrl,c,c->cause);
+ break;
+ case Q931_RELEASE:
++ c->hangupinitiated = 1;
+ if (missingmand) {
+ /* Force cause to be mandatory IE missing */
+ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
+@@ -3798,59 +6844,113 @@
+ else {
+ c->peercallstate = Q931_CALL_STATE_RELEASE_REQUEST;
+ }
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
+- pri->ev.e = PRI_EVENT_HANGUP;
+- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.hangup.cause = c->cause;
+- pri->ev.hangup.cref = c->cr;
+- pri->ev.hangup.call = c;
+- pri->ev.hangup.aoc_units = c->aoc_units;
+- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
++ ctrl->ev.e = PRI_EVENT_HANGUP;
++ ctrl->ev.hangup.subcmds = &ctrl->subcmds;
++ ctrl->ev.hangup.channel = q931_encode_channel(c);
++ ctrl->ev.hangup.cause = c->cause;
++ ctrl->ev.hangup.cref = c->cr;
++ ctrl->ev.hangup.call = c->master_call;
++ ctrl->ev.hangup.aoc_units = c->aoc_units;
++ ctrl->ev.hangup.call_held = NULL;
++ ctrl->ev.hangup.call_active = NULL;
++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
+ c->useruserinfo[0] = '\0';
+ /* Don't send release complete if they send us release
+ while we sent it, assume a NULL state */
+ if (c->newcall)
+- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+- else
++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ else if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call)))
++ return pri_hangup(ctrl, c, -1);
++ else
+ return Q931_RES_HAVEEVENT;
+ break;
+ case Q931_DISCONNECT:
++ c->hangupinitiated = 1;
+ if (missingmand) {
+ /* Still let user call release */
+ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
+ }
+ if (c->newcall) {
+- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_DISCONNECT_INDICATION);
++
++ /*
++ * Determine if there are any calls that can be proposed for
++ * a transfer of held call on disconnect.
++ */
++ ctrl->ev.hangup.call_held = NULL;
++ ctrl->ev.hangup.call_active = NULL;
++ switch (c->ourcallstate) {
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_ACTIVE:
++ if (c->master_call->hold_state == Q931_HOLD_STATE_CALL_HELD) {
++ /* Held call is being disconnected first. */
++ ctrl->ev.hangup.call_held = c->master_call;
++ ctrl->ev.hangup.call_active = q931_find_held_active_call(ctrl, c);
++ } else {
++ /* Active call is being disconnected first. */
++ if (q931_find_winning_call(c) == c) {
++ /*
++ * Only a normal call or the winning call of a broadcast SETUP
++ * can participate in a transfer of held call on disconnet.
++ */
++ ctrl->ev.hangup.call_active = c->master_call;
++ ctrl->ev.hangup.call_held = q931_find_held_call(ctrl, c);
++ }
++ }
++ break;
++ default:
++ break;
++ }
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ if (ctrl->ev.hangup.call_held) {
++ pri_message(ctrl, "-- Found held call: %p cref:%d\n",
++ ctrl->ev.hangup.call_held, ctrl->ev.hangup.call_held->cr);
++ }
++ if (ctrl->ev.hangup.call_active) {
++ pri_message(ctrl, "-- Found active call: %p cref:%d\n",
++ ctrl->ev.hangup.call_active, ctrl->ev.hangup.call_active->cr);
++ }
++ if (ctrl->ev.hangup.call_held && ctrl->ev.hangup.call_active) {
++ pri_message(ctrl, "-- Transfer held call on disconnect possible.\n");
++ }
++ }
++
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_DISCONNECT_INDICATION);
+ c->peercallstate = Q931_CALL_STATE_DISCONNECT_REQUEST;
+ c->sendhangupack = 1;
+
+ /* wait for a RELEASE so that sufficient time has passed
+ for the inband audio to be heard */
+- if (pri->acceptinbanddisconnect && (c->progressmask & PRI_PROG_INBAND_AVAILABLE))
++ if (ctrl->acceptinbanddisconnect && (c->progressmask & PRI_PROG_INBAND_AVAILABLE))
+ break;
+
+ /* Return such an event */
+- pri->ev.e = PRI_EVENT_HANGUP_REQ;
+- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.hangup.cause = c->cause;
+- pri->ev.hangup.cref = c->cr;
+- pri->ev.hangup.call = c;
+- pri->ev.hangup.aoc_units = c->aoc_units;
+- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
++ ctrl->ev.e = PRI_EVENT_HANGUP_REQ;
++ ctrl->ev.hangup.subcmds = &ctrl->subcmds;
++ ctrl->ev.hangup.channel = q931_encode_channel(c);
++ ctrl->ev.hangup.cause = c->cause;
++ ctrl->ev.hangup.cref = c->cr;
++ ctrl->ev.hangup.call = c->master_call;
++ ctrl->ev.hangup.aoc_units = c->aoc_units;
++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
+ c->useruserinfo[0] = '\0';
+ if (c->alive)
+ return Q931_RES_HAVEEVENT;
+ else
+- q931_hangup(pri,c,c->cause);
++ pri_hangup(ctrl,c,c->cause);
+ break;
+ case Q931_RESTART_ACKNOWLEDGE:
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
+ c->peercallstate = Q931_CALL_STATE_NULL;
+- pri->ev.e = PRI_EVENT_RESTART_ACK;
+- pri->ev.restartack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
++ ctrl->ev.e = PRI_EVENT_RESTART_ACK;
++ ctrl->ev.restartack.channel = q931_encode_channel(c);
+ return Q931_RES_HAVEEVENT;
+ case Q931_INFORMATION:
+ /* XXX We're handling only INFORMATION messages that contain
+@@ -3858,80 +6958,376 @@
+ + the "Complete" msg which is basically an EOF on further digits
+ XXX */
+ if (c->newcall) {
+- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+ if (c->ourcallstate != Q931_CALL_STATE_OVERLAP_RECEIVING) {
+- pri->ev.e = PRI_EVENT_KEYPAD_DIGIT;
+- pri->ev.digit.call = c;
+- pri->ev.digit.channel = c->channelno | (c->ds1no << 8);
+- libpri_copy_string(pri->ev.digit.digits, c->keypad_digits, sizeof(pri->ev.digit.digits));
+- /* Make sure we clear it out before we return */
+- c->keypad_digits[0] = '\0';
++ ctrl->ev.e = PRI_EVENT_KEYPAD_DIGIT;
++ ctrl->ev.digit.subcmds = &ctrl->subcmds;
++ ctrl->ev.digit.call = c->master_call;
++ ctrl->ev.digit.channel = q931_encode_channel(c);
++ libpri_copy_string(ctrl->ev.digit.digits, c->keypad_digits, sizeof(ctrl->ev.digit.digits));
+ return Q931_RES_HAVEEVENT;
+ }
+- pri->ev.e = PRI_EVENT_INFO_RECEIVED;
+- pri->ev.ring.call = c;
+- pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum));
+- libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr));
+- pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */
++ ctrl->ev.e = PRI_EVENT_INFO_RECEIVED;
++ ctrl->ev.ring.subcmds = &ctrl->subcmds;
++ ctrl->ev.ring.call = c->master_call;
++ ctrl->ev.ring.channel = q931_encode_channel(c);
++ libpri_copy_string(ctrl->ev.ring.callednum, c->overlap_digits, sizeof(ctrl->ev.ring.callednum));
++
++ q931_party_id_copy_to_pri(&ctrl->ev.ring.calling, &c->remote_id);
++ /* for backwards compatibility, still need ctrl->ev.ring.callingsubaddr */
++ if (!c->remote_id.subaddress.type) { /* NSAP: Type = 0 */
++ libpri_copy_string(ctrl->ev.ring.callingsubaddr, (char *) c->remote_id.subaddress.data, sizeof(ctrl->ev.ring.callingsubaddr));
++ } else {
++ ctrl->ev.ring.callingsubaddr[0] = '\0';
++ }
++
++ ctrl->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */
+ return Q931_RES_HAVEEVENT;
+ case Q931_STATUS_ENQUIRY:
+ if (c->newcall) {
+- q931_release_complete(pri, c, PRI_CAUSE_INVALID_CALL_REFERENCE);
++ q931_release_complete(ctrl, c, PRI_CAUSE_INVALID_CALL_REFERENCE);
+ } else
+- q931_status(pri,c, 0);
++ q931_status(ctrl,c, 0);
+ break;
+ case Q931_SETUP_ACKNOWLEDGE:
++ stop_t303(c);
+ if (c->newcall) {
+- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
+ break;
+ }
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OVERLAP_SENDING);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OVERLAP_SENDING);
+ c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING;
+- pri->ev.e = PRI_EVENT_SETUP_ACK;
+- pri->ev.setup_ack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.setup_ack.call = c;
++ ctrl->ev.e = PRI_EVENT_SETUP_ACK;
++ ctrl->ev.setup_ack.subcmds = &ctrl->subcmds;
++ ctrl->ev.setup_ack.channel = q931_encode_channel(c);
++ ctrl->ev.setup_ack.call = c->master_call;
+
+- cur = c->apdus;
+- while (cur) {
++ for (cur = c->apdus; cur; cur = cur->next) {
+ if (!cur->sent && cur->message == Q931_FACILITY) {
+- q931_facility(pri, c);
++ q931_facility(ctrl, c);
+ break;
+ }
+- cur = cur->next;
+ }
+
+ return Q931_RES_HAVEEVENT;
+ case Q931_NOTIFY:
+- pri->ev.e = PRI_EVENT_NOTIFY;
+- pri->ev.notify.channel = c->channelno;
+- pri->ev.notify.info = c->notify;
+- return Q931_RES_HAVEEVENT;
+- case Q931_USER_INFORMATION:
+- case Q931_SEGMENT:
+- case Q931_CONGESTION_CONTROL:
++ res = 0;
++ switch (c->notify) {
++ case PRI_NOTIFY_CALL_DIVERTING:
++ if (c->redirection_number.valid) {
++ c->redirecting.to.number = c->redirection_number;
++ if (c->redirecting.count < PRI_MAX_REDIRECTS) {
++ ++c->redirecting.count;
++ }
++ switch (c->ourcallstate) {
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ /* Call is deflecting after we have seen an ALERTING message */
++ c->redirecting.reason = PRI_REDIR_FORWARD_ON_NO_REPLY;
++ break;
++ default:
++ /* Call is deflecting for call forwarding unconditional or busy reason. */
++ c->redirecting.reason = PRI_REDIR_UNKNOWN;
++ break;
++ }
++
++ /* Setup redirecting subcommand */
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (subcmd) {
++ subcmd->cmd = PRI_SUBCMD_REDIRECTING;
++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting,
++ &c->redirecting);
++ }
++ }
++
++ if (ctrl->subcmds.counter_subcmd) {
++ q931_fill_facility_event(ctrl, c);
++ res = Q931_RES_HAVEEVENT;
++ }
++ break;
++ case PRI_NOTIFY_TRANSFER_ALERTING:
++ case PRI_NOTIFY_TRANSFER_ACTIVE:
++ if (c->redirection_number.valid
++ && q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) {
++ /* The remote party information changed. */
++ c->remote_id.number = c->redirection_number;
++
++ /* Setup connected line subcommand */
++ subcmd = q931_alloc_subcommand(ctrl);
++ if (subcmd) {
++ subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE;
++ q931_party_id_copy_to_pri(&subcmd->u.connected_line.id,
++ &c->remote_id);
++ }
++ }
++
++ if (ctrl->subcmds.counter_subcmd) {
++ q931_fill_facility_event(ctrl, c);
++ res = Q931_RES_HAVEEVENT;
++ }
++ break;
++ default:
++ ctrl->ev.e = PRI_EVENT_NOTIFY;
++ ctrl->ev.notify.subcmds = &ctrl->subcmds;
++ ctrl->ev.notify.channel = q931_encode_channel(c);
++ ctrl->ev.notify.info = c->notify;
++ ctrl->ev.notify.call = c->master_call;
++ res = Q931_RES_HAVEEVENT;
++ break;
++ }
++ return res;
+ case Q931_HOLD:
++ res = 0;
++ if (!PRI_MASTER(ctrl)->hold_support) {
++ /*
++ * Blocking any calls from getting on HOLD effectively
++ * disables HOLD/RETRIEVE.
++ */
++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_FACILITY_NOT_IMPLEMENTED);
++ break;
++ }
++ switch (c->ourcallstate) {
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ if (q931_is_ptmp(ctrl)) {
++ /* HOLD request only allowed in these states if point-to-point mode. */
++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
++ break;
++ }
++ /* Fall through */
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_ACTIVE:
++ if (!q931_find_winning_call(c)) {
++ /*
++ * Only the winning call of a broadcast SETUP can do hold since the
++ * call must be answered first.
++ */
++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
++ break;
++ }
++ master_call = c->master_call;
++ switch (master_call->hold_state) {
++ case Q931_HOLD_STATE_HOLD_REQ:
++ if (ctrl->localtype == PRI_NETWORK) {
++ /* The network ignores HOLD request on a hold collision. */
++ break;
++ }
++ /* Fall through */
++ case Q931_HOLD_STATE_IDLE:
++ ctrl->ev.e = PRI_EVENT_HOLD;
++ ctrl->ev.hold.channel = q931_encode_channel(c);
++ ctrl->ev.hold.call = master_call;
++ ctrl->ev.hold.subcmds = &ctrl->subcmds;
++ res = Q931_RES_HAVEEVENT;
++
++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_HOLD_IND);
++
++ /* Stop any T-HOLD timer from possible hold collision. */
++ pri_schedule_del(ctrl, master_call->hold_timer);
++ master_call->hold_timer = 0;
++ break;
++ default:
++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
++ break;
++ }
++ break;
++ case Q931_CALL_STATE_DISCONNECT_INDICATION:
++ case Q931_CALL_STATE_RELEASE_REQUEST:
++ /* Ignore HOLD request in these states. */
++ break;
++ default:
++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
++ break;
++ }
++ return res;
+ case Q931_HOLD_ACKNOWLEDGE:
++ res = 0;
++ master_call = c->master_call;
++ switch (master_call->hold_state) {
++ case Q931_HOLD_STATE_HOLD_REQ:
++ ctrl->ev.e = PRI_EVENT_HOLD_ACK;
++ ctrl->ev.hold_ack.channel = q931_encode_channel(c);
++ ctrl->ev.hold_ack.call = master_call;
++ ctrl->ev.hold_ack.subcmds = &ctrl->subcmds;
++ res = Q931_RES_HAVEEVENT;
++
++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_CALL_HELD);
++
++ /* Call is now on hold so forget the channel. */
++ c->channelno = 0;/* No channel */
++ c->ds1no = 0;
++ c->ds1explicit = 0;
++ c->chanflags = 0;
++
++ /* Stop T-HOLD timer */
++ pri_schedule_del(ctrl, master_call->hold_timer);
++ master_call->hold_timer = 0;
++ break;
++ default:
++ /* Ignore response. Response is late or spurrious. */
++ break;
++ }
++ return res;
+ case Q931_HOLD_REJECT:
++ res = 0;
++ master_call = c->master_call;
++ switch (master_call->hold_state) {
++ case Q931_HOLD_STATE_HOLD_REQ:
++ if (missingmand) {
++ /* Still, let hold rejection continue. */
++ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
++ }
++ ctrl->ev.e = PRI_EVENT_HOLD_REJ;
++ ctrl->ev.hold_rej.channel = q931_encode_channel(c);
++ ctrl->ev.hold_rej.call = master_call;
++ ctrl->ev.hold_rej.cause = c->cause;
++ ctrl->ev.hold_rej.subcmds = &ctrl->subcmds;
++ res = Q931_RES_HAVEEVENT;
++
++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_IDLE);
++
++ /* Stop T-HOLD timer */
++ pri_schedule_del(ctrl, master_call->hold_timer);
++ master_call->hold_timer = 0;
++ break;
++ default:
++ /* Ignore response. Response is late or spurrious. */
++ break;
++ }
++ return res;
+ case Q931_RETRIEVE:
++ res = 0;
++ switch (c->ourcallstate) {
++ case Q931_CALL_STATE_CALL_RECEIVED:
++ case Q931_CALL_STATE_CONNECT_REQUEST:
++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
++ if (q931_is_ptmp(ctrl)) {
++ /* RETRIEVE request only allowed in these states if point-to-point mode. */
++ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
++ break;
++ }
++ /* Fall through */
++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
++ case Q931_CALL_STATE_CALL_DELIVERED:
++ case Q931_CALL_STATE_ACTIVE:
++ if (!q931_find_winning_call(c)) {
++ /*
++ * Only the winning call of a broadcast SETUP can do hold since the
++ * call must be answered first.
++ */
++ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
++ break;
++ }
++ master_call = c->master_call;
++ switch (master_call->hold_state) {
++ case Q931_HOLD_STATE_RETRIEVE_REQ:
++ if (ctrl->localtype == PRI_NETWORK) {
++ /* The network ignores RETRIEVE request on a retrieve collision. */
++ break;
++ }
++ /* Fall through */
++ case Q931_HOLD_STATE_CALL_HELD:
++ ctrl->ev.e = PRI_EVENT_RETRIEVE;
++ ctrl->ev.retrieve.channel = q931_encode_channel(c);
++ ctrl->ev.retrieve.call = master_call;
++ ctrl->ev.retrieve.flexible = !(c->chanflags & FLAG_EXCLUSIVE);
++ ctrl->ev.retrieve.subcmds = &ctrl->subcmds;
++ res = Q931_RES_HAVEEVENT;
++
++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_RETRIEVE_IND);
++
++ /* Stop any T-RETRIEVE timer from possible retrieve collision. */
++ pri_schedule_del(ctrl, master_call->hold_timer);
++ master_call->hold_timer = 0;
++ break;
++ default:
++ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
++ break;
++ }
++ break;
++ case Q931_CALL_STATE_DISCONNECT_INDICATION:
++ case Q931_CALL_STATE_RELEASE_REQUEST:
++ /* Ignore RETRIEVE request in these states. */
++ break;
++ default:
++ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
++ break;
++ }
++ return res;
+ case Q931_RETRIEVE_ACKNOWLEDGE:
++ res = 0;
++ master_call = c->master_call;
++ switch (master_call->hold_state) {
++ case Q931_HOLD_STATE_RETRIEVE_REQ:
++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_IDLE);
++
++ /* Stop T-RETRIEVE timer */
++ pri_schedule_del(ctrl, master_call->hold_timer);
++ master_call->hold_timer = 0;
++
++ ctrl->ev.e = PRI_EVENT_RETRIEVE_ACK;
++ ctrl->ev.retrieve_ack.channel = q931_encode_channel(c);
++ ctrl->ev.retrieve_ack.call = master_call;
++ ctrl->ev.retrieve_ack.subcmds = &ctrl->subcmds;
++ res = Q931_RES_HAVEEVENT;
++ break;
++ default:
++ /* Ignore response. Response is late or spurrious. */
++ break;
++ }
++ return res;
+ case Q931_RETRIEVE_REJECT:
++ res = 0;
++ master_call = c->master_call;
++ switch (master_call->hold_state) {
++ case Q931_HOLD_STATE_RETRIEVE_REQ:
++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_CALL_HELD);
++
++ /* Call is still on hold so forget the channel. */
++ c->channelno = 0;/* No channel */
++ c->ds1no = 0;
++ c->ds1explicit = 0;
++ c->chanflags = 0;
++
++ /* Stop T-RETRIEVE timer */
++ pri_schedule_del(ctrl, master_call->hold_timer);
++ master_call->hold_timer = 0;
++
++ if (missingmand) {
++ /* Still, let retrive rejection continue. */
++ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
++ }
++ ctrl->ev.e = PRI_EVENT_RETRIEVE_REJ;
++ ctrl->ev.retrieve_rej.channel = q931_encode_channel(c);
++ ctrl->ev.retrieve_rej.call = master_call;
++ ctrl->ev.retrieve_rej.cause = c->cause;
++ ctrl->ev.retrieve_rej.subcmds = &ctrl->subcmds;
++ res = Q931_RES_HAVEEVENT;
++ break;
++ default:
++ /* Ignore response. Response is late or spurrious. */
++ break;
++ }
++ return res;
++ case Q931_USER_INFORMATION:
++ case Q931_SEGMENT:
++ case Q931_CONGESTION_CONTROL:
+ case Q931_RESUME:
+ case Q931_RESUME_ACKNOWLEDGE:
+ case Q931_RESUME_REJECT:
+ case Q931_SUSPEND:
+ case Q931_SUSPEND_ACKNOWLEDGE:
+ case Q931_SUSPEND_REJECT:
+- pri_error(pri, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
++ pri_error(ctrl, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+ /* Fall through */
+ default:
+-
+- pri_error(pri, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
+- q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
++ pri_error(ctrl, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
++ q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
+ if (c->newcall)
+- q931_destroycall(pri,c->cr);
++ pri_destroycall(ctrl, c);
+ return -1;
+ }
+ return 0;
+@@ -3941,40 +7337,46 @@
+ static int pri_internal_clear(void *data)
+ {
+ struct q931_call *c = data;
+- struct pri *pri = c->pri;
++ struct pri *ctrl = c->pri;
+ int res;
+
+- if (c->retranstimer)
+- pri_schedule_del(pri, c->retranstimer);
++ pri_schedule_del(ctrl, c->retranstimer);
+ c->retranstimer = 0;
+ c->useruserinfo[0] = '\0';
+- c->cause = -1;
++ //c->cause = -1;
+ c->causecode = -1;
+ c->causeloc = -1;
+- c->sugcallstate = -1;
++ c->sugcallstate = Q931_CALL_STATE_NOT_SET;
+ c->aoc_units = -1;
+
+- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
+ c->peercallstate = Q931_CALL_STATE_NULL;
+- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
+- pri->ev.hangup.cause = c->cause;
+- pri->ev.hangup.cref = c->cr;
+- pri->ev.hangup.call = c;
+- pri->ev.hangup.aoc_units = c->aoc_units;
+- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
++ q931_clr_subcommands(ctrl);
++ ctrl->ev.hangup.subcmds = &ctrl->subcmds;
++ ctrl->ev.hangup.channel = q931_encode_channel(c);
++ ctrl->ev.hangup.cause = c->cause;
++ ctrl->ev.hangup.cref = c->cr;
++ ctrl->ev.hangup.call = c->master_call;
++ ctrl->ev.hangup.aoc_units = c->aoc_units;
++ ctrl->ev.hangup.call_held = NULL;
++ ctrl->ev.hangup.call_active = NULL;
++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
+
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
++ pri_message(ctrl, "clearing, alive %d, hangupack %d\n", c->alive, c->sendhangupack);
++ }
+ /* Free resources */
+ if (c->alive) {
+- pri->ev.e = PRI_EVENT_HANGUP;
++ ctrl->ev.e = PRI_EVENT_HANGUP;
+ res = Q931_RES_HAVEEVENT;
+ c->alive = 0;
+ } else if (c->sendhangupack) {
+ res = Q931_RES_HAVEEVENT;
+- pri->ev.e = PRI_EVENT_HANGUP_ACK;
+- q931_hangup(pri, c, c->cause);
++ ctrl->ev.e = PRI_EVENT_HANGUP_ACK;
++ pri_hangup(ctrl, c, c->cause);
+ } else {
+ res = 0;
+- q931_hangup(pri, c, c->cause);
++ pri_hangup(ctrl, c, c->cause);
+ }
+
+ return res;
+@@ -3984,94 +7386,97 @@
+ static void pri_dl_down_timeout(void *data)
+ {
+ struct q931_call *c = data;
+- struct pri *pri = c->pri;
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, DBGHEAD "Timed out waiting for data link re-establishment\n", DBGINFO);
++ struct pri *ctrl = c->pri;
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl, DBGHEAD "Timed out waiting for data link re-establishment\n", DBGINFO);
+
+ c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER;
+ if (pri_internal_clear(c) == Q931_RES_HAVEEVENT)
+- pri->schedev = 1;
++ ctrl->schedev = 1;
+ }
+
+ /* Handle Layer 2 down event for a non active call. */
+ static void pri_dl_down_cancelcall(void *data)
+ {
+ struct q931_call *c = data;
+- struct pri *pri = c->pri;
+- if (pri->debug & PRI_DEBUG_Q931_STATE)
+- pri_message(pri, DBGHEAD "Cancel non active call after data link failure\n", DBGINFO);
++ struct pri *ctrl = c->pri;
++ if (ctrl->debug & PRI_DEBUG_Q931_STATE)
++ pri_message(ctrl, DBGHEAD "Cancel non active call after data link failure\n", DBGINFO);
+
+ c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER;
+ if (pri_internal_clear(c) == Q931_RES_HAVEEVENT)
+- pri->schedev = 1;
++ ctrl->schedev = 1;
+ }
+
+ /* Receive an indication from Layer 2 */
+-void q931_dl_indication(struct pri *pri, int event)
++void q931_dl_indication(struct pri *ctrl, int event)
+ {
+ q931_call *cur = NULL;
+
+ /* Just return if T309 is not enabled. */
+- if (!pri || pri->timers[PRI_TIMER_T309] < 0)
++ if (!ctrl || ctrl->timers[PRI_TIMER_T309] < 0)
+ return;
+
+ switch (event) {
+ case PRI_EVENT_DCHAN_DOWN:
+- pri_message(pri, DBGHEAD "link is DOWN\n", DBGINFO);
+- cur = *pri->callpool;
++ pri_message(ctrl, DBGHEAD "link is DOWN\n", DBGINFO);
++ cur = *ctrl->callpool;
+ while(cur) {
+ if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE) {
+ /* For a call in Active state, activate T309 only if there is no timer already running. */
+ if (!cur->retranstimer) {
+- pri_message(pri, DBGHEAD "activate T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno);
+- cur->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T309], pri_dl_down_timeout, cur);
++ pri_message(ctrl, DBGHEAD "activate T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno);
++ cur->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T309], pri_dl_down_timeout, cur);
+ }
+ } else if (cur->ourcallstate != Q931_CALL_STATE_NULL) {
+ /* For a call that is not in Active state, schedule internal clearing of the call 'ASAP' (delay 0). */
+- pri_message(pri, DBGHEAD "cancel call %d on channel %d in state %d (%s)\n", DBGINFO,
+- cur->cr, cur->channelno, cur->ourcallstate, callstate2str(cur->ourcallstate));
+- if (cur->retranstimer)
+- pri_schedule_del(pri, cur->retranstimer);
+- cur->retranstimer = pri_schedule_event(pri, 0, pri_dl_down_cancelcall, cur);
++ pri_message(ctrl, DBGHEAD "cancel call %d on channel %d in state %d (%s)\n", DBGINFO,
++ cur->cr, cur->channelno, cur->ourcallstate,
++ q931_call_state_str(cur->ourcallstate));
++ pri_schedule_del(ctrl, cur->retranstimer);
++ cur->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall, cur);
+ }
+ cur = cur->next;
+ }
+ break;
+ case PRI_EVENT_DCHAN_UP:
+- pri_message(pri, DBGHEAD "link is UP\n", DBGINFO);
+- cur = *pri->callpool;
++ pri_message(ctrl, DBGHEAD "link is UP\n", DBGINFO);
++ cur = *ctrl->callpool;
+ while(cur) {
+ if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE && cur->retranstimer) {
+- pri_message(pri, DBGHEAD "cancel T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno);
+- pri_schedule_del(pri, cur->retranstimer);
++ pri_message(ctrl, DBGHEAD "cancel T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno);
++ pri_schedule_del(ctrl, cur->retranstimer);
+ cur->retranstimer = 0;
+- q931_status(pri, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
++ q931_status(ctrl, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
+ } else if (cur->ourcallstate != Q931_CALL_STATE_NULL &&
+ cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_REQUEST &&
+ cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_INDICATION &&
+ cur->ourcallstate != Q931_CALL_STATE_RELEASE_REQUEST) {
+
+ /* The STATUS message sent here is not required by Q.931, but it may help anyway. */
+- q931_status(pri, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
++ q931_status(ctrl, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
+ }
+ cur = cur->next;
+ }
+ break;
+ default:
+- pri_message(pri, DBGHEAD "unexpected event %d.\n", DBGINFO, event);
++ pri_message(ctrl, DBGHEAD "unexpected event %d.\n", DBGINFO, event);
+ }
+ }
+
+-int q931_call_getcrv(struct pri *pri, q931_call *call, int *callmode)
++int q931_call_getcrv(struct pri *ctrl, q931_call *call, int *callmode)
+ {
+ if (callmode)
+ *callmode = call->cr & 0x7;
+ return ((call->cr & 0x7fff) >> 3);
+ }
+
+-int q931_call_setcrv(struct pri *pri, q931_call *call, int crv, int callmode)
++int q931_call_setcrv(struct pri *ctrl, q931_call *call, int crv, int callmode)
+ {
+- call->cr = (crv << 3) & 0x7fff;
+- call->cr |= (callmode & 0x7);
++ /* Do not allow changing the dummy call reference */
++ if (!q931_is_dummy_call(call)) {
++ call->cr = (crv << 3) & 0x7fff;
++ call->cr |= (callmode & 0x7);
++ }
+ return 0;
+ }
+Index: asn1.h
+===================================================================
+--- a/asn1.h (.../tags/1.4.10.2) (revision 0)
++++ b/asn1.h (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,257 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief ASN.1 definitions and prototypes
++ *
++ * \details
++ * This file contains all ASN.1 primitive data structures and
++ * definitions needed for ROSE component encoding and decoding.
++ *
++ * ROSE - Remote Operations Service Element
++ * ASN.1 - Abstract Syntax Notation 1
++ * APDU - Application Protocol Data Unit
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++#ifndef _LIBPRI_ASN1_H
++#define _LIBPRI_ASN1_H
++
++#include <string.h>
++#include <sys/types.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* ------------------------------------------------------------------- */
++
++/*! ASN.1 Identifier Octet - Tag class bits */
++#define ASN1_CLASS_MASK 0xc0
++#define ASN1_CLASS_UNIVERSAL 0x00 /*!< Universal primitive data types */
++#define ASN1_CLASS_APPLICATION 0x40 /*!< Application wide data tag */
++#define ASN1_CLASS_CONTEXT_SPECIFIC 0x80 /*!< Context specifc data tag */
++#define ASN1_CLASS_PRIVATE 0xc0 /*!< Private organization data tag */
++
++/*! ASN.1 Identifier Octet - Primitive/Constructor bit */
++#define ASN1_PC_MASK 0x20
++#define ASN1_PC_PRIMITIVE 0x00
++#define ASN1_PC_CONSTRUCTED 0x20
++
++/*! ASN.1 Identifier Octet - Universal data types */
++#define ASN1_TYPE_MASK 0x1f
++#define ASN1_TYPE_INDEF_TERM 0x00 /* 0 */
++#define ASN1_TYPE_BOOLEAN 0x01 /* 1 */
++#define ASN1_TYPE_INTEGER 0x02 /* 2 */
++#define ASN1_TYPE_BIT_STRING 0x03 /* 3 */
++#define ASN1_TYPE_OCTET_STRING 0x04 /* 4 */
++#define ASN1_TYPE_NULL 0x05 /* 5 */
++#define ASN1_TYPE_OBJECT_IDENTIFIER 0x06 /* 6 */
++#define ASN1_TYPE_OBJECT_DESCRIPTOR 0x07 /* 7 */
++#define ASN1_TYPE_EXTERN 0x08 /* 8 */
++#define ASN1_TYPE_REAL 0x09 /* 9 */
++#define ASN1_TYPE_ENUMERATED 0x0a /* 10 */
++#define ASN1_TYPE_EMBEDDED_PDV 0x0b /* 11 */
++#define ASN1_TYPE_UTF8_STRING 0x0c /* 12 */
++#define ASN1_TYPE_RELATIVE_OID 0x0d /* 13 */
++/* 0x0e & 0x0f are reserved for future ASN.1 editions */
++#define ASN1_TYPE_SEQUENCE 0x10 /* 16 */
++#define ASN1_TYPE_SET 0x11 /* 17 */
++#define ASN1_TYPE_NUMERIC_STRING 0x12 /* 18 */
++#define ASN1_TYPE_PRINTABLE_STRING 0x13 /* 19 */
++#define ASN1_TYPE_TELETEX_STRING 0x14 /* 20 */
++#define ASN1_TYPE_VIDEOTEX_STRING 0x15 /* 21 */
++#define ASN1_TYPE_IA5_STRING 0x16 /* 22 */
++#define ASN1_TYPE_UTC_TIME 0x17 /* 23 */
++#define ASN1_TYPE_GENERALIZED_TIME 0x18 /* 24 */
++#define ASN1_TYPE_GRAPHIC_STRING 0x19 /* 25 */
++#define ASN1_TYPE_VISIBLE_STRING 0x1a /* 26 */
++#define ASN1_TYPE_ISO646_STRING 0x1a /* 26 */
++#define ASN1_TYPE_GENERAL_STRING 0x1b /* 27 */
++#define ASN1_TYPE_UNIVERSAL_STRING 0x1c /* 28 */
++#define ASN1_TYPE_CHAR_STRING 0x1d /* 29 */
++#define ASN1_TYPE_BMP_STRING 0x1e /* 30 */
++#define ASN1_TYPE_EXTENSION 0x1f /* 31 */
++
++#define ASN1_TAG_SEQUENCE (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_SEQUENCE)
++#define ASN1_TAG_SET (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_SET)
++
++#define ASN1_INDEF_TERM (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_INDEF_TERM)
++#define ASN1_INDEF_TERM_LEN 2
++
++struct asn1_oid {
++ /*! \brief Number of subidentifier values in OID list */
++ u_int16_t num_values;
++
++ /*!
++ * \brief OID subidentifier value list
++ * \note The first value is really the first two OID subidentifiers.
++ * They are compressed using this formula:
++ * First_Value = (First_Subidentifier * 40) + Second_Subidentifier
++ */
++ u_int16_t value[10];
++};
++
++#define ASN1_CALL(new_pos, do_it) \
++ do \
++ { \
++ (new_pos) = (do_it); \
++ if (!(new_pos)) { \
++ return NULL; \
++ } \
++ } while (0)
++
++/*! \brief Determine the ending position of the set or sequence to verify the length. */
++#define ASN1_END_SETUP(component_end, offset, length, pos, end) \
++ do { \
++ if ((length) < 0) { \
++ (offset) = ASN1_INDEF_TERM_LEN; \
++ (component_end) = (end); \
++ } else { \
++ (offset) = 0; \
++ (component_end) = (pos) + (length); \
++ } \
++ } while (0)
++
++/*! \brief Account for the indefinite length terminator of the set or sequence. */
++#define ASN1_END_FIXUP(ctrl, pos, offset, component_end, end) \
++ do { \
++ if (offset) { \
++ ASN1_CALL((pos), asn1_dec_indef_end_fixup((ctrl), (pos), (end))); \
++ } else if ((pos) != (component_end)) { \
++ if ((ctrl)->debug & PRI_DEBUG_APDU) { \
++ pri_message((ctrl), \
++ " Skipping unused constructed component octets!\n"); \
++ } \
++ (pos) = (component_end); \
++ } \
++ } while (0)
++
++#define ASN1_DID_NOT_EXPECT_TAG(ctrl, tag) \
++ do { \
++ if ((ctrl)->debug & PRI_DEBUG_APDU) { \
++ pri_message((ctrl), " Did not expect: %s\n", asn1_tag2str(tag)); \
++ } \
++ } while (0)
++
++#define ASN1_CHECK_TAG(ctrl, actual_tag, match_tag, expected_tag) \
++ do { \
++ if ((match_tag) != (expected_tag)) { \
++ ASN1_DID_NOT_EXPECT_TAG((ctrl), (actual_tag)); \
++ return NULL; \
++ } \
++ } while (0)
++
++
++const unsigned char *asn1_dec_tag(const unsigned char *tag_pos, const unsigned char *end,
++ unsigned *tag);
++const unsigned char *asn1_dec_length(const unsigned char *len_pos,
++ const unsigned char *end, int *length);
++const unsigned char *asn1_dec_indef_end_fixup(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end);
++
++const unsigned char *asn1_dec_boolean(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, int32_t *value);
++const unsigned char *asn1_dec_int(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, int32_t *value);
++const unsigned char *asn1_dec_null(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end);
++const unsigned char *asn1_dec_oid(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct asn1_oid *oid);
++const unsigned char *asn1_dec_string_bin(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
++ unsigned char *str, size_t *str_len);
++const unsigned char *asn1_dec_string_max(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size,
++ unsigned char *str, size_t *str_len);
++
++const char *asn1_tag2str(unsigned tag);
++void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1,
++ const unsigned char *end);
++
++
++#define ASN1_LEN_FORM_SHORT 1 /*!< Hint that the final length will be less than 128 octets */
++#define ASN1_LEN_FORM_LONG_U8 2 /*!< Hint that the final length will be less than 256 octets */
++#define ASN1_LEN_FORM_LONG_U16 3 /*!< Hint that the final length will be less than 65536 octets */
++#define ASN1_LEN_INIT(len_pos, end, form_hint) \
++ do { \
++ if ((end) < (len_pos) + (form_hint)) { \
++ return NULL; \
++ } \
++ *(len_pos) = (form_hint); \
++ (len_pos) += (form_hint); \
++ } while (0)
++
++#define ASN1_LEN_FIXUP(len_pos, component_end, end) \
++ ASN1_CALL((component_end), asn1_enc_length_fixup((len_pos), (component_end), (end)))
++
++/*! \brief Use to begin encoding explicit tags, SET, and SEQUENCE constructed groupings. */
++#define ASN1_CONSTRUCTED_BEGIN(len_pos_save, pos, end, tag) \
++ do { \
++ if ((end) < (pos) + (1 + ASN1_LEN_FORM_SHORT)) { \
++ return NULL; \
++ } \
++ *(pos)++ = (tag) | ASN1_PC_CONSTRUCTED; \
++ (len_pos_save) = (pos); \
++ *(pos) = ASN1_LEN_FORM_SHORT; \
++ (pos) += ASN1_LEN_FORM_SHORT; \
++ } while (0)
++
++/*! \brief Use to end encoding explicit tags, SET, and SEQUENCE constructed groupings. */
++#define ASN1_CONSTRUCTED_END(len_pos, component_end, end) \
++ ASN1_CALL((component_end), asn1_enc_length_fixup((len_pos), (component_end), (end)))
++
++#define ASN1_ENC_ERROR(ctrl, msg) \
++ pri_error((ctrl), "%s error: %s\n", __FUNCTION__, (msg))
++
++unsigned char *asn1_enc_length(unsigned char *len_pos, unsigned char *end,
++ size_t str_len);
++unsigned char *asn1_enc_length_fixup(unsigned char *len_pos,
++ unsigned char *component_end, unsigned char *end);
++
++unsigned char *asn1_enc_boolean(unsigned char *pos, unsigned char *end, unsigned tag,
++ int32_t value);
++unsigned char *asn1_enc_int(unsigned char *pos, unsigned char *end, unsigned tag,
++ int32_t value);
++unsigned char *asn1_enc_null(unsigned char *pos, unsigned char *end, unsigned tag);
++unsigned char *asn1_enc_oid(unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct asn1_oid *oid);
++unsigned char *asn1_enc_string_bin(unsigned char *pos, unsigned char *end, unsigned tag,
++ const unsigned char *str, size_t str_len);
++unsigned char *asn1_enc_string_max(unsigned char *pos, unsigned char *end, unsigned tag,
++ const unsigned char *str, size_t max_len);
++
++/* ------------------------------------------------------------------- */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _LIBPRI_ASN1_H */
++/* ------------------------------------------------------------------- */
++/* end asn1.h */
+
+Property changes on: asn1.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose.c
+===================================================================
+--- a/rose.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,2464 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief Remote Operations Service Element (ROSE) main controlling functions
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include <stdio.h>
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++#include "pri_facility.h"
++
++
++#define ROSE_TAG_COMPONENT_INVOKE (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1)
++#define ROSE_TAG_COMPONENT_RESULT (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2)
++#define ROSE_TAG_COMPONENT_ERROR (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3)
++#define ROSE_TAG_COMPONENT_REJECT (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4)
++
++/*! \brief Structure to convert a code value to a string */
++struct rose_code_strings {
++ /*! \brief Code value to convert to a string */
++ int code;
++ /*! \brief String equivalent of the associated code value */
++ const char *name;
++};
++
++/*! \brief ROSE invoke/result message conversion table entry. */
++struct rose_convert_msg {
++ /*! \brief library encoded operation-value */
++ enum rose_operation operation;
++ /*!
++ * \brief OID prefix values to use when encoding/decoding the operation-value OID
++ * \note NULL if operation-value is a localValue.
++ */
++ const struct asn1_oid *oid_prefix;
++ /*! \brief Last OID value or localValue for the encoded operation-value */
++ u_int16_t value;
++
++ /*!
++ * \brief Encode the ROSE invoke operation-value arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ *
++ * \note The function pointer is NULL if there are no arguments to encode.
++ */
++ unsigned char *(*encode_invoke_args)(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args);
++ /*!
++ * \brief Encode the ROSE result operation-value arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ *
++ * \note The function pointer is NULL if there are no arguments to encode.
++ */
++ unsigned char *(*encode_result_args)(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args);
++
++ /*!
++ * \brief Decode the ROSE invoke operation-value arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ *
++ * \note The function pointer is NULL if there are no arguments to decode.
++ */
++ const unsigned char *(*decode_invoke_args)(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args);
++ /*!
++ * \brief Decode the ROSE result operation-value arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ *
++ * \note The function pointer is NULL if there are no arguments to decode.
++ */
++ const unsigned char *(*decode_result_args)(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args);
++};
++
++/*! \brief ROSE error code conversion table entry. */
++struct rose_convert_error {
++ /*! \brief library encoded error-value */
++ enum rose_error_code code;
++ /*!
++ * \brief OID prefix values to use when encoding/decoding the error-value OID
++ * \note NULL if error-value is a localValue.
++ */
++ const struct asn1_oid *oid_prefix;
++ /*! \brief Last OID value or localValue for the encoded error-value */
++ u_int16_t value;
++
++ /*!
++ * \brief Encode the ROSE error parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ *
++ * \note The function pointer is NULL if there are no arguments to encode.
++ */
++ unsigned char *(*encode_error_args)(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_error_args *args);
++
++ /*!
++ * \brief Decode the ROSE error parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ *
++ * \note The function pointer is NULL if there are no arguments to decode.
++ */
++ const unsigned char *(*decode_error_args)(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ union rose_msg_error_args *args);
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * Note the first value in oid.values[] is really the first two
++ * OID subidentifiers. They are compressed using this formula:
++ * First_Value = (First_Subidentifier * 40) + Second_Subidentifier
++ */
++
++/*! \brief ETSI Explicit Call Transfer OID prefix. */
++static const struct asn1_oid rose_etsi_ect = {
++/* *INDENT-OFF* */
++ /* {ccitt(0) identified-organization(4) etsi(0) 369 operations-and-errors(1)} */
++ 4, { 4, 0, 369, 1 }
++/* *INDENT-ON* */
++};
++
++/*! \brief ETSI specific invoke/result encode/decode message table */
++static const struct rose_convert_msg rose_etsi_msgs[] = {
++/* *INDENT-OFF* */
++/*
++ * operation, oid_prefix, value,
++ * encode_invoke_args, encode_result_args,
++ * decode_invoke_args, decode_result_args
++ */
++ /*
++ * localValue's from Diversion-Operations
++ * {ccitt identified-organization etsi(0) 207 operations-and-errors(1)}
++ */
++ {
++ ROSE_ETSI_ActivationDiversion, NULL, 7,
++ rose_enc_etsi_ActivationDiversion_ARG, NULL,
++ rose_dec_etsi_ActivationDiversion_ARG, NULL
++ },
++ {
++ ROSE_ETSI_DeactivationDiversion, NULL, 8,
++ rose_enc_etsi_DeactivationDiversion_ARG,NULL,
++ rose_dec_etsi_DeactivationDiversion_ARG,NULL
++ },
++ {
++ ROSE_ETSI_ActivationStatusNotificationDiv, NULL, 9,
++ rose_enc_etsi_ActivationStatusNotificationDiv_ARG,NULL,
++ rose_dec_etsi_ActivationStatusNotificationDiv_ARG,NULL
++ },
++ {
++ ROSE_ETSI_DeactivationStatusNotificationDiv,NULL, 10,
++ rose_enc_etsi_DeactivationStatusNotificationDiv_ARG,NULL,
++ rose_dec_etsi_DeactivationStatusNotificationDiv_ARG,NULL
++ },
++ {
++ ROSE_ETSI_InterrogationDiversion, NULL, 11,
++ rose_enc_etsi_InterrogationDiversion_ARG,rose_enc_etsi_InterrogationDiversion_RES,
++ rose_dec_etsi_InterrogationDiversion_ARG,rose_dec_etsi_InterrogationDiversion_RES
++ },
++ {
++ ROSE_ETSI_DiversionInformation, NULL, 12,
++ rose_enc_etsi_DiversionInformation_ARG, NULL,
++ rose_dec_etsi_DiversionInformation_ARG, NULL
++ },
++ {
++ ROSE_ETSI_CallDeflection, NULL, 13,
++ rose_enc_etsi_CallDeflection_ARG, NULL,
++ rose_dec_etsi_CallDeflection_ARG, NULL
++ },
++ {
++ ROSE_ETSI_CallRerouting, NULL, 14,
++ rose_enc_etsi_CallRerouting_ARG, NULL,
++ rose_dec_etsi_CallRerouting_ARG, NULL
++ },
++ {
++ ROSE_ETSI_DivertingLegInformation2, NULL, 15,
++ rose_enc_etsi_DivertingLegInformation2_ARG,NULL,
++ rose_dec_etsi_DivertingLegInformation2_ARG,NULL
++ },
++ {
++ ROSE_ETSI_InterrogateServedUserNumbers, NULL, 17,
++ NULL, rose_enc_etsi_InterrogateServedUserNumbers_RES,
++ NULL, rose_dec_etsi_InterrogateServedUserNumbers_RES
++ },
++ {
++ ROSE_ETSI_DivertingLegInformation1, NULL, 18,
++ rose_enc_etsi_DivertingLegInformation1_ARG,NULL,
++ rose_dec_etsi_DivertingLegInformation1_ARG,NULL
++ },
++ {
++ ROSE_ETSI_DivertingLegInformation3, NULL, 19,
++ rose_enc_etsi_DivertingLegInformation3_ARG,NULL,
++ rose_dec_etsi_DivertingLegInformation3_ARG,NULL
++ },
++
++ /*
++ * localValue's from Advice-of-Charge-Operations
++ * {ccitt identified-organization etsi (0) 182 operations-and-errors (1)}
++ *
++ * Advice-Of-Charge-at-call-Setup(AOCS)
++ * Advice-Of-Charge-During-the-call(AOCD)
++ * Advice-Of-Charge-at-the-End-of-the-call(AOCE)
++ */
++ {
++ ROSE_ETSI_ChargingRequest, NULL, 30,
++ rose_enc_etsi_ChargingRequest_ARG, rose_enc_etsi_ChargingRequest_RES,
++ rose_dec_etsi_ChargingRequest_ARG, rose_dec_etsi_ChargingRequest_RES
++ },
++ {
++ ROSE_ETSI_AOCSCurrency, NULL, 31,
++ rose_enc_etsi_AOCSCurrency_ARG, NULL,
++ rose_dec_etsi_AOCSCurrency_ARG, NULL
++ },
++ {
++ ROSE_ETSI_AOCSSpecialArr, NULL, 32,
++ rose_enc_etsi_AOCSSpecialArr_ARG, NULL,
++ rose_dec_etsi_AOCSSpecialArr_ARG, NULL
++ },
++ {
++ ROSE_ETSI_AOCDCurrency, NULL, 33,
++ rose_enc_etsi_AOCDCurrency_ARG, NULL,
++ rose_dec_etsi_AOCDCurrency_ARG, NULL
++ },
++ {
++ ROSE_ETSI_AOCDChargingUnit, NULL, 34,
++ rose_enc_etsi_AOCDChargingUnit_ARG, NULL,
++ rose_dec_etsi_AOCDChargingUnit_ARG, NULL
++ },
++ {
++ ROSE_ETSI_AOCECurrency, NULL, 35,
++ rose_enc_etsi_AOCECurrency_ARG, NULL,
++ rose_dec_etsi_AOCECurrency_ARG, NULL
++ },
++ {
++ ROSE_ETSI_AOCEChargingUnit, NULL, 36,
++ rose_enc_etsi_AOCEChargingUnit_ARG, NULL,
++ rose_dec_etsi_AOCEChargingUnit_ARG, NULL
++ },
++
++ /*
++ * localValue's from Explicit-Call-Transfer-Operations-and-Errors
++ * {ccitt identified-organization etsi(0) 369 operations-and-errors(1)}
++ */
++ {
++ ROSE_ETSI_EctExecute, NULL, 6,
++ NULL, NULL,
++ NULL, NULL
++ },
++
++ /*
++ * globalValue's (OIDs) from Explicit-Call-Transfer-Operations-and-Errors
++ * {ccitt identified-organization etsi(0) 369 operations-and-errors(1)}
++ */
++ {
++ ROSE_ETSI_ExplicitEctExecute, &rose_etsi_ect, 1,
++ rose_enc_etsi_ExplicitEctExecute_ARG, NULL,
++ rose_dec_etsi_ExplicitEctExecute_ARG, NULL
++ },
++ {
++ ROSE_ETSI_RequestSubaddress, &rose_etsi_ect, 2,
++ NULL, NULL,
++ NULL, NULL
++ },
++ {
++ ROSE_ETSI_SubaddressTransfer, &rose_etsi_ect, 3,
++ rose_enc_etsi_SubaddressTransfer_ARG, NULL,
++ rose_dec_etsi_SubaddressTransfer_ARG, NULL
++ },
++ {
++ ROSE_ETSI_EctLinkIdRequest, &rose_etsi_ect, 4,
++ NULL, rose_enc_etsi_EctLinkIdRequest_RES,
++ NULL, rose_dec_etsi_EctLinkIdRequest_RES
++ },
++ {
++ ROSE_ETSI_EctInform, &rose_etsi_ect, 5,
++ rose_enc_etsi_EctInform_ARG, NULL,
++ rose_dec_etsi_EctInform_ARG, NULL
++ },
++ {
++ ROSE_ETSI_EctLoopTest, &rose_etsi_ect, 6,
++ rose_enc_etsi_EctLoopTest_ARG, rose_enc_etsi_EctLoopTest_RES,
++ rose_dec_etsi_EctLoopTest_ARG, rose_dec_etsi_EctLoopTest_RES
++ },
++/* *INDENT-ON* */
++};
++
++
++/*! \brief ETSI specific error-value converion table */
++static const struct rose_convert_error rose_etsi_errors[] = {
++/* *INDENT-OFF* */
++/*
++ * error-code, oid_prefix, value
++ * encode_error_args, decode_error_args
++ */
++ /*
++ * localValue Errors from General-Errors
++ * {ccitt identified-organization etsi(0) 196 general-errors(2)}
++ */
++ {
++ ROSE_ERROR_Gen_NotSubscribed, NULL, 0,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_NotAvailable, NULL, 3,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_NotImplemented, NULL, 4,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_InvalidServedUserNr, NULL, 6,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_InvalidCallState, NULL, 7,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_BasicServiceNotProvided, NULL, 8,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_NotIncomingCall, NULL, 9,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed,NULL, 10,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_ResourceUnavailable, NULL, 11,
++ NULL, NULL
++ },
++
++ /*
++ * localValue Errors from Diversion-Operations
++ * {ccitt identified-organization etsi(0) 207 operations-and-errors(1)}
++ */
++ {
++ ROSE_ERROR_Div_InvalidDivertedToNr, NULL, 12,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Div_SpecialServiceNr, NULL, 14,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Div_DiversionToServedUserNr, NULL, 15,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Div_IncomingCallAccepted, NULL, 23,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Div_NumberOfDiversionsExceeded, NULL, 24,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Div_NotActivated, NULL, 46,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Div_RequestAlreadyAccepted, NULL, 48,
++ NULL, NULL
++ },
++
++ /*
++ * localValue Errors from Advice-of-Charge-Operations
++ * {ccitt identified-organization etsi (0) 182 operations-and-errors (1)}
++ */
++ {
++ ROSE_ERROR_AOC_NoChargingInfoAvailable, NULL, 26,
++ NULL, NULL
++ },
++
++ /*
++ * globalValue Errors (OIDs) from Explicit-Call-Transfer-Operations-and-Errors
++ * {ccitt identified-organization etsi(0) 369 operations-and-errors(1)}
++ */
++ {
++ ROSE_ERROR_ECT_LinkIdNotAssignedByNetwork, &rose_etsi_ect, 21,
++ NULL, NULL
++ },
++/* *INDENT-ON* */
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*! \brief Q.SIG specific invoke/result encode/decode message table */
++static const struct rose_convert_msg rose_qsig_msgs[] = {
++/* *INDENT-OFF* */
++/*
++ * operation, oid_prefix, value,
++ * encode_invoke_args, encode_result_args,
++ * decode_invoke_args, decode_result_args
++ */
++ /*
++ * localValue's from Q.SIG Name-Operations
++ * { iso(1) standard(0) pss1-name(13868) name-operations(0) }
++ */
++ {
++ ROSE_QSIG_CallingName, NULL, 0,
++ rose_enc_qsig_CallingName_ARG, NULL,
++ rose_dec_qsig_CallingName_ARG, NULL
++ },
++ {
++ ROSE_QSIG_CalledName, NULL, 1,
++ rose_enc_qsig_CalledName_ARG, NULL,
++ rose_dec_qsig_CalledName_ARG, NULL
++ },
++ {
++ ROSE_QSIG_ConnectedName, NULL, 2,
++ rose_enc_qsig_ConnectedName_ARG, NULL,
++ rose_dec_qsig_ConnectedName_ARG, NULL
++ },
++ {
++ ROSE_QSIG_BusyName, NULL, 3,
++ rose_enc_qsig_BusyName_ARG, NULL,
++ rose_dec_qsig_BusyName_ARG, NULL
++ },
++
++ /*
++ * localValue's from Q.SIG SS-AOC-Operations
++ * { iso(1) standard(0) pss1-advice-of-charge(15050) advice-of-charge-operations(0) }
++ */
++ {
++ ROSE_QSIG_ChargeRequest, NULL, 59,
++ rose_enc_qsig_ChargeRequest_ARG, rose_enc_qsig_ChargeRequest_RES,
++ rose_dec_qsig_ChargeRequest_ARG, rose_dec_qsig_ChargeRequest_RES
++ },
++ {
++ ROSE_QSIG_GetFinalCharge, NULL, 60,
++ rose_enc_qsig_DummyArg_ARG, NULL,
++ rose_dec_qsig_DummyArg_ARG, NULL
++ },
++ {
++ ROSE_QSIG_AocFinal, NULL, 61,
++ rose_enc_qsig_AocFinal_ARG, NULL,
++ rose_dec_qsig_AocFinal_ARG, NULL
++ },
++ {
++ ROSE_QSIG_AocInterim, NULL, 62,
++ rose_enc_qsig_AocInterim_ARG, NULL,
++ rose_dec_qsig_AocInterim_ARG, NULL
++ },
++ {
++ ROSE_QSIG_AocRate, NULL, 63,
++ rose_enc_qsig_AocRate_ARG, NULL,
++ rose_dec_qsig_AocRate_ARG, NULL
++ },
++ {
++ ROSE_QSIG_AocComplete, NULL, 64,
++ rose_enc_qsig_AocComplete_ARG, rose_enc_qsig_AocComplete_RES,
++ rose_dec_qsig_AocComplete_ARG, rose_dec_qsig_AocComplete_RES
++ },
++ {
++ ROSE_QSIG_AocDivChargeReq, NULL, 65,
++ rose_enc_qsig_AocDivChargeReq_ARG, NULL,
++ rose_dec_qsig_AocDivChargeReq_ARG, NULL
++ },
++
++ /*
++ * localValue's from Q.SIG Call-Transfer-Operations
++ * { iso(1) standard(0) pss1-call-transfer(13869) call-transfer-operations(0) }
++ */
++ {
++ ROSE_QSIG_CallTransferIdentify, NULL, 7,
++ rose_enc_qsig_DummyArg_ARG, rose_enc_qsig_CallTransferIdentify_RES,
++ rose_dec_qsig_DummyArg_ARG, rose_dec_qsig_CallTransferIdentify_RES
++ },
++ {
++ ROSE_QSIG_CallTransferAbandon, NULL, 8,
++ rose_enc_qsig_DummyArg_ARG, NULL,
++ rose_dec_qsig_DummyArg_ARG, NULL
++ },
++ {
++ ROSE_QSIG_CallTransferInitiate, NULL, 9,
++ rose_enc_qsig_CallTransferInitiate_ARG, rose_enc_qsig_DummyRes_RES,
++ rose_dec_qsig_CallTransferInitiate_ARG, rose_dec_qsig_DummyRes_RES
++ },
++ {
++ ROSE_QSIG_CallTransferSetup, NULL, 10,
++ rose_enc_qsig_CallTransferSetup_ARG, rose_enc_qsig_DummyRes_RES,
++ rose_dec_qsig_CallTransferSetup_ARG, rose_dec_qsig_DummyRes_RES
++ },
++ {
++ ROSE_QSIG_CallTransferActive, NULL, 11,
++ rose_enc_qsig_CallTransferActive_ARG, NULL,
++ rose_dec_qsig_CallTransferActive_ARG, NULL
++ },
++ {
++ ROSE_QSIG_CallTransferComplete, NULL, 12,
++ rose_enc_qsig_CallTransferComplete_ARG, NULL,
++ rose_dec_qsig_CallTransferComplete_ARG, NULL
++ },
++ {
++ ROSE_QSIG_CallTransferUpdate, NULL, 13,
++ rose_enc_qsig_CallTransferUpdate_ARG, NULL,
++ rose_dec_qsig_CallTransferUpdate_ARG, NULL
++ },
++ {
++ ROSE_QSIG_SubaddressTransfer, NULL, 14,
++ rose_enc_qsig_SubaddressTransfer_ARG, NULL,
++ rose_dec_qsig_SubaddressTransfer_ARG, NULL
++ },
++
++ /*
++ * NOTE: I do not have the specification needed to fully support this
++ * message. Fortunately, all I have to do for this message is to switch
++ * it to the bridged call leg for 2BCT support.
++ */
++ {
++ ROSE_QSIG_PathReplacement, NULL, 4,
++ NULL, NULL,
++ NULL, NULL
++ },
++
++ /*
++ * localValue's from Q.SIG Call-Diversion-Operations
++ * { iso(1) standard(0) pss1-call-diversion(13873) call-diversion-operations(0) }
++ */
++ {
++ ROSE_QSIG_ActivateDiversionQ, NULL, 15,
++ rose_enc_qsig_ActivateDiversionQ_ARG, rose_enc_qsig_DummyRes_RES,
++ rose_dec_qsig_ActivateDiversionQ_ARG, rose_dec_qsig_DummyRes_RES
++ },
++ {
++ ROSE_QSIG_DeactivateDiversionQ, NULL, 16,
++ rose_enc_qsig_DeactivateDiversionQ_ARG, rose_enc_qsig_DummyRes_RES,
++ rose_dec_qsig_DeactivateDiversionQ_ARG, rose_dec_qsig_DummyRes_RES
++ },
++ {
++ ROSE_QSIG_InterrogateDiversionQ, NULL, 17,
++ rose_enc_qsig_InterrogateDiversionQ_ARG,rose_enc_qsig_InterrogateDiversionQ_RES,
++ rose_dec_qsig_InterrogateDiversionQ_ARG,rose_dec_qsig_InterrogateDiversionQ_RES
++ },
++ {
++ ROSE_QSIG_CheckRestriction, NULL, 18,
++ rose_enc_qsig_CheckRestriction_ARG, rose_enc_qsig_DummyRes_RES,
++ rose_dec_qsig_CheckRestriction_ARG, rose_dec_qsig_DummyRes_RES
++ },
++ {
++ ROSE_QSIG_CallRerouting, NULL, 19,
++ rose_enc_qsig_CallRerouting_ARG, rose_enc_qsig_DummyRes_RES,
++ rose_dec_qsig_CallRerouting_ARG, rose_dec_qsig_DummyRes_RES
++ },
++ {
++ ROSE_QSIG_DivertingLegInformation1, NULL, 20,
++ rose_enc_qsig_DivertingLegInformation1_ARG,NULL,
++ rose_dec_qsig_DivertingLegInformation1_ARG,NULL
++ },
++ {
++ ROSE_QSIG_DivertingLegInformation2, NULL, 21,
++ rose_enc_qsig_DivertingLegInformation2_ARG,NULL,
++ rose_dec_qsig_DivertingLegInformation2_ARG,NULL
++ },
++ {
++ ROSE_QSIG_DivertingLegInformation3, NULL, 22,
++ rose_enc_qsig_DivertingLegInformation3_ARG,NULL,
++ rose_dec_qsig_DivertingLegInformation3_ARG,NULL
++ },
++ {
++ ROSE_QSIG_CfnrDivertedLegFailed, NULL, 23,
++ rose_enc_qsig_DummyArg_ARG, NULL,
++ rose_dec_qsig_DummyArg_ARG, NULL
++ },
++
++ /*
++ * localValue's from Q.SIG SS-MWI-Operations
++ * { iso(1) standard(0) pss1-message-waiting-indication(15506) message-waiting-operations(0) }
++ */
++ {
++ ROSE_QSIG_MWIActivate, NULL, 80,
++ rose_enc_qsig_MWIActivate_ARG, rose_enc_qsig_DummyRes_RES,
++ rose_dec_qsig_MWIActivate_ARG, rose_dec_qsig_DummyRes_RES
++ },
++ {
++ ROSE_QSIG_MWIDeactivate, NULL, 81,
++ rose_enc_qsig_MWIDeactivate_ARG, rose_enc_qsig_DummyRes_RES,
++ rose_dec_qsig_MWIDeactivate_ARG, rose_dec_qsig_DummyRes_RES
++ },
++ {
++ ROSE_QSIG_MWIInterrogate, NULL, 82,
++ rose_enc_qsig_MWIInterrogate_ARG, rose_enc_qsig_MWIInterrogate_RES,
++ rose_dec_qsig_MWIInterrogate_ARG, rose_dec_qsig_MWIInterrogate_RES
++ },
++/* *INDENT-ON* */
++};
++
++
++/*! \brief Q.SIG specific error-value converion table */
++static const struct rose_convert_error rose_qsig_errors[] = {
++/* *INDENT-OFF* */
++/*
++ * error-code, oid_prefix, value
++ * encode_error_args, decode_error_args
++ */
++ /*
++ * localValue Errors from General-Error-List
++ * {ccitt identified-organization q 950 general-error-list(1)}
++ */
++ {
++ ROSE_ERROR_Gen_NotSubscribed, NULL, 0,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_RejectedByNetwork, NULL, 1,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_RejectedByUser, NULL, 2,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_NotAvailable, NULL, 3,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_InsufficientInformation, NULL, 5,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_InvalidServedUserNr, NULL, 6,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_InvalidCallState, NULL, 7,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_BasicServiceNotProvided, NULL, 8,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_NotIncomingCall, NULL, 9,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed,NULL, 10,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_ResourceUnavailable, NULL, 11,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_CallFailure, NULL, 25,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_ProceduralError, NULL, 43,
++ NULL, NULL
++ },
++
++ /*
++ * From various Q.SIG specifications.
++ * We will ignore the manufacturer specific extension information.
++ */
++ {
++ ROSE_ERROR_QSIG_Unspecified, NULL, 1008,
++ NULL, NULL
++ },
++
++ /*
++ * localValue Errors from Q.SIG SS-AOC-Operations
++ * { iso(1) standard(0) pss1-advice-of-charge(15050) advice-of-charge-operations(0) }
++ */
++ {
++ ROSE_ERROR_QSIG_AOC_FreeOfCharge, NULL, 1016,
++ NULL, NULL
++ },
++
++ /*
++ * localValue's from Q.SIG Call-Transfer-Operations
++ * { iso(1) standard(0) pss1-call-transfer(13869) call-transfer-operations(0) }
++ */
++ {
++ ROSE_ERROR_QSIG_CT_InvalidReroutingNumber, NULL, 1004,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_QSIG_CT_UnrecognizedCallIdentity,NULL, 1005,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_QSIG_CT_EstablishmentFailure, NULL, 1006,
++ NULL, NULL
++ },
++
++ /*
++ * localValue's from Q.SIG Call-Diversion-Operations
++ * { iso(1) standard(0) pss1-call-diversion(13873) call-diversion-operations(0) }
++ */
++ {
++ ROSE_ERROR_Div_InvalidDivertedToNr, NULL, 12,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Div_SpecialServiceNr, NULL, 14,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Div_DiversionToServedUserNr, NULL, 15,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Div_NumberOfDiversionsExceeded, NULL, 24,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_QSIG_Div_TemporarilyUnavailable, NULL, 1000,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_QSIG_Div_NotAuthorized, NULL, 1007,
++ NULL, NULL
++ },
++
++ /*
++ * localValue's from Q.SIG SS-MWI-Operations
++ * { iso(1) standard(0) pss1-message-waiting-indication(15506) message-waiting-operations(0) }
++ */
++ {
++ ROSE_ERROR_QSIG_InvalidMsgCentreId, NULL, 1018,
++ NULL, NULL
++ },
++/* *INDENT-ON* */
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*! \brief DMS-100 specific invoke/result encode/decode message table */
++static const struct rose_convert_msg rose_dms100_msgs[] = {
++/* *INDENT-OFF* */
++/*
++ * operation, oid_prefix, value,
++ * encode_invoke_args, encode_result_args,
++ * decode_invoke_args, decode_result_args
++ */
++ {
++ ROSE_DMS100_RLT_OperationInd, NULL, ROSE_DMS100_RLT_OPERATION_IND,
++ NULL, rose_enc_dms100_RLT_OperationInd_RES,
++ NULL, rose_dec_dms100_RLT_OperationInd_RES
++ },
++ {
++ ROSE_DMS100_RLT_ThirdParty, NULL, ROSE_DMS100_RLT_THIRD_PARTY,
++ rose_enc_dms100_RLT_ThirdParty_ARG, NULL,
++ rose_dec_dms100_RLT_ThirdParty_ARG, NULL
++ },
++/* *INDENT-ON* */
++};
++
++
++/*! \brief DMS-100 specific error-value converion table */
++static const struct rose_convert_error rose_dms100_errors[] = {
++/* *INDENT-OFF* */
++/*
++ * error-code, oid_prefix, value
++ * encode_error_args, decode_error_args
++ */
++ {
++ ROSE_ERROR_DMS100_RLT_BridgeFail, NULL, 0x10,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_DMS100_RLT_CallIDNotFound, NULL, 0x11,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_DMS100_RLT_NotAllowed, NULL, 0x12,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_DMS100_RLT_SwitchEquipCongs, NULL, 0x13,
++ NULL, NULL
++ },
++/* *INDENT-ON* */
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * Note the first value in oid.values[] is really the first two
++ * OID subidentifiers. They are compressed using this formula:
++ * First_Value = (First_Subidentifier * 40) + Second_Subidentifier
++ */
++
++static const struct asn1_oid rose_ni2_oid = {
++/* *INDENT-OFF* */
++ /* { iso(1) member-body(2) usa(840) ansi-t1(10005) operations(0) } */
++ 4, { 42, 840, 10005, 0 }
++/* *INDENT-ON* */
++};
++
++/*! \brief NI2 specific invoke/result encode/decode message table */
++static const struct rose_convert_msg rose_ni2_msgs[] = {
++/* *INDENT-OFF* */
++/*
++ * operation, oid_prefix, value,
++ * encode_invoke_args, encode_result_args,
++ * decode_invoke_args, decode_result_args
++ */
++ /* NI2 seems to have pirated several Q.SIG messages */
++ /*
++ * localValue's from Q.SIG Name-Operations
++ * { iso(1) standard(0) pss1-name(13868) name-operations(0) }
++ */
++ {
++ ROSE_QSIG_CallingName, NULL, 0,
++ rose_enc_qsig_CallingName_ARG, NULL,
++ rose_dec_qsig_CallingName_ARG, NULL
++ },
++ {
++ ROSE_QSIG_CalledName, NULL, 1,
++ rose_enc_qsig_CalledName_ARG, NULL,
++ rose_dec_qsig_CalledName_ARG, NULL
++ },
++ {
++ ROSE_QSIG_ConnectedName, NULL, 2,
++ rose_enc_qsig_ConnectedName_ARG, NULL,
++ rose_dec_qsig_ConnectedName_ARG, NULL
++ },
++ {
++ ROSE_QSIG_BusyName, NULL, 3,
++ rose_enc_qsig_BusyName_ARG, NULL,
++ rose_dec_qsig_BusyName_ARG, NULL
++ },
++
++ {
++ ROSE_NI2_InformationFollowing, &rose_ni2_oid, 4,
++ rose_enc_ni2_InformationFollowing_ARG, NULL,
++ rose_dec_ni2_InformationFollowing_ARG, NULL
++ },
++
++ /* Also used by PRI_SWITCH_ATT4ESS and PRI_SWITCH_LUCENT5E */
++ {
++ ROSE_NI2_InitiateTransfer, &rose_ni2_oid, 8,
++ rose_enc_ni2_InitiateTransfer_ARG, NULL,
++ rose_dec_ni2_InitiateTransfer_ARG, NULL
++ },
++/* *INDENT-ON* */
++};
++
++
++/*! \brief NI2 specific error-value converion table */
++static const struct rose_convert_error rose_ni2_errors[] = {
++/* *INDENT-OFF* */
++/*
++ * error-code, oid_prefix, value
++ * encode_error_args, decode_error_args
++ */
++ /*
++ * localValue Errors from General-Error-List
++ * {ccitt identified-organization q 950 general-error-list(1)}
++ */
++ {
++ ROSE_ERROR_Gen_NotSubscribed, NULL, 0,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_RejectedByNetwork, NULL, 1,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_RejectedByUser, NULL, 2,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_NotAvailable, NULL, 3,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_InsufficientInformation, NULL, 5,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_InvalidServedUserNr, NULL, 6,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_InvalidCallState, NULL, 7,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_BasicServiceNotProvided, NULL, 8,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_NotIncomingCall, NULL, 9,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed,NULL, 10,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_ResourceUnavailable, NULL, 11,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_CallFailure, NULL, 25,
++ NULL, NULL
++ },
++ {
++ ROSE_ERROR_Gen_ProceduralError, NULL, 43,
++ NULL, NULL
++ },
++/* *INDENT-ON* */
++};
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Convert the given code value to a string.
++ *
++ * \param code Code value to convert to a string.
++ * \param arr Array to convert the code to a string.
++ * \param num_elements Number of elements in the conversion array.
++ *
++ * \retval String version of the given code value.
++ */
++static const char *rose_code2str(int code, const struct rose_code_strings *arr,
++ unsigned num_elements)
++{
++ static char invalid_code[40];
++
++ unsigned index;
++
++ for (index = 0; index < num_elements; ++index) {
++ if (arr[index].code == code) {
++ return arr[index].name;
++ }
++ }
++
++ snprintf(invalid_code, sizeof(invalid_code), "Invalid code:%d 0x%X", code, code);
++ return invalid_code;
++}
++
++/*!
++ * \brief Convert the given operation-value to a string.
++ *
++ * \param operation Operation-value to convert to a string.
++ *
++ * \retval String version of the given operation-value.
++ */
++const char *rose_operation2str(enum rose_operation operation)
++{
++ static const struct rose_code_strings arr[] = {
++/* *INDENT-OFF* */
++ { ROSE_None, "ROSE_None" },
++ { ROSE_Unknown, "ROSE_Unknown" },
++
++ { ROSE_ETSI_ActivationDiversion, "ROSE_ETSI_ActivationDiversion" },
++ { ROSE_ETSI_DeactivationDiversion, "ROSE_ETSI_DeactivationDiversion" },
++ { ROSE_ETSI_ActivationStatusNotificationDiv,"ROSE_ETSI_ActivationStatusNotificationDiv" },
++ { ROSE_ETSI_DeactivationStatusNotificationDiv,"ROSE_ETSI_DeactivationStatusNotificationDiv" },
++ { ROSE_ETSI_InterrogationDiversion, "ROSE_ETSI_InterrogationDiversion" },
++ { ROSE_ETSI_DiversionInformation, "ROSE_ETSI_DiversionInformation" },
++ { ROSE_ETSI_CallDeflection, "ROSE_ETSI_CallDeflection" },
++ { ROSE_ETSI_CallRerouting, "ROSE_ETSI_CallRerouting" },
++ { ROSE_ETSI_DivertingLegInformation2, "ROSE_ETSI_DivertingLegInformation2" },
++ { ROSE_ETSI_InterrogateServedUserNumbers, "ROSE_ETSI_InterrogateServedUserNumbers" },
++ { ROSE_ETSI_DivertingLegInformation1, "ROSE_ETSI_DivertingLegInformation1" },
++ { ROSE_ETSI_DivertingLegInformation3, "ROSE_ETSI_DivertingLegInformation3" },
++
++ { ROSE_ETSI_EctExecute, "ROSE_ETSI_EctExecute" },
++ { ROSE_ETSI_ExplicitEctExecute, "ROSE_ETSI_ExplicitEctExecute" },
++ { ROSE_ETSI_RequestSubaddress, "ROSE_ETSI_RequestSubaddress" },
++ { ROSE_ETSI_SubaddressTransfer, "ROSE_ETSI_SubaddressTransfer" },
++ { ROSE_ETSI_EctLinkIdRequest, "ROSE_ETSI_EctLinkIdRequest" },
++ { ROSE_ETSI_EctInform, "ROSE_ETSI_EctInform" },
++ { ROSE_ETSI_EctLoopTest, "ROSE_ETSI_EctLoopTest" },
++
++ { ROSE_ETSI_ChargingRequest, "ROSE_ETSI_ChargingRequest" },
++ { ROSE_ETSI_AOCSCurrency, "ROSE_ETSI_AOCSCurrency" },
++ { ROSE_ETSI_AOCSSpecialArr, "ROSE_ETSI_AOCSSpecialArr" },
++ { ROSE_ETSI_AOCDCurrency, "ROSE_ETSI_AOCDCurrency" },
++ { ROSE_ETSI_AOCDChargingUnit, "ROSE_ETSI_AOCDChargingUnit" },
++ { ROSE_ETSI_AOCECurrency, "ROSE_ETSI_AOCECurrency" },
++ { ROSE_ETSI_AOCEChargingUnit, "ROSE_ETSI_AOCEChargingUnit" },
++
++ { ROSE_QSIG_CallingName, "ROSE_QSIG_CallingName" },
++ { ROSE_QSIG_CalledName, "ROSE_QSIG_CalledName" },
++ { ROSE_QSIG_ConnectedName, "ROSE_QSIG_ConnectedName" },
++ { ROSE_QSIG_BusyName, "ROSE_QSIG_BusyName" },
++
++ { ROSE_QSIG_ChargeRequest, "ROSE_QSIG_ChargeRequest" },
++ { ROSE_QSIG_GetFinalCharge, "ROSE_QSIG_GetFinalCharge" },
++ { ROSE_QSIG_AocFinal, "ROSE_QSIG_AocFinal" },
++ { ROSE_QSIG_AocInterim, "ROSE_QSIG_AocInterim" },
++ { ROSE_QSIG_AocRate, "ROSE_QSIG_AocRate" },
++ { ROSE_QSIG_AocComplete, "ROSE_QSIG_AocComplete" },
++ { ROSE_QSIG_AocDivChargeReq, "ROSE_QSIG_AocDivChargeReq" },
++
++ { ROSE_QSIG_CallTransferIdentify, "ROSE_QSIG_CallTransferIdentify" },
++ { ROSE_QSIG_CallTransferAbandon, "ROSE_QSIG_CallTransferAbandon" },
++ { ROSE_QSIG_CallTransferInitiate, "ROSE_QSIG_CallTransferInitiate" },
++ { ROSE_QSIG_CallTransferSetup, "ROSE_QSIG_CallTransferSetup" },
++ { ROSE_QSIG_CallTransferActive, "ROSE_QSIG_CallTransferActive" },
++ { ROSE_QSIG_CallTransferComplete, "ROSE_QSIG_CallTransferComplete" },
++ { ROSE_QSIG_CallTransferUpdate, "ROSE_QSIG_CallTransferUpdate" },
++ { ROSE_QSIG_SubaddressTransfer, "ROSE_QSIG_SubaddressTransfer" },
++
++ { ROSE_QSIG_PathReplacement, "ROSE_QSIG_PathReplacement" },
++
++ { ROSE_QSIG_ActivateDiversionQ, "ROSE_QSIG_ActivateDiversionQ" },
++ { ROSE_QSIG_DeactivateDiversionQ, "ROSE_QSIG_DeactivateDiversionQ" },
++ { ROSE_QSIG_InterrogateDiversionQ, "ROSE_QSIG_InterrogateDiversionQ" },
++ { ROSE_QSIG_CheckRestriction, "ROSE_QSIG_CheckRestriction" },
++ { ROSE_QSIG_CallRerouting, "ROSE_QSIG_CallRerouting" },
++ { ROSE_QSIG_DivertingLegInformation1, "ROSE_QSIG_DivertingLegInformation1" },
++ { ROSE_QSIG_DivertingLegInformation2, "ROSE_QSIG_DivertingLegInformation2" },
++ { ROSE_QSIG_DivertingLegInformation3, "ROSE_QSIG_DivertingLegInformation3" },
++ { ROSE_QSIG_CfnrDivertedLegFailed, "ROSE_QSIG_CfnrDivertedLegFailed" },
++
++ { ROSE_QSIG_MWIActivate, "ROSE_QSIG_MWIActivate" },
++ { ROSE_QSIG_MWIDeactivate, "ROSE_QSIG_MWIDeactivate" },
++ { ROSE_QSIG_MWIInterrogate, "ROSE_QSIG_MWIInterrogate" },
++
++ { ROSE_DMS100_RLT_OperationInd, "ROSE_DMS100_RLT_OperationInd" },
++ { ROSE_DMS100_RLT_ThirdParty, "ROSE_DMS100_RLT_ThirdParty" },
++
++ { ROSE_NI2_InformationFollowing, "ROSE_NI2_InformationFollowing" },
++ { ROSE_NI2_InitiateTransfer, "ROSE_NI2_InitiateTransfer" },
++/* *INDENT-ON* */
++ };
++
++ return rose_code2str(operation, arr, ARRAY_LEN(arr));
++}
++
++/*!
++ * \brief Convert the given error-value to a string.
++ *
++ * \param code Error-value to convert to a string.
++ *
++ * \retval String version of the given error-value.
++ */
++const char *rose_error2str(enum rose_error_code code)
++{
++ static const struct rose_code_strings arr[] = {
++/* *INDENT-OFF* */
++ { ROSE_ERROR_None, "No error occurred" },
++ { ROSE_ERROR_Unknown, "Unknown error-value code" },
++
++ { ROSE_ERROR_Gen_NotSubscribed, "General: Not Subscribed" },
++ { ROSE_ERROR_Gen_NotAvailable, "General: Not Available" },
++ { ROSE_ERROR_Gen_NotImplemented, "General: Not Implemented" },
++ { ROSE_ERROR_Gen_InvalidServedUserNr, "General: Invalid Served User Number" },
++ { ROSE_ERROR_Gen_InvalidCallState, "General: Invalid Call State" },
++ { ROSE_ERROR_Gen_BasicServiceNotProvided, "General: Basic Service Not Provided" },
++ { ROSE_ERROR_Gen_NotIncomingCall, "General: Not Incoming Call" },
++ { ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed,"General: Supplementary Service Interaction Not Allowed" },
++ { ROSE_ERROR_Gen_ResourceUnavailable, "General: Resource Unavailable" },
++
++ /* Additional Q.950 General-Errors for Q.SIG */
++ { ROSE_ERROR_Gen_RejectedByNetwork, "General: Rejected By Network" },
++ { ROSE_ERROR_Gen_RejectedByUser, "General: Rejected By User" },
++ { ROSE_ERROR_Gen_InsufficientInformation, "General: Insufficient Information" },
++ { ROSE_ERROR_Gen_CallFailure, "General: Call Failure" },
++ { ROSE_ERROR_Gen_ProceduralError, "General: Procedural Error" },
++
++ { ROSE_ERROR_Div_InvalidDivertedToNr, "Diversion: Invalid Diverted To Number" },
++ { ROSE_ERROR_Div_SpecialServiceNr, "Diversion: Special Service Number" },
++ { ROSE_ERROR_Div_DiversionToServedUserNr, "Diversion: Diversion To Served User Number" },
++ { ROSE_ERROR_Div_IncomingCallAccepted, "Diversion: Incoming Call Accepted" },
++ { ROSE_ERROR_Div_NumberOfDiversionsExceeded, "Diversion: Number Of Diversions Exceeded" },
++ { ROSE_ERROR_Div_NotActivated, "Diversion: Not Activated" },
++ { ROSE_ERROR_Div_RequestAlreadyAccepted, "Diversion: Request Already Accepted" },
++
++ { ROSE_ERROR_AOC_NoChargingInfoAvailable, "AOC: No Charging Info Available" },
++
++ { ROSE_ERROR_ECT_LinkIdNotAssignedByNetwork, "ECT: Link ID Not Assigned By Network" },
++
++ /* Q.SIG specific errors */
++ { ROSE_ERROR_QSIG_Unspecified, "Unspecified" },
++
++ { ROSE_ERROR_QSIG_AOC_FreeOfCharge, "AOC: FreeOfCharge" },
++
++ { ROSE_ERROR_QSIG_CT_InvalidReroutingNumber, "CT: Invalid Rerouting Number" },
++ { ROSE_ERROR_QSIG_CT_UnrecognizedCallIdentity,"CT: Unrecognized Call Identity" },
++ { ROSE_ERROR_QSIG_CT_EstablishmentFailure, "CT: Establishment Failure" },
++
++ { ROSE_ERROR_QSIG_Div_TemporarilyUnavailable, "Diversion: Temporarily Unavailable" },
++ { ROSE_ERROR_QSIG_Div_NotAuthorized, "Diversion: Not Authorized" },
++
++ { ROSE_ERROR_QSIG_InvalidMsgCentreId, "MWI: Invalid Message Center ID" },
++
++ /* DMS-100 specific errors */
++ { ROSE_ERROR_DMS100_RLT_BridgeFail, "RLT: Bridge Fail" },
++ { ROSE_ERROR_DMS100_RLT_CallIDNotFound, "RLT: Call ID Not Found" },
++ { ROSE_ERROR_DMS100_RLT_NotAllowed, "RLT: Not Allowed" },
++ { ROSE_ERROR_DMS100_RLT_SwitchEquipCongs, "RLT: Switch Equip Congs" },
++/* *INDENT-ON* */
++ };
++
++ return rose_code2str(code, arr, ARRAY_LEN(arr));
++}
++
++/*!
++ * \brief Convert the given reject problem-value to a string.
++ *
++ * \param code Reject problem-value to convert to a string.
++ *
++ * \retval String version of the given reject problem-value.
++ */
++const char *rose_reject2str(enum rose_reject_code code)
++{
++ static const struct rose_code_strings arr[] = {
++/* *INDENT-OFF* */
++ { ROSE_REJECT_None, "No reject occurred" },
++ { ROSE_REJECT_Unknown, "Unknown reject code" },
++
++ { ROSE_REJECT_Gen_UnrecognizedComponent, "General: Unrecognized Component" },
++ { ROSE_REJECT_Gen_MistypedComponent, "General: Mistyped Component" },
++ { ROSE_REJECT_Gen_BadlyStructuredComponent, "General: Badly Structured Component" },
++
++ { ROSE_REJECT_Inv_DuplicateInvocation, "Invoke: Duplicate Invocation" },
++ { ROSE_REJECT_Inv_UnrecognizedOperation, "Invoke: Unrecognized Operation" },
++ { ROSE_REJECT_Inv_MistypedArgument, "Invoke: Mistyped Argument" },
++ { ROSE_REJECT_Inv_ResourceLimitation, "Invoke: Resource Limitation" },
++ { ROSE_REJECT_Inv_InitiatorReleasing, "Invoke: Initiator Releasing" },
++ { ROSE_REJECT_Inv_UnrecognizedLinkedID, "Invoke: Unrecognized Linked ID" },
++ { ROSE_REJECT_Inv_LinkedResponseUnexpected, "Invoke: Linked Response Unexpected" },
++ { ROSE_REJECT_Inv_UnexpectedChildOperation, "Invoke: Unexpected Child Operation" },
++
++ { ROSE_REJECT_Res_UnrecognizedInvocation, "Result: Unrecognized Invocation" },
++ { ROSE_REJECT_Res_ResultResponseUnexpected, "Result: Result Response Unexpected" },
++ { ROSE_REJECT_Res_MistypedResult, "Result: Mistyped Result" },
++
++ { ROSE_REJECT_Err_UnrecognizedInvocation, "Error: Unrecognized Invocation" },
++ { ROSE_REJECT_Err_ErrorResponseUnexpected, "Error: Error Response Unexpected" },
++ { ROSE_REJECT_Err_UnrecognizedError, "Error: Unrecognized Error" },
++ { ROSE_REJECT_Err_UnexpectedError, "Error: Unexpected Error" },
++ { ROSE_REJECT_Err_MistypedParameter, "Error: Mistyped Parameter" },
++/* *INDENT-ON* */
++ };
++
++ return rose_code2str(code, arr, ARRAY_LEN(arr));
++}
++
++/*!
++ * \internal
++ * \brief Find an operation message conversion entry using the operation code.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param operation Library operation-value code.
++ *
++ * \retval Message conversion entry on success.
++ * \retval NULL on error.
++ */
++static const struct rose_convert_msg *rose_find_msg_by_op_code(struct pri *ctrl,
++ enum rose_operation operation)
++{
++ const struct rose_convert_msg *found;
++ const struct rose_convert_msg *table;
++ size_t num_entries;
++ size_t index;
++
++ /* Determine which message conversion table to use */
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_T1:
++ case PRI_SWITCH_EUROISDN_E1:
++ table = rose_etsi_msgs;
++ num_entries = ARRAY_LEN(rose_etsi_msgs);
++ break;
++ case PRI_SWITCH_QSIG:
++ table = rose_qsig_msgs;
++ num_entries = ARRAY_LEN(rose_qsig_msgs);
++ break;
++ case PRI_SWITCH_DMS100:
++ table = rose_dms100_msgs;
++ num_entries = ARRAY_LEN(rose_dms100_msgs);
++ break;
++ case PRI_SWITCH_ATT4ESS:
++ case PRI_SWITCH_LUCENT5E:
++ case PRI_SWITCH_NI2:
++ table = rose_ni2_msgs;
++ num_entries = ARRAY_LEN(rose_ni2_msgs);
++ break;
++ default:
++ return NULL;
++ }
++
++ /* Search for the table entry */
++ found = NULL;
++ for (index = 0; index < num_entries; ++index) {
++ if (table[index].operation == operation) {
++ found = &table[index];
++ break;
++ }
++ }
++
++ return found;
++}
++
++/*!
++ * \internal
++ * \brief Find an operation message conversion entry using the
++ * operation-value OID value or localValue.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param oid Search for the full OID if not NULL.
++ * \param local Search for the localValue if OID is NULL.
++ *
++ * \retval Message conversion entry on success.
++ * \retval NULL on error.
++ */
++static const struct rose_convert_msg *rose_find_msg_by_op_val(struct pri *ctrl,
++ const struct asn1_oid *oid, unsigned local)
++{
++ const struct rose_convert_msg *found;
++ const struct rose_convert_msg *table;
++ size_t num_entries;
++ size_t index;
++ int sub_index;
++
++ /* Determine which message conversion table to use */
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_T1:
++ case PRI_SWITCH_EUROISDN_E1:
++ table = rose_etsi_msgs;
++ num_entries = ARRAY_LEN(rose_etsi_msgs);
++ break;
++ case PRI_SWITCH_QSIG:
++ table = rose_qsig_msgs;
++ num_entries = ARRAY_LEN(rose_qsig_msgs);
++ break;
++ case PRI_SWITCH_DMS100:
++ table = rose_dms100_msgs;
++ num_entries = ARRAY_LEN(rose_dms100_msgs);
++ break;
++ case PRI_SWITCH_ATT4ESS:
++ case PRI_SWITCH_LUCENT5E:
++ case PRI_SWITCH_NI2:
++ table = rose_ni2_msgs;
++ num_entries = ARRAY_LEN(rose_ni2_msgs);
++ break;
++ default:
++ return NULL;
++ }
++
++ /* Search for the table entry */
++ found = NULL;
++ if (oid) {
++ /* Search for an OID entry */
++ local = oid->value[oid->num_values - 1];
++ for (index = 0; index < num_entries; ++index) {
++ if (table[index].value == local && table[index].oid_prefix
++ && table[index].oid_prefix->num_values == oid->num_values - 1) {
++ /* Now lets match the OID prefix subidentifiers */
++ for (sub_index = oid->num_values - 2; 0 <= sub_index; --sub_index) {
++ if (oid->value[sub_index]
++ != table[index].oid_prefix->value[sub_index]) {
++ break;
++ }
++ }
++ if (sub_index == -1) {
++ /* All of the OID subidentifiers matched */
++ found = &table[index];
++ break;
++ }
++ }
++ }
++ } else {
++ /* Search for a localValue entry */
++ for (index = 0; index < num_entries; ++index) {
++ if (table[index].value == local && !table[index].oid_prefix) {
++ found = &table[index];
++ break;
++ }
++ }
++ }
++
++ return found;
++}
++
++/*!
++ * \internal
++ * \brief Find an error conversion entry using the error code.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param code Library error-value code.
++ *
++ * \retval Error conversion entry on success.
++ * \retval NULL on error.
++ */
++static const struct rose_convert_error *rose_find_error_by_op_code(struct pri *ctrl,
++ enum rose_error_code code)
++{
++ const struct rose_convert_error *found;
++ const struct rose_convert_error *table;
++ size_t num_entries;
++ size_t index;
++
++ /* Determine which error conversion table to use */
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_T1:
++ case PRI_SWITCH_EUROISDN_E1:
++ table = rose_etsi_errors;
++ num_entries = ARRAY_LEN(rose_etsi_errors);
++ break;
++ case PRI_SWITCH_QSIG:
++ table = rose_qsig_errors;
++ num_entries = ARRAY_LEN(rose_qsig_errors);
++ break;
++ case PRI_SWITCH_DMS100:
++ table = rose_dms100_errors;
++ num_entries = ARRAY_LEN(rose_dms100_errors);
++ break;
++ case PRI_SWITCH_ATT4ESS:
++ case PRI_SWITCH_LUCENT5E:
++ case PRI_SWITCH_NI2:
++ table = rose_ni2_errors;
++ num_entries = ARRAY_LEN(rose_ni2_errors);
++ break;
++ default:
++ return NULL;
++ }
++
++ /* Search for the table entry */
++ found = NULL;
++ for (index = 0; index < num_entries; ++index) {
++ if (table[index].code == code) {
++ found = &table[index];
++ break;
++ }
++ }
++
++ return found;
++}
++
++/*!
++ * \internal
++ * \brief Find an error conversion entry using the
++ * error-value OID value or localValue.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param oid Search for the full OID if not NULL.
++ * \param local Search for the localValue if OID is NULL.
++ *
++ * \retval Error conversion entry on success.
++ * \retval NULL on error.
++ */
++static const struct rose_convert_error *rose_find_error_by_op_val(struct pri *ctrl,
++ const struct asn1_oid *oid, unsigned local)
++{
++ const struct rose_convert_error *found;
++ const struct rose_convert_error *table;
++ size_t num_entries;
++ size_t index;
++ int sub_index;
++
++ /* Determine which error conversion table to use */
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_T1:
++ case PRI_SWITCH_EUROISDN_E1:
++ table = rose_etsi_errors;
++ num_entries = ARRAY_LEN(rose_etsi_errors);
++ break;
++ case PRI_SWITCH_QSIG:
++ table = rose_qsig_errors;
++ num_entries = ARRAY_LEN(rose_qsig_errors);
++ break;
++ case PRI_SWITCH_DMS100:
++ table = rose_dms100_errors;
++ num_entries = ARRAY_LEN(rose_dms100_errors);
++ break;
++ case PRI_SWITCH_ATT4ESS:
++ case PRI_SWITCH_LUCENT5E:
++ case PRI_SWITCH_NI2:
++ table = rose_ni2_errors;
++ num_entries = ARRAY_LEN(rose_ni2_errors);
++ break;
++ default:
++ return NULL;
++ }
++
++ /* Search for the table entry */
++ found = NULL;
++ if (oid) {
++ /* Search for an OID entry */
++ local = oid->value[oid->num_values - 1];
++ for (index = 0; index < num_entries; ++index) {
++ if (table[index].value == local && table[index].oid_prefix
++ && table[index].oid_prefix->num_values == oid->num_values - 1) {
++ /* Now lets match the OID prefix subidentifiers */
++ for (sub_index = oid->num_values - 2; 0 <= sub_index; --sub_index) {
++ if (oid->value[sub_index]
++ != table[index].oid_prefix->value[sub_index]) {
++ break;
++ }
++ }
++ if (sub_index == -1) {
++ /* All of the OID subidentifiers matched */
++ found = &table[index];
++ break;
++ }
++ }
++ }
++ } else {
++ /* Search for a localValue entry */
++ for (index = 0; index < num_entries; ++index) {
++ if (table[index].value == local && !table[index].oid_prefix) {
++ found = &table[index];
++ break;
++ }
++ }
++ }
++
++ return found;
++}
++
++/*!
++ * \internal
++ * \brief Encode the Facility ie component operation-value.
++ *
++ * \param pos Starting position to encode the operation-value.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param oid_prefix Encode as an OID if not NULL.
++ * \param local Encode as a localValue if oid_prefix is NULL
++ * else it is the last OID subidentifier.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_operation_value(unsigned char *pos, unsigned char *end,
++ const struct asn1_oid *oid_prefix, unsigned local)
++{
++ struct asn1_oid oid;
++
++ if (oid_prefix) {
++ if (ARRAY_LEN(oid_prefix->value) <= oid_prefix->num_values) {
++ return NULL;
++ }
++ oid = *oid_prefix;
++ oid.value[oid.num_values++] = local;
++ return asn1_enc_oid(pos, end, ASN1_TYPE_OBJECT_IDENTIFIER, &oid);
++ } else {
++ return asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, local);
++ }
++}
++
++/*! \brief Mapped to rose_enc_operation_value() */
++#define rose_enc_error_value(pos, end, oid_prefix, local) \
++ rose_enc_operation_value(pos, end, oid_prefix, local)
++
++/*!
++ * \brief Encode the invoke component for a ROSE message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 message.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param msg ROSE invoke message to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_encode_invoke(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rose_msg_invoke *msg)
++{
++ const struct rose_convert_msg *convert;
++ unsigned char *seq_len;
++
++ convert = rose_find_msg_by_op_code(ctrl, msg->operation);
++ if (!convert) {
++ return NULL;
++ }
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ROSE_TAG_COMPONENT_INVOKE);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, msg->invoke_id));
++ if (msg->linked_id_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ msg->linked_id));
++ }
++ ASN1_CALL(pos, rose_enc_operation_value(pos, end, convert->oid_prefix,
++ convert->value));
++
++ if (convert->encode_invoke_args) {
++ ASN1_CALL(pos, convert->encode_invoke_args(ctrl, pos, end, &msg->args));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the result component for a ROSE message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 message.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param msg ROSE result message to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_encode_result(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rose_msg_result *msg)
++{
++ const struct rose_convert_msg *convert;
++ unsigned char *seq_len;
++ unsigned char *op_seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ROSE_TAG_COMPONENT_RESULT);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, msg->invoke_id));
++
++ if (msg->operation != ROSE_None) {
++ convert = rose_find_msg_by_op_code(ctrl, msg->operation);
++ if (!convert) {
++ return NULL;
++ }
++
++ ASN1_CONSTRUCTED_BEGIN(op_seq_len, pos, end, ASN1_TYPE_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_operation_value(pos, end, convert->oid_prefix,
++ convert->value));
++
++ if (convert->encode_result_args) {
++ ASN1_CALL(pos, convert->encode_result_args(ctrl, pos, end, &msg->args));
++ }
++
++ ASN1_CONSTRUCTED_END(op_seq_len, pos, end);
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the error component for a ROSE message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 message.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param msg ROSE error message to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_encode_error(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rose_msg_error *msg)
++{
++ const struct rose_convert_error *convert;
++ unsigned char *seq_len;
++
++ convert = rose_find_error_by_op_code(ctrl, msg->code);
++ if (!convert) {
++ return NULL;
++ }
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ROSE_TAG_COMPONENT_ERROR);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, msg->invoke_id));
++ ASN1_CALL(pos, rose_enc_error_value(pos, end, convert->oid_prefix, convert->value));
++ if (convert->encode_error_args) {
++ ASN1_CALL(pos, convert->encode_error_args(ctrl, pos, end, &msg->args));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the reject component for a ROSE message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 message.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param msg ROSE reject message to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_encode_reject(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rose_msg_reject *msg)
++{
++ unsigned char *seq_len;
++ unsigned tag;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ROSE_TAG_COMPONENT_REJECT);
++
++ /* Encode Invoke ID */
++ if (msg->invoke_id_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, msg->invoke_id));
++ } else {
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ }
++
++ /* Encode the reject problem */
++ switch (msg->code & ~0xFF) {
++ case ROSE_REJECT_BASE(ROSE_REJECT_BASE_General):
++ tag = ASN1_CLASS_CONTEXT_SPECIFIC | 0;
++ break;
++ case ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke):
++ tag = ASN1_CLASS_CONTEXT_SPECIFIC | 1;
++ break;
++ case ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result):
++ tag = ASN1_CLASS_CONTEXT_SPECIFIC | 2;
++ break;
++ case ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error):
++ tag = ASN1_CLASS_CONTEXT_SPECIFIC | 3;
++ break;
++ default:
++ return NULL;
++ }
++ ASN1_CALL(pos, asn1_enc_int(pos, end, tag, msg->code & 0xFF));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the ROSE message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 message.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param msg ROSE message to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ *
++ * \note This function only encodes the ROSE contents. It does not include
++ * the protocol profile, NFE, NPP, and interpretation octets defined in
++ * a facility ie that may precede the ROSE contents. These header octets
++ * may already be stored in the encompassing buffer before the starting
++ * position given here.
++ */
++unsigned char *rose_encode(struct pri *ctrl, unsigned char *pos, unsigned char *end,
++ const struct rose_message *msg)
++{
++ switch (msg->type) {
++ case ROSE_COMP_TYPE_INVOKE:
++ pos = rose_encode_invoke(ctrl, pos, end, &msg->component.invoke);
++ break;
++ case ROSE_COMP_TYPE_RESULT:
++ pos = rose_encode_result(ctrl, pos, end, &msg->component.result);
++ break;
++ case ROSE_COMP_TYPE_ERROR:
++ pos = rose_encode_error(ctrl, pos, end, &msg->component.error);
++ break;
++ case ROSE_COMP_TYPE_REJECT:
++ pos = rose_encode_reject(ctrl, pos, end, &msg->component.reject);
++ break;
++ default:
++ pos = NULL;
++ break;
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the NetworkFacilityExtension type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param nfe Network Facility Extension information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *fac_enc_nfe(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct facNetworkFacilityExtension *nfe)
++{
++ unsigned char *seq_len;
++ unsigned char *explicit_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 10);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ nfe->source_entity));
++ if (nfe->source_number.length) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &nfe->source_number));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ nfe->destination_entity));
++ if (nfe->destination_number.length) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &nfe->destination_number));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the facility extension header.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param header Facility extension information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *fac_enc_extension_header(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct fac_extension_header *header)
++{
++ if (header->nfe_present) {
++ ASN1_CALL(pos, fac_enc_nfe(ctrl, pos, end, &header->nfe));
++ }
++ if (header->npp_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 18,
++ header->npp));
++ }
++ if (header->interpretation_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 11,
++ header->interpretation));
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the facility ie contents header.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode the facility ie contents.
++ * \param end End of facility ie contents encoding data buffer.
++ * \param header Facility extension header data to encode (NULL if none).
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *facility_encode_header(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct fac_extension_header *header)
++{
++ /* Make sure we have some room. */
++ if (end < pos + 2) {
++ return NULL;
++ }
++
++ switch (ctrl->switchtype) {
++ case PRI_SWITCH_EUROISDN_T1:
++ case PRI_SWITCH_EUROISDN_E1:
++ *pos++ = 0x80 | Q932_PROTOCOL_ROSE;
++ header = NULL;
++ break;
++ case PRI_SWITCH_QSIG:
++ *pos++ = 0x80 | Q932_PROTOCOL_EXTENSIONS;
++ break;
++ case PRI_SWITCH_DMS100:
++ *pos++ = Q932_PROTOCOL_ROSE; /* DON'T set the EXT bit yet. */
++ *pos++ = 0x80 | ROSE_DMS100_RLT_SERVICE_ID;
++ header = NULL;
++ break;
++ case PRI_SWITCH_ATT4ESS:
++ case PRI_SWITCH_LUCENT5E:
++ case PRI_SWITCH_NI2:
++ if (header) {
++ *pos++ = 0x80 | Q932_PROTOCOL_EXTENSIONS;
++ } else {
++ *pos++ = 0x80 | Q932_PROTOCOL_ROSE;
++ }
++ break;
++ default:
++ return NULL;
++ }
++
++ if (header) {
++ ASN1_CALL(pos, fac_enc_extension_header(ctrl, pos, end, header));
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the ROSE invoke message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param msg ROSE invoke message data to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_decode_invoke(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct rose_msg_invoke *msg)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const struct rose_convert_msg *convert;
++ struct asn1_oid oid;
++ unsigned local;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "INVOKE Component %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "invokeId", tag, pos, seq_end, &value));
++ msg->invoke_id = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | 0)) {
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "linkedId", tag, pos, seq_end, &value));
++ msg->linked_id = value;
++ msg->linked_id_present = 1;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ } else {
++ msg->linked_id_present = 0;
++ }
++
++ /* Decode operation-value */
++ switch (tag) {
++ case ASN1_TYPE_INTEGER:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "operationValue", tag, pos, seq_end, &value));
++ local = value;
++ oid.num_values = 0;
++ break;
++ case ASN1_TYPE_OBJECT_IDENTIFIER:
++ ASN1_CALL(pos, asn1_dec_oid(ctrl, "operationValue", tag, pos, seq_end, &oid));
++ local = 0;
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++ convert = rose_find_msg_by_op_val(ctrl, (oid.num_values == 0) ? NULL : &oid, local);
++ if (convert) {
++ msg->operation = convert->operation;
++ } else {
++ msg->operation = ROSE_Unknown;
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " operationValue = %s\n", rose_operation2str(msg->operation));
++ }
++
++ /* Decode any expected invoke arguments */
++ if (convert && convert->decode_invoke_args) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, convert->decode_invoke_args(ctrl, tag, pos, seq_end, &msg->args));
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the ROSE result message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param msg ROSE result message data to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_decode_result(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct rose_msg_result *msg)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ int op_seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *op_seq_end;
++ const struct rose_convert_msg *convert;
++ struct asn1_oid oid;
++ unsigned local;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "RESULT Component %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "invokeId", tag, pos, seq_end, &value));
++ msg->invoke_id = value;
++
++ /* Decode optional operation sequence */
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " operation %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(op_seq_end, op_seq_offset, length, pos, seq_end);
++
++ /* Decode operation-value */
++ ASN1_CALL(pos, asn1_dec_tag(pos, op_seq_end, &tag));
++ switch (tag) {
++ case ASN1_TYPE_INTEGER:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "operationValue", tag, pos, op_seq_end,
++ &value));
++ local = value;
++ oid.num_values = 0;
++ break;
++ case ASN1_TYPE_OBJECT_IDENTIFIER:
++ ASN1_CALL(pos, asn1_dec_oid(ctrl, "operationValue", tag, pos, op_seq_end,
++ &oid));
++ local = 0;
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++ convert =
++ rose_find_msg_by_op_val(ctrl, (oid.num_values == 0) ? NULL : &oid, local);
++ if (convert) {
++ msg->operation = convert->operation;
++ } else {
++ msg->operation = ROSE_Unknown;
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " operationValue = %s\n",
++ rose_operation2str(msg->operation));
++ }
++
++ /* Decode any expected result arguments */
++ if (convert && convert->decode_result_args) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, op_seq_end, &tag));
++ ASN1_CALL(pos, convert->decode_result_args(ctrl, tag, pos, op_seq_end,
++ &msg->args));
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, op_seq_offset, op_seq_end, seq_end);
++ } else {
++ msg->operation = ROSE_None;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the ROSE error message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param msg ROSE error message data to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_decode_error(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct rose_msg_error *msg)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const struct rose_convert_error *convert;
++ struct asn1_oid oid;
++ unsigned local;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "ERROR Component %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "invokeId", tag, pos, seq_end, &value));
++ msg->invoke_id = value;
++
++ /* Decode error-value */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_TYPE_INTEGER:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "errorValue", tag, pos, seq_end, &value));
++ local = value;
++ oid.num_values = 0;
++ break;
++ case ASN1_TYPE_OBJECT_IDENTIFIER:
++ ASN1_CALL(pos, asn1_dec_oid(ctrl, "errorValue", tag, pos, seq_end, &oid));
++ local = 0;
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++ convert =
++ rose_find_error_by_op_val(ctrl, (oid.num_values == 0) ? NULL : &oid, local);
++ if (convert) {
++ msg->code = convert->code;
++ } else {
++ msg->code = ROSE_ERROR_Unknown;
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " errorValue = %s\n", rose_error2str(msg->code));
++ }
++
++ /* Decode any expected error parameters */
++ if (convert && convert->decode_error_args) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, convert->decode_error_args(ctrl, tag, pos, seq_end, &msg->args));
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the ROSE reject message.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param msg ROSE reject message data to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_decode_reject(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct rose_msg_reject *msg)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, "REJECT Component %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ /* Invoke ID choice */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_TYPE_INTEGER:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "invokeId", tag, pos, seq_end, &value));
++ msg->invoke_id = value;
++ msg->invoke_id_present = 1;
++ break;
++ case ASN1_TYPE_NULL:
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "invokeId", tag, pos, seq_end));
++ msg->invoke_id_present = 0;
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ /* Problem choice */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "problemGeneral", tag, pos, seq_end, &value));
++ msg->code = ROSE_REJECT_BASE(ROSE_REJECT_BASE_General) | (value & 0xFF);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "problemInvoke", tag, pos, seq_end, &value));
++ msg->code = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) | (value & 0xFF);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "problemResult", tag, pos, seq_end, &value));
++ msg->code = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result) | (value & 0xFF);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "problemError", tag, pos, seq_end, &value));
++ msg->code = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) | (value & 0xFF);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " problem = %s\n", rose_reject2str(msg->code));
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the ROSE message into the given buffer.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position of the ASN.1 component.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param msg Decoded ROSE message contents.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ *
++ * \note This function only decodes the ROSE contents. It does not check
++ * for the protocol profile, NFE, NPP, and interpretation octets defined in
++ * a facility ie that may preceed the ROSE contents. These header octets
++ * may already have been consumed from the encompasing buffer before the
++ * buffer given here.
++ */
++const unsigned char *rose_decode(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end, struct rose_message *msg)
++{
++ unsigned tag;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag));
++ switch (tag) {
++ case ROSE_TAG_COMPONENT_INVOKE:
++ msg->type = ROSE_COMP_TYPE_INVOKE;
++ ASN1_CALL(pos, rose_decode_invoke(ctrl, tag, pos, end, &msg->component.invoke));
++ break;
++ case ROSE_TAG_COMPONENT_RESULT:
++ msg->type = ROSE_COMP_TYPE_RESULT;
++ ASN1_CALL(pos, rose_decode_result(ctrl, tag, pos, end, &msg->component.result));
++ break;
++ case ROSE_TAG_COMPONENT_ERROR:
++ msg->type = ROSE_COMP_TYPE_ERROR;
++ ASN1_CALL(pos, rose_decode_error(ctrl, tag, pos, end, &msg->component.error));
++ break;
++ case ROSE_TAG_COMPONENT_REJECT:
++ msg->type = ROSE_COMP_TYPE_REJECT;
++ ASN1_CALL(pos, rose_decode_reject(ctrl, tag, pos, end, &msg->component.reject));
++ break;
++ default:
++ msg->type = ROSE_COMP_TYPE_INVALID;
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ if (pos < end) {
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %u byte(s) of trailing data not consumed.\n",
++ (unsigned) (end - pos));
++ }
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the NetworkFacilityExtension argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param nfe Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *fac_dec_nfe(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end,
++ struct facNetworkFacilityExtension *nfe)
++{
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *seq_end;
++ const unsigned char *explicit_end;
++ const unsigned char *save_pos;
++ int32_t value;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s NetworkFacilityExtension %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 0);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "sourceEntity", tag, pos, seq_end, &value));
++ nfe->source_entity = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1)) {
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "sourceEntityAddress", tag, pos,
++ seq_end, &nfe->source_number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ } else {
++ nfe->source_number.length = 0;
++ }
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "destinationEntity", tag, pos, seq_end, &value));
++ nfe->destination_entity = value;
++
++ nfe->destination_number.length = 0;
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3)) {
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "destinationEntityAddress", tag,
++ pos, seq_end, &nfe->destination_number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ } else {
++ pos = save_pos;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the extension header argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param pos Starting position of the ASN.1 component.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param header Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *fac_dec_extension_header(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end, struct fac_extension_header *header)
++{
++ int32_t value;
++ unsigned tag;
++ const unsigned char *save_pos;
++
++ /*
++ * For simplicity we are not checking the order of
++ * the optional header components.
++ */
++ header->nfe_present = 0;
++ header->npp_present = 0;
++ header->interpretation_present = 0;
++ while (pos < end) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 10:
++ ASN1_CALL(pos, fac_dec_nfe(ctrl, "nfe", tag, pos, end, &header->nfe));
++ header->nfe_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 18:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "networkProtocolProfile", tag, pos, end,
++ &value));
++ header->npp = value;
++ header->npp_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 11:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "interpretation", tag, pos, end, &value));
++ header->interpretation = value;
++ header->interpretation_present = 1;
++ break;
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the facility ie contents header.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param pos Starting position of the facility ie contents.
++ * \param end End of facility ie contents.
++ * \param header Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success (ROSE message).
++ * \retval NULL on error.
++ */
++const unsigned char *facility_decode_header(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end, struct fac_extension_header *header)
++{
++ /* Make sure we have enough room for the protocol profile ie octet(s) */
++ if (end < pos + 2) {
++ return NULL;
++ }
++ switch (*pos & Q932_PROTOCOL_MASK) {
++ case Q932_PROTOCOL_ROSE:
++ case Q932_PROTOCOL_EXTENSIONS:
++ break;
++ default:
++ return NULL;
++ }
++ if (!(*pos & 0x80)) {
++ /* DMS-100 Service indicator octet - Just ignore for now */
++ ++pos;
++ }
++ ++pos;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ asn1_dump(ctrl, pos, end);
++ }
++
++ pos = fac_dec_extension_header(ctrl, pos, end, header);
++ return pos;
++}
++
++/*!
++ * \brief Decode the facility ie contents for debug purposes.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param buf Buffer containing the facility ie contents.
++ * \param length Length of facility ie contents.
++ *
++ * \return Nothing
++ *
++ * \note Should only be called if PRI_DEBUG_APDU is enabled. Otherwise,
++ * it it does nothing useful.
++ */
++void facility_decode_dump(struct pri *ctrl, const unsigned char *buf, size_t length)
++{
++ const unsigned char *pos;
++ const unsigned char *end;
++ union {
++ struct fac_extension_header header;
++ struct rose_message rose;
++ } discard;
++
++ end = buf + length;
++ pos = facility_decode_header(ctrl, buf, end, &discard.header);
++ while (pos && pos < end) {
++ pos = rose_decode(ctrl, pos, end, &discard.rose);
++ }
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose.c */
+
+Property changes on: rose.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_other.c
+===================================================================
+--- a/rose_other.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_other.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,277 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief Switch type operations for: NI2, 4ESS, 5ESS, DMS-100
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \brief Encode the DMS-100 RLT_OperationInd result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args)
++{
++ return asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ args->dms100.RLT_OperationInd.call_id);
++}
++
++/*!
++ * \brief Encode the DMS-100 RLT_ThirdParty invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseDms100RLTThirdParty_ARG *rlt_thirdparty;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ rlt_thirdparty = &args->dms100.RLT_ThirdParty;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ rlt_thirdparty->call_id));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ rlt_thirdparty->reason));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the DMS-100 RLT_OperationInd result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args)
++{
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 0);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "callId", tag, pos, end, &value));
++ args->dms100.RLT_OperationInd.call_id = value;
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the DMS-100 RLT_ThirdParty invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseDms100RLTThirdParty_ARG *rlt_third_party;
++
++ rlt_third_party = &args->dms100.RLT_ThirdParty;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " RLT_ThirdParty %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 0);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "callId", tag, pos, seq_end, &value));
++ rlt_third_party->call_id = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "reason", tag, pos, seq_end, &value));
++ rlt_third_party->reason = value;
++
++ /* Fixup will skip over any OPTIONAL information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the NI2 InformationFollowing invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_ni2_InformationFollowing_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ /* Encode the unknown enumeration value. */
++ return asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ args->ni2.InformationFollowing.value);
++}
++
++/*!
++ * \brief Encode the NI2 InitiateTransfer invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseNi2InitiateTransfer_ARG *initiate_transfer;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ initiate_transfer = &args->ni2.InitiateTransfer;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ initiate_transfer->call_reference));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the NI2 InformationFollowing invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_ni2_InformationFollowing_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "unknown", tag, pos, end, &value));
++ args->ni2.InformationFollowing.value = value;
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the NI2 InitiateTransfer invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseNi2InitiateTransfer_ARG *initiate_transfer;
++
++ initiate_transfer = &args->ni2.InitiateTransfer;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " InitiateTransfer %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "callReference", tag, pos, seq_end, &value));
++ initiate_transfer->call_reference = value;
++
++ /* Fixup will skip over any OPTIONAL information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_other.c */
+
+Property changes on: rose_other.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: pri_q931.h
+===================================================================
+--- a/pri_q931.h (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_q931.h (.../branches/1.4) (revision 1357)
+@@ -30,44 +30,6 @@
+ #ifndef _PRI_Q931_H
+ #define _PRI_Q931_H
+
+-typedef enum q931_state {
+- /* User states */
+- U0_NULL_STATE,
+- U1_CALL_INITIATED,
+- U2_OVERLAP_SENDING,
+- U3_OUTGOING_CALL_PROCEEDING,
+- U4_CALL_DELIVERED,
+- U6_CALL_PRESENT,
+- U7_CALL_RECEIVED,
+- U8_CONNECT_REQUEST,
+- U9_INCOMING_CALL_PROCEEDING,
+- U10_ACTIVE,
+- U11_DISCONNECT_REQUEST,
+- U12_DISCONNECT_INDICATION,
+- U15_SUSPEND_REQUEST,
+- U17_RESUME_REQUEST,
+- U19_RELEASE_REQUEST,
+- U25_OVERLAP_RECEIVING,
+- /* Network states */
+- N0_NULL_STATE,
+- N1_CALL_INITIATED,
+- N2_OVERLAP_SENDING,
+- N3_OUTGOING_CALL_PROCEEDING,
+- N4_CALL_DELIVERED,
+- N6_CALL_PRESENT,
+- N7_CALL_RECEIVED,
+- N8_CONNECT_REQUEST,
+- N9_INCOMING_CALL_PROCEEDING,
+- N10_ACTIVE,
+- N11_DISCONNECT_REQUEST,
+- N12_DISCONNECT_INDICATION,
+- N15_SUSPEND_REQUEST,
+- N17_RESUME_REQUEST,
+- N19_RELEASE_REQUEST,
+- N22_CALL_ABORT,
+- N25_OVERLAP_RECEIVING
+-} q931_state;
+-
+ typedef enum q931_mode {
+ UNKNOWN_MODE,
+ CIRCUIT_MODE,
+@@ -79,13 +41,13 @@
+ u_int8_t pd; /* Protocol Discriminator */
+ #if __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t x0:4;
+- u_int8_t crlen:4;
++ u_int8_t crlen:4;/*!< Call reference length */
+ #else
+- u_int8_t crlen:4;
++ u_int8_t crlen:4;/*!< Call reference length */
+ u_int8_t x0:4;
+ #endif
+ u_int8_t contents[0];
+- u_int8_t crv[3];
++ u_int8_t crv[3];/*!< Call reference value */
+ } __attribute__ ((packed)) q931_h;
+
+
+@@ -113,6 +75,10 @@
+
+ #define Q931_PROTOCOL_DISCRIMINATOR 0x08
+ #define GR303_PROTOCOL_DISCRIMINATOR 0x4f
++/* AT&T Maintenance Protocol Discriminator */
++#define MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 0x03
++/* National Maintenance Protocol Discriminator */
++#define MAINTENANCE_PROTOCOL_DISCRIMINATOR_2 0x43
+
+ /* Q.931 / National ISDN Message Types */
+
+@@ -157,9 +123,17 @@
+ #define Q931_SUSPEND_REJECT 0x21
+
+ /* Maintenance messages (codeset 0 only) */
+-#define NATIONAL_SERVICE 0x0f
+-#define NATIONAL_SERVICE_ACKNOWLEDGE 0x07
++#define ATT_SERVICE 0x0f
++#define ATT_SERVICE_ACKNOWLEDGE 0x07
++#define NATIONAL_SERVICE 0x07
++#define NATIONAL_SERVICE_ACKNOWLEDGE 0x0f
+
++#define SERVICE_CHANGE_STATUS_INSERVICE 0
++#define SERVICE_CHANGE_STATUS_LOOPBACK 1 /* not supported */
++#define SERVICE_CHANGE_STATUS_OUTOFSERVICE 2
++#define SERVICE_CHANGE_STATUS_REQCONTINUITYCHECK 3 /* not supported */
++#define SERVICE_CHANGE_STATUS_SHUTDOWN 4 /* not supported */
++
+ /* Special codeset 0 IE */
+ #define NATIONAL_CHANGE_STATUS 0x1
+
+@@ -168,10 +142,11 @@
+ #define Q931_NON_LOCKING_SHIFT 0x98
+ #define Q931_BEARER_CAPABILITY 0x04
+ #define Q931_CAUSE 0x08
+-#define Q931_CALL_STATE 0x14
++#define Q931_IE_CALL_STATE 0x14
+ #define Q931_CHANNEL_IDENT 0x18
+ #define Q931_PROGRESS_INDICATOR 0x1e
+ #define Q931_NETWORK_SPEC_FAC 0x20
++#define Q931_CALLING_PARTY_CATEGORY (0x32 | Q931_CODESET(5))
+ #define Q931_INFORMATION_RATE 0x40
+ #define Q931_TRANSIT_DELAY 0x42
+ #define Q931_TRANS_DELAY_SELECT 0x43
+@@ -200,8 +175,9 @@
+ #define Q931_IE_SEGMENTED_MSG 0x00
+ #define Q931_IE_CHANGE_STATUS 0x01
+ #define Q931_IE_ORIGINATING_LINE_INFO (0x01 | Q931_CODESET(6))
+-#define Q931_IE_CONNECTED_ADDR 0x0C
+-#define Q931_IE_CONNECTED_NUM 0x4C
++#define Q931_IE_CONNECTED_ADDR 0x0c
++#define Q931_IE_CONNECTED_NUM 0x4c
++#define Q931_IE_CONNECTED_SUBADDR 0x4d
+ #define Q931_IE_CALL_IDENTITY 0x10
+ #define Q931_IE_FACILITY 0x1c
+ #define Q931_IE_ENDPOINT_ID 0x26
+@@ -224,31 +200,255 @@
+ #define Q931_IE_ESCAPE_FOR_EXT 0x7F
+
+
+-/* Call state stuff */
+-#define Q931_CALL_STATE_NULL 0
+-#define Q931_CALL_STATE_CALL_INITIATED 1
+-#define Q931_CALL_STATE_OVERLAP_SENDING 2
+-#define Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING 3
+-#define Q931_CALL_STATE_CALL_DELIVERED 4
+-#define Q931_CALL_STATE_CALL_PRESENT 6
+-#define Q931_CALL_STATE_CALL_RECEIVED 7
+-#define Q931_CALL_STATE_CONNECT_REQUEST 8
+-#define Q931_CALL_STATE_INCOMING_CALL_PROCEEDING 9
+-#define Q931_CALL_STATE_ACTIVE 10
+-#define Q931_CALL_STATE_DISCONNECT_REQUEST 11
+-#define Q931_CALL_STATE_DISCONNECT_INDICATION 12
+-#define Q931_CALL_STATE_SUSPEND_REQUEST 15
+-#define Q931_CALL_STATE_RESUME_REQUEST 17
+-#define Q931_CALL_STATE_RELEASE_REQUEST 19
+-#define Q931_CALL_STATE_OVERLAP_RECEIVING 25
+-#define Q931_CALL_STATE_RESTART_REQUEST 61
+-#define Q931_CALL_STATE_RESTART 62
++/*! Q.931 call states */
++enum Q931_CALL_STATE {
++ /*!
++ * \details
++ * null state (U0):
++ * No call exists.
++ * \details
++ * null state (N0):
++ * No call exists.
++ */
++ Q931_CALL_STATE_NULL = 0,
++ /*!
++ * \details
++ * call initiated (U1):
++ * This state exists for an outgoing call, when the user requests
++ * call establishment from the network.
++ * \details
++ * call initiated (N1):
++ * This state exists for an outgoing call when the network has received
++ * a call establishment request but has not yet responded.
++ */
++ Q931_CALL_STATE_CALL_INITIATED = 1,
++ /*!
++ * \details
++ * overlap sending (U2):
++ * This state exists for an outgoing call when the user has
++ * received acknowledgement of the call establishment request which
++ * permits the user to send additional call information to the network
++ * in overlap mode.
++ * \details
++ * overlap sending (N2):
++ * This state exists for an outgoing call when the network has acknowledged
++ * the call establishment request and is prepared to receive additional
++ * call information (if any) in overlap mode.
++ */
++ Q931_CALL_STATE_OVERLAP_SENDING = 2,
++ /*!
++ * \details
++ * outgoing call proceeding (U3):
++ * This state exists for an outgoing call when the user has
++ * received acknowledgement that the network has received all
++ * call information necessary to effect call establishment.
++ * \details
++ * outgoing call proceeding (N3):
++ * This state exists for an outgoing call when the network has sent
++ * acknowledgement that the network has received all call information
++ * necessary to effect call establishment.
++ */
++ Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING = 3,
++ /*!
++ * \details
++ * call delivered (U4):
++ * This state exists for an outgoing call when the calling user has
++ * received an indication that remote user alerting has been initiated.
++ * \details
++ * call delivered (N4):
++ * This state exists for an outgoing call when the network has indicated
++ * that remote user alerting has been initiated.
++ */
++ Q931_CALL_STATE_CALL_DELIVERED = 4,
++ /*!
++ * \details
++ * call present (U6):
++ * This state exists for an incoming call when the user has received a
++ * call establishment request but has not yet responded.
++ * \details
++ * call present (N6):
++ * This state exists for an incoming call when the network has sent a
++ * call establishment request but has not yet received a satisfactory
++ * response.
++ */
++ Q931_CALL_STATE_CALL_PRESENT = 6,
++ /*!
++ * \details
++ * call received (U7):
++ * This state exists for an incoming call when the user has indicated
++ * alerting but has not yet answered.
++ * \details
++ * call received (N7):
++ * This state exists for an incoming call when the network has received
++ * an indication that the user is alerting but has not yet received an
++ * answer.
++ */
++ Q931_CALL_STATE_CALL_RECEIVED = 7,
++ /*!
++ * \details
++ * connect request (U8):
++ * This state exists for an incoming call when the user has answered
++ * the call and is waiting to be awarded the call.
++ * \details
++ * connect request (N8):
++ * This state exists for an incoming call when the network has received
++ * an answer but the network has not yet awarded the call.
++ */
++ Q931_CALL_STATE_CONNECT_REQUEST = 8,
++ /*!
++ * \details
++ * incoming call proceeding (U9):
++ * This state exists for an incoming call when the user has sent
++ * acknowledgement that the user has received all call information
++ * necessary to effect call establishment.
++ * \details
++ * incoming call proceeding (N9):
++ * This state exists for an incoming call when the network has received
++ * acknowledgement that the user has received all call information
++ * necessary to effect call establishment.
++ */
++ Q931_CALL_STATE_INCOMING_CALL_PROCEEDING = 9,
++ /*!
++ * \details
++ * active (U10):
++ * This state exists for an incoming call when the user has received
++ * an acknowledgement from the network that the user has been awarded
++ * the call. This state exists for an outgoing call when the user has
++ * received an indication that the remote user has answered the call.
++ * \details
++ * active (N10):
++ * This state exists for an incoming call when the network has awarded
++ * the call to the called user. This state exists for an outgoing call
++ * when the network has indicated that the remote user has answered
++ * the call.
++ */
++ Q931_CALL_STATE_ACTIVE = 10,
++ /*!
++ * \details
++ * disconnect request (U11):
++ * This state exists when the user has requested the network to clear
++ * the end-to-end connection (if any) and is waiting for a response.
++ * \details
++ * disconnect request (N11):
++ * This state exists when the network has received a request from the
++ * user to clear the end-to-end connection (if any).
++ */
++ Q931_CALL_STATE_DISCONNECT_REQUEST = 11,
++ /*!
++ * \details
++ * disconnect indication (U12):
++ * This state exists when the user has received an invitation to
++ * disconnect because the network has disconnected the end-to-end
++ * connection (if any).
++ * \details
++ * disconnect indication (N12):
++ * This state exists when the network has disconnected the end-to-end
++ * connection (if any) and has sent an invitation to disconnect the
++ * user-network connection.
++ */
++ Q931_CALL_STATE_DISCONNECT_INDICATION = 12,
++ /*!
++ * \details
++ * suspend request (U15):
++ * This state exists when the user has requested the network to suspend
++ * the call and is waiting for a response.
++ * \details
++ * suspend request (N15):
++ * This state exists when the network has received a request to suspend
++ * the call but has not yet responded.
++ */
++ Q931_CALL_STATE_SUSPEND_REQUEST = 15,
++ /*!
++ * \details
++ * resume request (U17):
++ * This state exists when the user has requested the network to resume
++ * a previously suspended call and is waiting for a response.
++ * \details
++ * resume request (N17):
++ * This state exists when the network has received a request to resume
++ * a previously suspended call but has not yet responded.
++ */
++ Q931_CALL_STATE_RESUME_REQUEST = 17,
++ /*!
++ * \details
++ * release request (U19):
++ * This state exists when the user has requested the network to release
++ * and is waiting for a response.
++ * \details
++ * release request (N19):
++ * This state exists when the network has requested the user to release
++ * and is waiting for a response.
++ */
++ Q931_CALL_STATE_RELEASE_REQUEST = 19,
++ /*!
++ * \details
++ * call abort (N22):
++ * This state exists for an incoming call for the point-to-multipoint
++ * configuration when the call is being cleared before any user has been
++ * awarded the call.
++ */
++ Q931_CALL_STATE_CALL_ABORT = 22,
++ /*!
++ * \details
++ * overlap receiving (U25):
++ * This state exists for an incoming call when the user has acknowledged
++ * the call establishment request from the network and is prepared to
++ * receive additional call information (if any) in overlap mode.
++ * \details
++ * overlap receiving (N25):
++ * This state exists for an incoming call when the network has received
++ * acknowledgement of the call establishment request which permits the
++ * network to send additional call information (if any) in the overlap
++ * mode.
++ */
++ Q931_CALL_STATE_OVERLAP_RECEIVING = 25,
++ /*!
++ * \details
++ * call independent service (U31): (From Q.932)
++ * This state exists when a call independent supplementary service
++ * signalling connection is established.
++ * \details
++ * call independent service (N31): (From Q.932)
++ * This state exists when a call independent supplementary service
++ * signalling connection is established.
++ */
++ Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE = 31,
++ Q931_CALL_STATE_RESTART_REQUEST = 61,
++ Q931_CALL_STATE_RESTART = 62,
++ /*!
++ * \details
++ * Call state has not been set.
++ * Call state does not exist.
++ * Call state not initialized.
++ * Call state internal use only.
++ */
++ Q931_CALL_STATE_NOT_SET = 0xFF,
++};
+
++/*! Q.931 call establishment state ranking for competing calls in PTMP NT mode. */
++enum Q931_RANKED_CALL_STATE {
++ /*! Call is present but has no response yet. */
++ Q931_RANKED_CALL_STATE_PRESENT,
++ /*! Call is collecting digits. */
++ Q931_RANKED_CALL_STATE_OVERLAP,
++ /*! Call routing is happening. */
++ Q931_RANKED_CALL_STATE_PROCEEDING,
++ /*! Called party is being alerted of the call. */
++ Q931_RANKED_CALL_STATE_ALERTING,
++ /*! Call is connected. A winner has been declared. */
++ Q931_RANKED_CALL_STATE_CONNECT,
++ /*! Call is in some non-call establishment state (likely disconnecting). */
++ Q931_RANKED_CALL_STATE_OTHER,
++};
+
+ /* EuroISDN */
+ #define Q931_SENDING_COMPLETE 0xa1
+
++extern int maintenance_service(struct pri *pri, int span, int channel, int changestatus);
+
++extern int maintenance_service_ack(struct pri *pri, q931_call *call);
++
++
+ /* Q.SIG specific */
+ #define QSIG_IE_TRANSIT_COUNT 0x31
+
+@@ -268,7 +468,7 @@
+
+ extern int q931_information(struct pri *pri, q931_call *call, char digit);
+
+-extern int q931_keypad_facility(struct pri *pri, q931_call *call, char *digits);
++extern int q931_keypad_facility(struct pri *pri, q931_call *call, const char *digits);
+
+ extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn);
+
+@@ -291,8 +491,16 @@
+ extern int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req);
+ extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx);
+
+-extern void __q931_destroycall(struct pri *pri, q931_call *c);
++void q931_destroycall(struct pri *pri, q931_call *c);
+
+ extern void q931_dl_indication(struct pri *pri, int event);
+
++int q931_send_hold(struct pri *ctrl, struct q931_call *call);
++int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call);
++int q931_send_hold_rej(struct pri *ctrl, struct q931_call *call, int cause);
++
++int q931_send_retrieve(struct pri *ctrl, struct q931_call *call, int channel);
++int q931_send_retrieve_ack(struct pri *ctrl, struct q931_call *call, int channel);
++int q931_send_retrieve_rej(struct pri *ctrl, struct q931_call *call, int cause);
++
+ #endif
+Index: rose_qsig_diversion.c
+===================================================================
+--- a/rose_qsig_diversion.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_qsig_diversion.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,1390 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief Q.SIG ROSE Call-Diversion-Operations
++ *
++ * Call-Diversion-Operations ECMA-174 Annex F Table F.1
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Encode the IntResult type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param int_result Forwarding record information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_IntResult(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseQsigForwardingRecord *int_result)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &int_result->served_user_number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ int_result->basic_service));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, int_result->procedure));
++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &int_result->diverted_to));
++ if (int_result->remote_enabled) {
++ /* Not the DEFAULT value */
++ ASN1_CALL(pos, asn1_enc_boolean(pos, end, ASN1_TYPE_BOOLEAN,
++ int_result->remote_enabled));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the IntResultList type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SET unless the caller implicitly
++ * tags it otherwise.
++ * \param int_result_list Forwarding record list information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_IntResultList(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag,
++ const struct roseQsigForwardingList *int_result_list)
++{
++ unsigned index;
++ unsigned char *set_len;
++
++ ASN1_CONSTRUCTED_BEGIN(set_len, pos, end, tag);
++
++ for (index = 0; index < int_result_list->num_records; ++index) {
++ ASN1_CALL(pos, rose_enc_qsig_IntResult(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &int_result_list->list[index]));
++ }
++
++ ASN1_CONSTRUCTED_END(set_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the ActivateDiversionQ invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigActivateDiversionQ_ARG *activate_diversion_q;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ activate_diversion_q = &args->qsig.ActivateDiversionQ;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ activate_diversion_q->procedure));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ activate_diversion_q->basic_service));
++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &activate_diversion_q->diverted_to));
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &activate_diversion_q->served_user_number));
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &activate_diversion_q->activating_user_number));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the DeactivateDiversionQ invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigDeactivateDiversionQ_ARG *deactivate_diversion_q;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ deactivate_diversion_q = &args->qsig.DeactivateDiversionQ;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ deactivate_diversion_q->procedure));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ deactivate_diversion_q->basic_service));
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &deactivate_diversion_q->served_user_number));
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &deactivate_diversion_q->deactivating_user_number));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the InterrogateDiversionQ invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigInterrogateDiversionQ_ARG *interrogate_diversion_q;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ interrogate_diversion_q = &args->qsig.InterrogateDiversionQ;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ interrogate_diversion_q->procedure));
++ if (interrogate_diversion_q->basic_service) {
++ /* Not the DEFAULT value */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ interrogate_diversion_q->basic_service));
++ }
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &interrogate_diversion_q->served_user_number));
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &interrogate_diversion_q->interrogating_user_number));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the InterrogateDiversionQ result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_InterrogateDiversionQ_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args)
++{
++ return rose_enc_qsig_IntResultList(ctrl, pos, end, ASN1_TAG_SET,
++ &args->qsig.InterrogateDiversionQ);
++}
++
++/*!
++ * \brief Encode the CheckRestriction invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigCheckRestriction_ARG *check_restriction;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ check_restriction = &args->qsig.CheckRestriction;
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &check_restriction->served_user_number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ check_restriction->basic_service));
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &check_restriction->diverted_to_number));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the CallRerouting invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigCallRerouting_ARG *call_rerouting;
++ unsigned char *seq_len;
++ unsigned char *exp_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ call_rerouting = &args->qsig.CallRerouting;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ call_rerouting->rerouting_reason));
++ if (call_rerouting->original_rerouting_reason_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ call_rerouting->original_rerouting_reason));
++ }
++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &call_rerouting->called));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ call_rerouting->diversion_counter));
++ ASN1_CALL(pos, rose_enc_Q931ie(ctrl, pos, end, ASN1_CLASS_APPLICATION | 0,
++ &call_rerouting->q931ie));
++
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &call_rerouting->last_rerouting));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ call_rerouting->subscription_option));
++
++ if (call_rerouting->calling_subaddress.length) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end,
++ &call_rerouting->calling_subaddress));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4);
++ ASN1_CALL(pos, rose_enc_PresentedNumberScreened(ctrl, pos, end,
++ &call_rerouting->calling));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++
++ if (call_rerouting->calling_name_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5);
++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end,
++ &call_rerouting->calling_name));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ if (call_rerouting->original_called_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 6);
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &call_rerouting->original_called));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ if (call_rerouting->redirecting_name_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 7);
++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end,
++ &call_rerouting->redirecting_name));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ if (call_rerouting->original_called_name_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 8);
++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end,
++ &call_rerouting->original_called_name));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the DivertingLegInformation1 invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigDivertingLegInformation1_ARG *diverting_leg_information_1;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ diverting_leg_information_1 = &args->qsig.DivertingLegInformation1;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ diverting_leg_information_1->diversion_reason));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ diverting_leg_information_1->subscription_option));
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &diverting_leg_information_1->nominated_number));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the DivertingLegInformation2 invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigDivertingLegInformation2_ARG *diverting_leg_information_2;
++ unsigned char *seq_len;
++ unsigned char *exp_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ diverting_leg_information_2 = &args->qsig.DivertingLegInformation2;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ diverting_leg_information_2->diversion_counter));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ diverting_leg_information_2->diversion_reason));
++ if (diverting_leg_information_2->original_diversion_reason_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ diverting_leg_information_2->original_diversion_reason));
++ }
++
++ if (diverting_leg_information_2->diverting_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &diverting_leg_information_2->diverting));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ if (diverting_leg_information_2->original_called_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &diverting_leg_information_2->original_called));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ if (diverting_leg_information_2->redirecting_name_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end,
++ &diverting_leg_information_2->redirecting_name));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ if (diverting_leg_information_2->original_called_name_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4);
++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end,
++ &diverting_leg_information_2->original_called_name));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the DivertingLegInformation3 invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseQsigDivertingLegInformation3_ARG *diverting_leg_information_3;
++ unsigned char *seq_len;
++ unsigned char *exp_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ diverting_leg_information_3 = &args->qsig.DivertingLegInformation3;
++ ASN1_CALL(pos, asn1_enc_boolean(pos, end, ASN1_TYPE_BOOLEAN,
++ diverting_leg_information_3->presentation_allowed_indicator));
++
++ if (diverting_leg_information_3->redirection_name_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0);
++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end,
++ &diverting_leg_information_3->redirection_name));
++ ASN1_CONSTRUCTED_END(exp_len, pos, end);
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the IntResult argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param int_result Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_IntResult(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigForwardingRecord *int_result)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s IntResult %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &int_result->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ int_result->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ int_result->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_Address(ctrl, "divertedToAddress", tag, pos, seq_end,
++ &int_result->diverted_to));
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ int_result->remote_enabled = 0; /* DEFAULT FALSE */
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_TYPE_BOOLEAN:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_boolean(ctrl, "remoteEnabled", tag, pos, seq_end,
++ &value));
++ int_result->remote_enabled = value;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " extension %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the IntResultList argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param int_result_list Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_IntResultList(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigForwardingList *int_result_list)
++{
++ int length;
++ int set_offset;
++ const unsigned char *set_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s IntResultList %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(set_end, set_offset, length, pos, end);
++
++ int_result_list->num_records = 0;
++ while (pos < set_end && *pos != ASN1_INDEF_TERM) {
++ if (int_result_list->num_records < ARRAY_LEN(int_result_list->list)) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, set_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_qsig_IntResult(ctrl, "listEntry", tag, pos, set_end,
++ &int_result_list->list[int_result_list->num_records]));
++ ++int_result_list->num_records;
++ } else {
++ /* Too many records */
++ return NULL;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, set_offset, set_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG ActivateDiversionQ invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigActivateDiversionQ_ARG *activate_diversion_q;
++
++ activate_diversion_q = &args->qsig.ActivateDiversionQ;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " ActivateDiversionQ %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ activate_diversion_q->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ activate_diversion_q->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_Address(ctrl, "divertedToAddress", tag, pos, seq_end,
++ &activate_diversion_q->diverted_to));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &activate_diversion_q->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "activatingUserNr", tag, pos, seq_end,
++ &activate_diversion_q->activating_user_number));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG DeactivateDiversionQ invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigDeactivateDiversionQ_ARG *deactivate_diversion_q;
++
++ deactivate_diversion_q = &args->qsig.DeactivateDiversionQ;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " DeactivateDiversionQ %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ deactivate_diversion_q->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ deactivate_diversion_q->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &deactivate_diversion_q->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "deactivatingUserNr", tag, pos, seq_end,
++ &deactivate_diversion_q->deactivating_user_number));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG InterrogateDiversionQ invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigInterrogateDiversionQ_ARG *interrogate_diversion_q;
++
++ interrogate_diversion_q = &args->qsig.InterrogateDiversionQ;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " InterrogateDiversionQ %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ interrogate_diversion_q->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ if (tag == ASN1_TYPE_ENUMERATED) {
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ interrogate_diversion_q->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ } else {
++ interrogate_diversion_q->basic_service = 0; /* allServices */
++ }
++
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &interrogate_diversion_q->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "interrogatingUserNr", tag, pos, seq_end,
++ &interrogate_diversion_q->interrogating_user_number));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG InterrogateDiversionQ result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args)
++{
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SET);
++ return rose_dec_qsig_IntResultList(ctrl, "InterrogateDiversionQ", tag, pos, end,
++ &args->qsig.InterrogateDiversionQ);
++}
++
++/*!
++ * \brief Decode the Q.SIG CheckRestriction invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigCheckRestriction_ARG *check_restriction;
++
++ check_restriction = &args->qsig.CheckRestriction;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CheckRestriction %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end,
++ &check_restriction->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ check_restriction->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "divertedToNr", tag, pos, seq_end,
++ &check_restriction->diverted_to_number));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG CallRerouting invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigCallRerouting_ARG *call_rerouting;
++
++ call_rerouting = &args->qsig.CallRerouting;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CallRerouting %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "reroutingReason", tag, pos, seq_end, &value));
++ call_rerouting->rerouting_reason = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | 0)) {
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "originalReroutingReason", tag, pos, seq_end,
++ &value));
++ call_rerouting->original_rerouting_reason = value;
++ call_rerouting->original_rerouting_reason_present = 1;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ } else {
++ call_rerouting->original_rerouting_reason_present = 0;
++ }
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_Address(ctrl, "calledAddress", tag, pos, seq_end,
++ &call_rerouting->called));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionCounter", tag, pos, seq_end, &value));
++ call_rerouting->diversion_counter = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_CLASS_APPLICATION | 0);
++ ASN1_CALL(pos, rose_dec_Q931ie(ctrl, "pSS1InfoElement", tag, pos, seq_end,
++ &call_rerouting->q931ie, sizeof(call_rerouting->q931ie_contents)));
++
++ /* Remove EXPLICIT tag */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "lastReroutingNr", tag, pos,
++ explicit_end, &call_rerouting->last_rerouting));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "subscriptionOption", tag, pos, seq_end, &value));
++ call_rerouting->subscription_option = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3)) {
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "callingPartySubaddress", tag, pos,
++ explicit_end, &call_rerouting->calling_subaddress));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ } else {
++ call_rerouting->calling_subaddress.length = 0;
++ }
++
++ /* Remove EXPLICIT tag */
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberScreened(ctrl, "callingNumber", tag, pos,
++ explicit_end, &call_rerouting->calling));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ call_rerouting->calling_name_present = 0;
++ call_rerouting->redirecting_name_present = 0;
++ call_rerouting->original_called_name_present = 0;
++ call_rerouting->original_called_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "callingName", tag, pos,
++ explicit_end, &call_rerouting->calling_name));
++ call_rerouting->calling_name_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 6:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "originalCalledNr",
++ tag, pos, explicit_end, &call_rerouting->original_called));
++ call_rerouting->original_called_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 7:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "redirectingName", tag, pos,
++ explicit_end, &call_rerouting->redirecting_name));
++ call_rerouting->redirecting_name_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 8:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "originalCalledName", tag, pos,
++ explicit_end, &call_rerouting->original_called_name));
++ call_rerouting->original_called_name_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 9:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 9:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 10:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " extension %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG DivertingLegInformation1 invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigDivertingLegInformation1_ARG *diverting_leg_information_1;
++
++ diverting_leg_information_1 = &args->qsig.DivertingLegInformation1;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " DivertingLegInformation1 %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionReason", tag, pos, seq_end, &value));
++ diverting_leg_information_1->diversion_reason = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "subscriptionOption", tag, pos, seq_end, &value));
++ diverting_leg_information_1->subscription_option = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "nominatedNr", tag, pos, seq_end,
++ &diverting_leg_information_1->nominated_number));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG DivertingLegInformation2 invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigDivertingLegInformation2_ARG *diverting_leg_information_2;
++
++ diverting_leg_information_2 = &args->qsig.DivertingLegInformation2;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " DivertingLegInformation2 %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionCounter", tag, pos, seq_end, &value));
++ diverting_leg_information_2->diversion_counter = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionReason", tag, pos, seq_end, &value));
++ diverting_leg_information_2->diversion_reason = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ diverting_leg_information_2->original_diversion_reason_present = 0;
++ diverting_leg_information_2->diverting_present = 0;
++ diverting_leg_information_2->original_called_present = 0;
++ diverting_leg_information_2->redirecting_name_present = 0;
++ diverting_leg_information_2->original_called_name_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "originalDiversionReason", tag, pos,
++ seq_end, &value));
++ diverting_leg_information_2->original_diversion_reason = value;
++ diverting_leg_information_2->original_diversion_reason_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "divertingNr", tag,
++ pos, explicit_end, &diverting_leg_information_2->diverting));
++ diverting_leg_information_2->diverting_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "originalCalledNr",
++ tag, pos, explicit_end, &diverting_leg_information_2->original_called));
++ diverting_leg_information_2->original_called_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "redirectingName", tag, pos,
++ explicit_end, &diverting_leg_information_2->redirecting_name));
++ diverting_leg_information_2->redirecting_name_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "originalCalledName", tag, pos,
++ explicit_end, &diverting_leg_information_2->original_called_name));
++ diverting_leg_information_2->original_called_name_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 6:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " extension %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG DivertingLegInformation3 invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigDivertingLegInformation3_ARG *diverting_leg_information_3;
++
++ diverting_leg_information_3 = &args->qsig.DivertingLegInformation3;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " DivertingLegInformation3 %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_BOOLEAN);
++ ASN1_CALL(pos, asn1_dec_boolean(ctrl, "presentationAllowedIndicator", tag, pos,
++ seq_end, &value));
++ diverting_leg_information_3->presentation_allowed_indicator = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ diverting_leg_information_3->redirection_name_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "redirectionName", tag, pos,
++ explicit_end, &diverting_leg_information_3->redirection_name));
++ diverting_leg_information_3->redirection_name_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " extension %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_qsig_diversion.c */
+
+Property changes on: rose_qsig_diversion.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose.h
+===================================================================
+--- a/rose.h (.../tags/1.4.10.2) (revision 0)
++++ b/rose.h (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,3580 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief ROSE definitions and prototypes
++ *
++ * \details
++ * This file contains all of the data structures and definitions needed
++ * for ROSE component encoding and decoding.
++ *
++ * ROSE - Remote Operations Service Element
++ * ASN.1 - Abstract Syntax Notation 1
++ * APDU - Application Protocol Data Unit
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++#ifndef _LIBPRI_ROSE_H
++#define _LIBPRI_ROSE_H
++
++#include <string.h>
++#include <sys/types.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* ------------------------------------------------------------------- */
++
++
++/* Northern Telecom DMS-100 RLT related operations */
++#define ROSE_DMS100_RLT_SERVICE_ID 0x3e
++#define ROSE_DMS100_RLT_OPERATION_IND 0x01
++#define ROSE_DMS100_RLT_THIRD_PARTY 0x02
++
++/*! \brief ROSE operation-value function code */
++enum rose_operation {
++ /*! \brief No ROSE operation */
++ ROSE_None,
++ /*! \brief Unknown OID/localValue operation-value code */
++ ROSE_Unknown,
++
++/* *INDENT-OFF* */
++ /* ETSI Diversion-Operations */
++ ROSE_ETSI_ActivationDiversion, /*!< Invoke/Result */
++ ROSE_ETSI_DeactivationDiversion, /*!< Invoke/Result */
++ ROSE_ETSI_ActivationStatusNotificationDiv,/*!< Invoke only */
++ ROSE_ETSI_DeactivationStatusNotificationDiv,/*!< Invoke only */
++ ROSE_ETSI_InterrogationDiversion, /*!< Invoke/Result */
++ ROSE_ETSI_DiversionInformation, /*!< Invoke only */
++ ROSE_ETSI_CallDeflection, /*!< Invoke/Result */
++ ROSE_ETSI_CallRerouting, /*!< Invoke/Result */
++ ROSE_ETSI_InterrogateServedUserNumbers, /*!< Invoke/Result */
++ ROSE_ETSI_DivertingLegInformation1, /*!< Invoke only */
++ ROSE_ETSI_DivertingLegInformation2, /*!< Invoke only */
++ ROSE_ETSI_DivertingLegInformation3, /*!< Invoke only */
++
++ /*
++ * ETSI Advice-of-Charge-Operations
++ *
++ * Advice-Of-Charge-at-call-Setup(AOCS)
++ * Advice-Of-Charge-During-the-call(AOCD)
++ * Advice-Of-Charge-at-the-End-of-the-call(AOCE)
++ */
++ ROSE_ETSI_ChargingRequest, /*!< Invoke/Result */
++ ROSE_ETSI_AOCSCurrency, /*!< Invoke only */
++ ROSE_ETSI_AOCSSpecialArr, /*!< Invoke only */
++ ROSE_ETSI_AOCDCurrency, /*!< Invoke only */
++ ROSE_ETSI_AOCDChargingUnit, /*!< Invoke only */
++ ROSE_ETSI_AOCECurrency, /*!< Invoke only */
++ ROSE_ETSI_AOCEChargingUnit, /*!< Invoke only */
++
++ /* ETSI Explicit-Call-Transfer-Operations-and-Errors */
++ ROSE_ETSI_EctExecute, /*!< Invoke/Result */
++ ROSE_ETSI_ExplicitEctExecute, /*!< Invoke/Result */
++ ROSE_ETSI_RequestSubaddress, /*!< Invoke only */
++ ROSE_ETSI_SubaddressTransfer, /*!< Invoke only */
++ ROSE_ETSI_EctLinkIdRequest, /*!< Invoke/Result */
++ ROSE_ETSI_EctInform, /*!< Invoke only */
++ ROSE_ETSI_EctLoopTest, /*!< Invoke/Result */
++
++ /* Q.SIG Name-Operations */
++ ROSE_QSIG_CallingName, /*!< Invoke only */
++ ROSE_QSIG_CalledName, /*!< Invoke only */
++ ROSE_QSIG_ConnectedName, /*!< Invoke only */
++ ROSE_QSIG_BusyName, /*!< Invoke only */
++
++ /* Q.SIG SS-AOC-Operations */
++ ROSE_QSIG_ChargeRequest, /*!< Invoke/Result */
++ ROSE_QSIG_GetFinalCharge, /*!< Invoke only */
++ ROSE_QSIG_AocFinal, /*!< Invoke only */
++ ROSE_QSIG_AocInterim, /*!< Invoke only */
++ ROSE_QSIG_AocRate, /*!< Invoke only */
++ ROSE_QSIG_AocComplete, /*!< Invoke/Result */
++ ROSE_QSIG_AocDivChargeReq, /*!< Invoke only */
++
++ /* Q.SIG Call-Transfer-Operations (CT) */
++ ROSE_QSIG_CallTransferIdentify, /*!< Invoke/Result */
++ ROSE_QSIG_CallTransferAbandon, /*!< Invoke only */
++ ROSE_QSIG_CallTransferInitiate, /*!< Invoke/Result */
++ ROSE_QSIG_CallTransferSetup, /*!< Invoke/Result */
++ ROSE_QSIG_CallTransferActive, /*!< Invoke only */
++ ROSE_QSIG_CallTransferComplete, /*!< Invoke only */
++ ROSE_QSIG_CallTransferUpdate, /*!< Invoke only */
++ ROSE_QSIG_SubaddressTransfer, /*!< Invoke only */
++
++ ROSE_QSIG_PathReplacement, /*!< Invoke only */
++
++ /* Q.SIG Call-Diversion-Operations */
++ ROSE_QSIG_ActivateDiversionQ, /*!< Invoke/Result */
++ ROSE_QSIG_DeactivateDiversionQ, /*!< Invoke/Result */
++ ROSE_QSIG_InterrogateDiversionQ, /*!< Invoke/Result */
++ ROSE_QSIG_CheckRestriction, /*!< Invoke/Result */
++ ROSE_QSIG_CallRerouting, /*!< Invoke/Result */
++ ROSE_QSIG_DivertingLegInformation1, /*!< Invoke only */
++ ROSE_QSIG_DivertingLegInformation2, /*!< Invoke only */
++ ROSE_QSIG_DivertingLegInformation3, /*!< Invoke only */
++ ROSE_QSIG_CfnrDivertedLegFailed, /*!< Invoke only */
++
++ /* Q.SIG SS-MWI-Operations */
++ ROSE_QSIG_MWIActivate, /*!< Invoke/Result */
++ ROSE_QSIG_MWIDeactivate, /*!< Invoke/Result */
++ ROSE_QSIG_MWIInterrogate, /*!< Invoke/Result */
++
++ /* Northern Telecom DMS-100 RLT related operations */
++ /*! Invoke/Result: Must set invokeId to ROSE_DMS100_RLT_OPERATION_IND */
++ ROSE_DMS100_RLT_OperationInd,
++ /*! Invoke/Result: Must set invokeId to ROSE_DMS100_RLT_THIRD_PARTY */
++ ROSE_DMS100_RLT_ThirdParty,
++
++ ROSE_NI2_InformationFollowing, /*!< Invoke only? */
++ ROSE_NI2_InitiateTransfer, /*!< Invoke only? Is this correct operation name? */
++
++ ROSE_Num_Operation_Codes /*!< Must be last in the enumeration */
++/* *INDENT-ON* */
++};
++
++enum rose_error_code {
++ /*! \brief No error occurred */
++ ROSE_ERROR_None,
++ /*! \brief Unknown OID/localValue error-value code */
++ ROSE_ERROR_Unknown,
++
++ /* General-Errors (ETS 300 196) and General-Error-List(Q.950) */
++ ROSE_ERROR_Gen_NotSubscribed, /*!< also: UserNotSubscribed */
++ ROSE_ERROR_Gen_NotAvailable,
++ ROSE_ERROR_Gen_NotImplemented, /*!< Not in Q.950 */
++ ROSE_ERROR_Gen_InvalidServedUserNr,
++ ROSE_ERROR_Gen_InvalidCallState,
++ ROSE_ERROR_Gen_BasicServiceNotProvided,
++ ROSE_ERROR_Gen_NotIncomingCall,
++ ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed,
++ ROSE_ERROR_Gen_ResourceUnavailable,
++
++ /* Additional General-Error-List(Q.950) */
++ ROSE_ERROR_Gen_RejectedByNetwork,
++ ROSE_ERROR_Gen_RejectedByUser,
++ ROSE_ERROR_Gen_InsufficientInformation,
++ ROSE_ERROR_Gen_CallFailure,
++ ROSE_ERROR_Gen_ProceduralError,
++
++ /* ETSI Diversion-Operations */
++ ROSE_ERROR_Div_InvalidDivertedToNr,
++ ROSE_ERROR_Div_SpecialServiceNr,
++ ROSE_ERROR_Div_DiversionToServedUserNr,
++ ROSE_ERROR_Div_IncomingCallAccepted,
++ ROSE_ERROR_Div_NumberOfDiversionsExceeded,
++ ROSE_ERROR_Div_NotActivated,
++ ROSE_ERROR_Div_RequestAlreadyAccepted,
++
++ /* ETSI Advice-of-Charge-Operations */
++ ROSE_ERROR_AOC_NoChargingInfoAvailable,
++
++ /* ETSI Explicit-Call-Transfer-Operations-and-Errors */
++ ROSE_ERROR_ECT_LinkIdNotAssignedByNetwork,
++
++ /* Q.SIG from various specifications */
++ ROSE_ERROR_QSIG_Unspecified,
++
++ /* Q.SIG SS-AOC-Operations */
++ ROSE_ERROR_QSIG_AOC_FreeOfCharge,
++
++ /* Q.SIG Call-Transfer-Operations (CT) */
++ ROSE_ERROR_QSIG_CT_InvalidReroutingNumber,
++ ROSE_ERROR_QSIG_CT_UnrecognizedCallIdentity,
++ ROSE_ERROR_QSIG_CT_EstablishmentFailure,
++
++ /* Q.SIG Call-Diversion-Operations (Additional Q.SIG specific errors) */
++ ROSE_ERROR_QSIG_Div_TemporarilyUnavailable,
++ ROSE_ERROR_QSIG_Div_NotAuthorized,
++
++ /* Q.SIG SS-MWI-Operations */
++ ROSE_ERROR_QSIG_InvalidMsgCentreId,
++
++ /* Northern Telecom DMS-100 RLT related operations */
++ ROSE_ERROR_DMS100_RLT_BridgeFail,
++ ROSE_ERROR_DMS100_RLT_CallIDNotFound,
++ ROSE_ERROR_DMS100_RLT_NotAllowed,
++ ROSE_ERROR_DMS100_RLT_SwitchEquipCongs,
++
++ ROSE_ERROR_Num_Codes /*!< Must be last in the enumeration */
++};
++
++#define ROSE_REJECT_BASE(base) ((base) * 0x100)
++enum rose_reject_base {
++ ROSE_REJECT_BASE_General,
++ ROSE_REJECT_BASE_Invoke,
++ ROSE_REJECT_BASE_Result,
++ ROSE_REJECT_BASE_Error,
++
++ /*! \brief Must be last in the list */
++ ROSE_REJECT_BASE_Last
++};
++
++/*!
++ * \brief From Facility-Information-Element-Components
++ * {itu-t identified-organization etsi(0) 196 facility-information-element-component(3)}
++ */
++enum rose_reject_code {
++ /*! \brief Not rejected */
++ ROSE_REJECT_None = -1,
++ /*! \brief Unknown reject code */
++ ROSE_REJECT_Unknown = -2,
++
++/* *INDENT-OFF* */
++ ROSE_REJECT_Gen_UnrecognizedComponent = ROSE_REJECT_BASE(ROSE_REJECT_BASE_General) + 0,
++ ROSE_REJECT_Gen_MistypedComponent = ROSE_REJECT_BASE(ROSE_REJECT_BASE_General) + 1,
++ ROSE_REJECT_Gen_BadlyStructuredComponent = ROSE_REJECT_BASE(ROSE_REJECT_BASE_General) + 2,
++
++ ROSE_REJECT_Inv_DuplicateInvocation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 0,
++ ROSE_REJECT_Inv_UnrecognizedOperation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 1,
++ ROSE_REJECT_Inv_MistypedArgument = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 2,
++ ROSE_REJECT_Inv_ResourceLimitation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 3,
++ ROSE_REJECT_Inv_InitiatorReleasing = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 4,
++ ROSE_REJECT_Inv_UnrecognizedLinkedID = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 5,
++ ROSE_REJECT_Inv_LinkedResponseUnexpected = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 6,
++ ROSE_REJECT_Inv_UnexpectedChildOperation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 7,
++
++ ROSE_REJECT_Res_UnrecognizedInvocation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result) + 0,
++ ROSE_REJECT_Res_ResultResponseUnexpected = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result) + 1,
++ ROSE_REJECT_Res_MistypedResult = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result) + 2,
++
++ ROSE_REJECT_Err_UnrecognizedInvocation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 0,
++ ROSE_REJECT_Err_ErrorResponseUnexpected = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 1,
++ ROSE_REJECT_Err_UnrecognizedError = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 2,
++ ROSE_REJECT_Err_UnexpectedError = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 3,
++ ROSE_REJECT_Err_MistypedParameter = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 4,
++/* *INDENT-ON* */
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * Q931InformationElement ::= [APPLICATION 0] IMPLICIT OCTET STRING
++ */
++struct roseQ931ie {
++ /*!
++ * \brief The Q.931 ie is present if length is nonzero.
++ * (If this field is optional in the message.)
++ */
++ u_int8_t length;
++
++ /*!
++ * \brief We mostly just need to store the contents so we will defer
++ * decoding/encoding.
++ *
++ * \note To reduce the size of the structure, the memory for the
++ * ie contents is "allocated" after the structure.
++ * \note Remember the "allocated" memory needs to have room for a
++ * null terminator.
++ */
++ unsigned char contents[0];
++};
++
++enum {
++ /*! Bearer Capability has a max length of 12. */
++ ROSE_Q931_MAX_BC = 12,
++ /*! High Layer Compatibility has a max length of 5. */
++ ROSE_Q931_MAX_HLC = 5,
++ /*! Low Layer Compatibility has a max length of 18. */
++ ROSE_Q931_MAX_LLC = 18,
++ /*!
++ * User-User Information has a network dependent maximum.
++ * The network dependent maximum is either 35 or 131 octets
++ * in non-USER-INFORMATION messages.
++ */
++ ROSE_Q931_MAX_USER = 131,
++ /*!
++ * Progress Indicator has a max length of 4.
++ * There can be multiple progress indicator ies.
++ * Q.SIG allows up to 3.
++ * ITU-T allows up to 2.
++ */
++ ROSE_Q931_MAX_PROGRESS = 3 * 4,
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * PartyNumber ::= CHOICE {
++ * -- the numbering plan is the default numbering plan of
++ * -- the network. It is recommended that this value is
++ * -- used.
++ * unknownPartyNumber [0] IMPLICIT NumberDigits,
++ *
++ * -- the numbering plan is according to
++ * -- ITU-T Recommendation E.164.
++ * publicPartyNumber [1] IMPLICIT PublicPartyNumber,
++ *
++ * -- ATM endsystem address encoded as an NSAP address.
++ * nsapEncodedNumber [2] IMPLICIT NsapEncodedNumber,
++ *
++ * -- not used, value reserved.
++ * dataPartyNumber [3] IMPLICIT NumberDigits,
++ *
++ * -- not used, value reserved.
++ * telexPartyNumber [4] IMPLICIT NumberDigits,
++ * privatePartyNumber [5] IMPLICIT PrivatePartyNumber,
++ *
++ * -- not used, value reserved.
++ * nationalStandardPartyNumber [8] IMPLICIT NumberDigits
++ * }
++ */
++struct rosePartyNumber {
++ /*!
++ * \brief Party numbering plan
++ * \details
++ * unknown(0),
++ * public(1) - The numbering plan is according to ITU-T E.164,
++ * nsapEncoded(2),
++ * data(3) - Reserved,
++ * telex(4) - Reserved,
++ * private(5),
++ * nationalStandard(8) - Reserved
++ */
++ u_int8_t plan;
++
++ /*!
++ * \brief Type-Of-Number valid for public and private party number plans
++ * \details
++ * public:
++ * unknown(0),
++ * internationalNumber(1),
++ * nationalNumber(2),
++ * networkSpecificNumber(3) - Reserved,
++ * subscriberNumber(4) - Reserved,
++ * abbreviatedNumber(6)
++ * \details
++ * private:
++ * unknown(0),
++ * level2RegionalNumber(1),
++ * level1RegionalNumber(2),
++ * pTNSpecificNumber/pISNSpecificNumber(3),
++ * localNumber(4),
++ * abbreviatedNumber(6)
++ */
++ u_int8_t ton;
++
++ /*! \brief Number present if length is nonzero. */
++ u_int8_t length;
++
++ /*! \brief Number string data. */
++ unsigned char str[20 + 1];
++};
++
++/*
++ * NumberScreened ::= SEQUENCE {
++ * partyNumber PartyNumber,
++ * screeningIndicator ScreeningIndicator
++ * }
++ */
++struct roseNumberScreened {
++ struct rosePartyNumber number;
++
++ /*!
++ * \details
++ * userProvidedNotScreened(0),
++ * userProvidedVerifiedAndPassed(1),
++ * userProvidedVerifiedAndFailed(2) (Not used, value reserved),
++ * networkProvided(3)
++ */
++ u_int8_t screening_indicator;
++};
++
++/*
++ * PartySubaddress ::= CHOICE {
++ * -- not recommended
++ * UserSpecifiedSubaddress,
++ *
++ * -- according to ITU-T Recommendation X.213
++ * NSAPSubaddress
++ * }
++ *
++ * UserSpecifiedSubaddress ::= SEQUENCE {
++ * SubaddressInformation,
++ *
++ * -- used when the coding of subaddress is BCD
++ * oddCountIndicator BOOLEAN OPTIONAL
++ * }
++ *
++ * -- specified according to ITU-T Recommendation X.213. Some
++ * -- networks may limit the subaddress value to some other
++ * -- length, e.g. 4 octets
++ * NSAPSubaddress ::= OCTET STRING (SIZE(1..20))
++ *
++ * -- coded according to user requirements. Some networks may
++ * -- limit the subaddress value to some other length,
++ * -- e.g. 4 octets
++ * SubaddressInformation ::= OCTET STRING (SIZE(1..20))
++ */
++struct rosePartySubaddress {
++ /*! \brief Subaddress type UserSpecified(0), NSAP(1) */
++ u_int8_t type;
++
++ /*! \brief Subaddress present if length is nonzero */
++ u_int8_t length;
++
++ union {
++ /*! \brief Specified according to ITU-T Recommendation X.213 */
++ unsigned char nsap[20 + 1];
++
++ /*! \brief Use of this formatting is not recommended */
++ struct {
++ /*! \brief TRUE if OddCount present */
++ u_int8_t odd_count_present;
++
++ /*!
++ * \brief TRUE if odd number of BCD digits (optional)
++ * \note Used when the coding of subaddress is BCD.
++ */
++ u_int8_t odd_count;
++ unsigned char information[20 + 1];
++ } user_specified;
++ } u;
++};
++
++/*
++ * Address ::= SEQUENCE {
++ * PartyNumber,
++ * PartySubaddress OPTIONAL
++ * }
++ */
++struct roseAddress {
++ struct rosePartyNumber number;
++
++ /*! \brief Subaddress (Optional) */
++ struct rosePartySubaddress subaddress;
++};
++
++/*
++ * AddressScreened ::= SEQUENCE {
++ * PartyNumber,
++ * ScreeningIndicator,
++ * PartySubaddress OPTIONAL
++ * }
++ */
++struct roseAddressScreened {
++ struct rosePartyNumber number;
++
++ /*! \brief Subaddress (Optional) */
++ struct rosePartySubaddress subaddress;
++
++ /*!
++ * \details
++ * userProvidedNotScreened(0),
++ * userProvidedVerifiedAndPassed(1),
++ * userProvidedVerifiedAndFailed(2) (Not used, value reserved),
++ * networkProvided(3)
++ */
++ u_int8_t screening_indicator;
++};
++
++/*
++ * PresentedNumberUnscreened ::= CHOICE {
++ * presentationAllowedNumber [0] EXPLICIT PartyNumber,
++ * presentationRestricted [1] IMPLICIT NULL,
++ * numberNotAvailableDueToInterworking [2] IMPLICIT NULL,
++ * presentationRestrictedNumber [3] EXPLICIT PartyNumber
++ * }
++ */
++struct rosePresentedNumberUnscreened {
++ struct rosePartyNumber number;
++ /*!
++ * \brief Number presentation type
++ * \details
++ * presentationAllowedNumber(0),
++ * presentationRestricted(1),
++ * numberNotAvailableDueToInterworking(2),
++ * presentationRestrictedNumber(3)
++ */
++ u_int8_t presentation;
++};
++
++/*
++ * PresentedNumberScreened ::= CHOICE {
++ * presentationAllowedNumber [0] IMPLICIT NumberScreened,
++ * presentationRestricted [1] IMPLICIT NULL,
++ * numberNotAvailableDueToInterworking [2] IMPLICIT NULL,
++ * presentationRestrictedNumber [3] IMPLICIT NumberScreened
++ * }
++ */
++struct rosePresentedNumberScreened {
++ /*! \brief Screened number */
++ struct roseNumberScreened screened;
++ /*!
++ * \brief Number presentation type
++ * \details
++ * presentationAllowedNumber(0),
++ * presentationRestricted(1),
++ * numberNotAvailableDueToInterworking(2),
++ * presentationRestrictedNumber(3)
++ */
++ u_int8_t presentation;
++};
++
++/*
++ * PresentedAddressScreened ::= CHOICE {
++ * presentationAllowedAddress [0] IMPLICIT AddressScreened,
++ * presentationRestricted [1] IMPLICIT NULL,
++ * numberNotAvailableDueToInterworking [2] IMPLICIT NULL,
++ * presentationRestrictedAddress [3] IMPLICIT AddressScreened
++ * }
++ */
++struct rosePresentedAddressScreened {
++ /*! \breif Screened address */
++ struct roseAddressScreened screened;
++ /*!
++ * \brief Address presentation type
++ * \details
++ * presentationAllowedAddress(0),
++ * presentationRestricted(1),
++ * numberNotAvailableDueToInterworking(2),
++ * presentationRestrictedAddress(3)
++ */
++ u_int8_t presentation;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * Time ::= SEQUENCE {
++ * lengthOfTimeUnit [1] IMPLICIT LengthOfTimeUnit,
++ * scale [2] IMPLICIT Scale
++ * }
++ */
++struct roseEtsiAOCTime {
++ /*! LengthOfTimeUnit ::= INTEGER (0..16777215) -- 24 bit number */
++ u_int32_t length;
++ /*!
++ * \details
++ * oneHundredthSecond(0),
++ * oneTenthSecond(1),
++ * oneSecond(2),
++ * tenSeconds(3),
++ * oneMinute(4),
++ * oneHour(5),
++ * twentyFourHours(6)
++ */
++ u_int8_t scale;
++};
++
++/*
++ * Amount ::= SEQUENCE {
++ * currencyAmount [1] IMPLICIT CurrencyAmount,
++ * multiplier [2] IMPLICIT Multiplier
++ * }
++ */
++struct roseEtsiAOCAmount {
++ /*! CurrencyAmount ::= INTEGER (0..16777215) -- 24 bit number */
++ u_int32_t currency;
++ /*!
++ * \details
++ * oneThousandth(0),
++ * oneHundredth(1),
++ * oneTenth(2),
++ * one(3),
++ * ten(4),
++ * hundred(5),
++ * thousand(6)
++ */
++ u_int8_t multiplier;
++};
++
++/*
++ * DurationCurrency ::= SEQUENCE {
++ * dCurrency [1] IMPLICIT Currency,
++ * dAmount [2] IMPLICIT Amount,
++ * dChargingType [3] IMPLICIT ChargingType,
++ * dTime [4] IMPLICIT Time,
++ * dGranularity [5] IMPLICIT Time OPTIONAL
++ * }
++ */
++struct roseEtsiAOCDurationCurrency {
++ struct roseEtsiAOCAmount amount;
++ struct roseEtsiAOCTime time;
++ /*! \breif dGranularity (optional) */
++ struct roseEtsiAOCTime granularity;
++ /*! Currency ::= IA5String (SIZE (1..10)) -- Name of currency. */
++ unsigned char currency[10 + 1];
++ /*!
++ * \details
++ * continuousCharging(0),
++ * stepFunction(1)
++ */
++ u_int8_t charging_type;
++ /*! TRUE if granularity time is present */
++ u_int8_t granularity_present;
++};
++
++/*
++ * FlatRateCurrency ::= SEQUENCE {
++ * fRCurrency [1] IMPLICIT Currency,
++ * fRAmount [2] IMPLICIT Amount
++ * }
++ */
++struct roseEtsiAOCFlatRateCurrency {
++ struct roseEtsiAOCAmount amount;
++ /*! Currency ::= IA5String (SIZE (1..10)) -- Name of currency. */
++ unsigned char currency[10 + 1];
++};
++
++/*
++ * VolumeRateCurrency ::= SEQUENCE {
++ * vRCurrency [1] IMPLICIT Currency,
++ * vRAmount [2] IMPLICIT Amount,
++ * vRVolumeUnit [3] IMPLICIT VolumeUnit
++ * }
++ */
++struct roseEtsiAOCVolumeRateCurrency {
++ struct roseEtsiAOCAmount amount;
++ /*! Currency ::= IA5String (SIZE (1..10)) -- Name of currency. */
++ unsigned char currency[10 + 1];
++ /*!
++ * \brief Volume rate volume unit
++ * \details
++ * octet(0),
++ * segment(1),
++ * message(2)
++ */
++ u_int8_t unit;
++};
++
++/*
++ * AOCSCurrencyInfo ::= SEQUENCE {
++ * chargedItem ChargedItem,
++ * CHOICE {
++ * specialChargingCode SpecialChargingCode,
++ * durationCurrency [1] IMPLICIT DurationCurrency,
++ * flatRateCurrency [2] IMPLICIT FlatRateCurrency,
++ * volumeRateCurrency [3] IMPLICIT VolumeRateCurrency
++ * freeOfCharge [4] IMPLICIT NULL,
++ * currencyInfoNotAvailable [5] IMPLICIT NULL
++ * }
++ * }
++ */
++struct roseEtsiAOCSCurrencyInfo {
++ union {
++ struct roseEtsiAOCDurationCurrency duration;
++ struct roseEtsiAOCFlatRateCurrency flat_rate;
++ struct roseEtsiAOCVolumeRateCurrency volume_rate;
++ /*! SpecialChargingCode ::= INTEGER (1..10) */
++ u_int8_t special_charging_code;
++ } u;
++ /*!
++ * \brief Determine what is stored in the union.
++ * \details
++ * specialChargingCode(0),
++ * durationCurrency(1),
++ * flatRateCurrency(2),
++ * volumeRateCurrency(3),
++ * freeOfCharge(4),
++ * currencyInfoNotAvailable(5),
++ */
++ u_int8_t currency_type;
++ /*!
++ * \brief What service is being billed.
++ * \details
++ * basicCommunication(0),
++ * callAttempt(1),
++ * callSetup(2),
++ * userToUserInfo(3),
++ * operationOfSupplementaryServ(4)
++ */
++ u_int8_t charged_item;
++};
++
++/*
++ * AOCSCurrencyInfoList ::= SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo
++ */
++struct roseEtsiAOCSCurrencyInfoList {
++ /*! \brief SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo */
++ struct roseEtsiAOCSCurrencyInfo list[10];
++
++ /*! \brief Number of AOCSCurrencyInfo records present */
++ u_int8_t num_records;
++};
++
++/*
++ * RecordedCurrency ::= SEQUENCE {
++ * rCurrency [1] IMPLICIT Currency,
++ * rAmount [2] IMPLICIT Amount
++ * }
++ */
++struct roseEtsiAOCRecordedCurrency {
++ /*! Amount of currency involved. */
++ struct roseEtsiAOCAmount amount;
++ /*! Currency ::= IA5String (SIZE (1..10)) -- Name of currency. */
++ unsigned char currency[10 + 1];
++};
++
++/*
++ * RecordedUnits ::= SEQUENCE {
++ * CHOICE {
++ * recordedNumberOfUnits NumberOfUnits,
++ * notAvailable NULL
++ * },
++ * recordedTypeOfUnits TypeOfUnit OPTIONAL
++ * }
++ */
++struct roseEtsiAOCRecordedUnits {
++ /*! \brief recordedNumberOfUnits INTEGER (0..16777215) -- 24 bit number */
++ u_int32_t number_of_units;
++ /*! \brief TRUE if number_of_units is not available (not present) */
++ u_int8_t not_available;
++ /*! \brief recordedTypeOfUnits INTEGER (1..16) (optional) */
++ u_int8_t type_of_unit;
++ /*! \brief TRUE if type_of_unit is present */
++ u_int8_t type_of_unit_present;
++};
++
++/*
++ * RecordedUnitsList ::= SEQUENCE SIZE (1..32) OF RecordedUnits
++ */
++struct roseEtsiAOCRecordedUnitsList {
++ /*! \brief SEQUENCE SIZE (1..32) OF RecordedUnits */
++ struct roseEtsiAOCRecordedUnits list[32];
++
++ /*! \brief Number of RecordedUnits records present */
++ u_int8_t num_records;
++};
++
++/*
++ * ChargingAssociation ::= CHOICE {
++ * chargedNumber [0] EXPLICIT PartyNumber,
++ * chargeIdentifier ChargeIdentifier
++ * }
++ */
++struct roseEtsiAOCChargingAssociation {
++ /*! chargeIdentifier: INTEGER (-32768..32767) -- 16 bit number */
++ int16_t id;
++ /*! chargedNumber */
++ struct rosePartyNumber number;
++ /*!
++ * \details
++ * charge_identifier(0),
++ * charged_number(1)
++ */
++ u_int8_t type;
++};
++
++/*
++ * AOCECurrencyInfo ::= SEQUENCE {
++ * CHOICE {
++ * freeOfCharge [1] IMPLICIT NULL,
++ * specificCurrency SEQUENCE {
++ * recordedCurrency [1] IMPLICIT RecordedCurrency,
++ * aOCEBillingId [2] IMPLICIT AOCEBillingId OPTIONAL
++ * }
++ * },
++ * chargingAssociation ChargingAssociation OPTIONAL
++ * }
++ */
++struct roseEtsiAOCECurrencyInfo {
++ struct {
++ /*! \brief recorded currency */
++ struct roseEtsiAOCRecordedCurrency recorded;
++ /*!
++ * \brief AOCEBillingId (optional)
++ * \details
++ * normalCharging(0),
++ * reverseCharging(1),
++ * creditCardCharging(2),
++ * callForwardingUnconditional(3),
++ * callForwardingBusy(4),
++ * callForwardingNoReply(5),
++ * callDeflection(6),
++ * callTransfer(7)
++ */
++ u_int8_t billing_id;
++ /*! \brief TRUE if billing id is present */
++ u_int8_t billing_id_present;
++ } specific;
++
++ /*! \brief chargingAssociation (optional) */
++ struct roseEtsiAOCChargingAssociation charging_association;
++
++ /*! \brief TRUE if charging_association is present */
++ u_int8_t charging_association_present;
++
++ /*!
++ * \brief TRUE if this is free of charge.
++ * \note When TRUE, the contents of specific are not valid.
++ */
++ u_int8_t free_of_charge;
++};
++
++/*
++ * AOCEChargingUnitInfo ::= SEQUENCE {
++ * CHOICE {
++ * freeOfCharge [1] IMPLICIT NULL,
++ * specificChargingUnits SEQUENCE
++ * {
++ * recordedUnitsList [1] IMPLICIT RecordedUnitsList,
++ * aOCEBillingId [2] IMPLICIT AOCEBillingId OPTIONAL
++ * }
++ * },
++ * chargingAssociation ChargingAssociation OPTIONAL
++ * }
++ */
++struct roseEtsiAOCEChargingUnitInfo {
++ /*! \brief Not valid if free_of_charge is TRUE */
++ struct {
++ /*! \brief RecordedUnitsList */
++ struct roseEtsiAOCRecordedUnitsList recorded;
++ /*!
++ * \brief AOCEBillingId (optional)
++ * \details
++ * normalCharging(0),
++ * reverseCharging(1),
++ * creditCardCharging(2),
++ * callForwardingUnconditional(3),
++ * callForwardingBusy(4),
++ * callForwardingNoReply(5),
++ * callDeflection(6),
++ * callTransfer(7)
++ */
++ u_int8_t billing_id;
++ /*! \brief TRUE if billing id is present */
++ u_int8_t billing_id_present;
++ } specific;
++
++ /*! \brief chargingAssociation (optional) */
++ struct roseEtsiAOCChargingAssociation charging_association;
++
++ /*! \brief TRUE if charging_association is present */
++ u_int8_t charging_association_present;
++
++ /*!
++ * \brief TRUE if this is free of charge.
++ * \note When TRUE, the contents of specific are not valid.
++ */
++ u_int8_t free_of_charge;
++};
++
++/*
++ * ARGUMENT ChargingCase
++ */
++struct roseEtsiChargingRequest_ARG {
++ /*!
++ * \details
++ * chargingInformationAtCallSetup(0),
++ * chargingDuringACall(1),
++ * chargingAtTheEndOfACall(2)
++ */
++ u_int8_t charging_case;
++};
++
++/*
++ * RESULT CHOICE {
++ * AOCSCurrencyInfoList,
++ * AOCSSpecialArrInfo,
++ * chargingInfoFollows NULL
++ * }
++ */
++struct roseEtsiChargingRequest_RES {
++ union {
++ struct roseEtsiAOCSCurrencyInfoList currency_info;
++
++ /*! AOCSSpecialArrInfo ::= INTEGER (1..10) */
++ u_int8_t special_arrangement;
++ } u;
++ /*!
++ * \details
++ * currency_info_list(0),
++ * special_arrangement_info(1),
++ * charging_info_follows(2)
++ */
++ u_int8_t type;
++};
++
++/*
++ * ARGUMENT CHOICE {
++ * chargeNotAvailable NULL,
++ * AOCSCurrencyInfoList
++ * }
++ */
++struct roseEtsiAOCSCurrency_ARG {
++ struct roseEtsiAOCSCurrencyInfoList currency_info;
++ /*!
++ * \details
++ * charge_not_available(0),
++ * currency_info_list(1)
++ */
++ u_int8_t type;
++};
++
++/*
++ * ARGUMENT CHOICE {
++ * chargeNotAvailable NULL,
++ * AOCSSpecialArrInfo
++ * }
++ */
++struct roseEtsiAOCSSpecialArr_ARG {
++ /*!
++ * \details
++ * charge_not_available(0),
++ * special_arrangement_info(1)
++ */
++ u_int8_t type;
++ /*! AOCSSpecialArrInfo ::= INTEGER (1..10) */
++ u_int8_t special_arrangement;
++};
++
++/*
++ * ARGUMENT CHOICE {
++ * chargeNotAvailable NULL,
++ * aOCDCurrencyInfo CHOICE {
++ * freeOfCharge [1] IMPLICIT NULL,
++ * specificCurrency SEQUENCE {
++ * recordedCurrency [1] IMPLICIT RecordedCurrency,
++ * typeOfChargingInfo [2] IMPLICIT TypeOfChargingInfo,
++ * aOCDBillingId [3] IMPLICIT AOCDBillingId OPTIONAL
++ * }
++ * }
++ * }
++ */
++struct roseEtsiAOCDCurrency_ARG {
++ struct {
++ /*! \brief recorded currency */
++ struct roseEtsiAOCRecordedCurrency recorded;
++ /*!
++ * \brief Type of recorded charging information.
++ * \details
++ * subTotal(0),
++ * total(1)
++ */
++ u_int8_t type_of_charging_info;
++ /*!
++ * \brief AOCDBillingId (optional)
++ * \details
++ * normalCharging(0),
++ * reverseCharging(1),
++ * creditCardCharging(2)
++ */
++ u_int8_t billing_id;
++ /*! \brief TRUE if billing id is present */
++ u_int8_t billing_id_present;
++ } specific;
++ /*!
++ * \details
++ * charge_not_available(0),
++ * free_of_charge(1),
++ * specific_currency(2)
++ */
++ u_int8_t type;
++};
++
++/*
++ * ARGUMENT CHOICE {
++ * chargeNotAvailable NULL,
++ * aOCDChargingUnitInfo CHOICE {
++ * freeOfCharge [1] IMPLICIT NULL,
++ * specificChargingUnits SEQUENCE {
++ * recordedUnitsList [1] IMPLICIT RecordedUnitsList,
++ * typeOfChargingInfo [2] IMPLICIT TypeOfChargingInfo,
++ * aOCDBillingId [3] IMPLICIT AOCDBillingId OPTIONAL
++ * }
++ * }
++ * }
++ */
++struct roseEtsiAOCDChargingUnit_ARG {
++ struct {
++ /*! \brief RecordedUnitsList */
++ struct roseEtsiAOCRecordedUnitsList recorded;
++ /*!
++ * \brief Type of recorded charging information.
++ * \details
++ * subTotal(0),
++ * total(1)
++ */
++ u_int8_t type_of_charging_info;
++ /*!
++ * \brief AOCDBillingId (optional)
++ * \details
++ * normalCharging(0),
++ * reverseCharging(1),
++ * creditCardCharging(2)
++ */
++ u_int8_t billing_id;
++ /*! \brief TRUE if billing id is present */
++ u_int8_t billing_id_present;
++ } specific;
++ /*!
++ * \details
++ * charge_not_available(0),
++ * free_of_charge(1),
++ * specific_charging_units(2)
++ */
++ u_int8_t type;
++};
++
++/*
++ * ARGUMENT CHOICE {
++ * chargeNotAvailable NULL,
++ * AOCECurrencyInfo
++ * }
++ */
++struct roseEtsiAOCECurrency_ARG {
++ struct roseEtsiAOCECurrencyInfo currency_info;
++ /*!
++ * \details
++ * charge_not_available(0),
++ * currency_info(1)
++ */
++ u_int8_t type;
++};
++
++/*
++ * ARGUMENT CHOICE {
++ * chargeNotAvailable NULL,
++ * AOCEChargingUnitInfo
++ * }
++ */
++struct roseEtsiAOCEChargingUnit_ARG {
++ struct roseEtsiAOCEChargingUnitInfo charging_unit;
++ /*!
++ * \details
++ * charge_not_available(0),
++ * charging_unit(1)
++ */
++ u_int8_t type;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * ARGUMENT SEQUENCE {
++ * procedure Procedure,
++ * basicService BasicService,
++ * forwardedToAddress Address,
++ * servedUserNr ServedUserNr
++ * }
++ */
++struct roseEtsiActivationDiversion_ARG {
++ /*! \brief Forwarded to address */
++ struct roseAddress forwarded_to;
++
++ /*! \brief Forward all numbers if not present (Number length is zero). */
++ struct rosePartyNumber served_user_number;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3k1Hz(3),
++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4),
++ * multirate(5),
++ * telephony3k1Hz(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * telephony7kHz(38),
++ * euroFileTransfer(39),
++ * fileTransferAndAccessManagement(40),
++ * videoconference(41),
++ * audioGraphicConference(42)
++ */
++ u_int8_t basic_service;
++};
++
++
++/*
++ * ARGUMENT SEQUENCE {
++ * procedure Procedure,
++ * basicService BasicService,
++ * servedUserNr ServedUserNr
++ * }
++ */
++struct roseEtsiDeactivationDiversion_ARG {
++ /*! \brief Forward all numbers if not present (Number length is zero). */
++ struct rosePartyNumber served_user_number;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3k1Hz(3),
++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4),
++ * multirate(5),
++ * telephony3k1Hz(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * telephony7kHz(38),
++ * euroFileTransfer(39),
++ * fileTransferAndAccessManagement(40),
++ * videoconference(41),
++ * audioGraphicConference(42)
++ */
++ u_int8_t basic_service;
++};
++
++
++/*
++ * ARGUMENT SEQUENCE {
++ * procedure Procedure,
++ * basicService BasicService,
++ * forwardedToAddresss Address,
++ * servedUserNr ServedUserNr
++ * }
++ */
++struct roseEtsiActivationStatusNotificationDiv_ARG {
++ /*! \brief Forwarded to address */
++ struct roseAddress forwarded_to;
++
++ /*! \brief Forward all numbers if not present (Number length is zero). */
++ struct rosePartyNumber served_user_number;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3k1Hz(3),
++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4),
++ * multirate(5),
++ * telephony3k1Hz(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * telephony7kHz(38),
++ * euroFileTransfer(39),
++ * fileTransferAndAccessManagement(40),
++ * videoconference(41),
++ * audioGraphicConference(42)
++ */
++ u_int8_t basic_service;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * procedure Procedure,
++ * basicService BasicService,
++ * servedUserNr ServedUserNr
++ * }
++ */
++struct roseEtsiDeactivationStatusNotificationDiv_ARG {
++ /*! \brief Forward all numbers if not present (Number length is zero). */
++ struct rosePartyNumber served_user_number;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3k1Hz(3),
++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4),
++ * multirate(5),
++ * telephony3k1Hz(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * telephony7kHz(38),
++ * euroFileTransfer(39),
++ * fileTransferAndAccessManagement(40),
++ * videoconference(41),
++ * audioGraphicConference(42)
++ */
++ u_int8_t basic_service;
++};
++
++
++/*
++ * ARGUMENT SEQUENCE {
++ * procedure Procedure,
++ * basicService BasicService DEFAULT allServices,
++ * servedUserNr ServedUserNr
++ * }
++ */
++struct roseEtsiInterrogationDiversion_ARG {
++ /*! \brief Forward all numbers if not present (Number length is zero). */
++ struct rosePartyNumber served_user_number;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*!
++ * \details
++ * DEFAULT allServices
++ *
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3k1Hz(3),
++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4),
++ * multirate(5),
++ * telephony3k1Hz(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * telephony7kHz(38),
++ * euroFileTransfer(39),
++ * fileTransferAndAccessManagement(40),
++ * videoconference(41),
++ * audioGraphicConference(42)
++ */
++ u_int8_t basic_service;
++};
++
++/*
++ * IntResult ::= SEQUENCE {
++ * servedUserNr ServedUserNr,
++ * basicService BasicService,
++ * procedure Procedure,
++ * forwardedToAddress Address
++ * }
++ */
++struct roseEtsiForwardingRecord {
++ /*! \brief Forwarded to address */
++ struct roseAddress forwarded_to;
++
++ /*! \brief Forward all numbers if not present (Number length is zero). */
++ struct rosePartyNumber served_user_number;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3k1Hz(3),
++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4),
++ * multirate(5),
++ * telephony3k1Hz(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * telephony7kHz(38),
++ * euroFileTransfer(39),
++ * fileTransferAndAccessManagement(40),
++ * videoconference(41),
++ * audioGraphicConference(42)
++ */
++ u_int8_t basic_service;
++};
++
++/*
++ * roseInterrogationDiversion_RES
++ * IntResultList ::= SET SIZE (0..29) OF IntResult
++ */
++struct roseEtsiForwardingList {
++ /*!
++ * \brief SET SIZE (0..29) OF Forwarding Records
++ * \note Reduced the size of the array to conserve
++ * potential stack usage.
++ */
++ struct roseEtsiForwardingRecord list[10];
++
++ /*! \brief Number of Forwarding records present */
++ u_int8_t num_records;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * diversionReason DiversionReason,
++ * basicService BasicService,
++ * servedUserSubaddress PartySubaddress OPTIONAL,
++ * callingAddress [0] EXPLICIT PresentedAddressScreened OPTIONAL,
++ * originalCalledNr [1] EXPLICIT PresentedNumberUnscreened OPTIONAL,
++ * lastDivertingNr [2] EXPLICIT PresentedNumberUnscreened OPTIONAL,
++ * lastDivertingReason [3] EXPLICIT DiversionReason OPTIONAL,
++ *
++ * -- The User-user information element, as specified
++ * -- in ETS 300 102-1 [11], subclause 4.5.29, shall
++ * -- be embedded in the userInfo parameter.
++ * userInfo Q931InformationElement OPTIONAL
++ * }
++ */
++struct roseEtsiDiversionInformation_ARG {
++ /*! \brief Served user subaddress (Optional) */
++ struct rosePartySubaddress served_user_subaddress;
++
++ /*! \brief Calling address (Optional) */
++ struct rosePresentedAddressScreened calling;
++
++ /*! \brief Original called number (Optional) */
++ struct rosePresentedNumberUnscreened original_called;
++
++ /*! \brief Last diverting number (Optional) */
++ struct rosePresentedNumberUnscreened last_diverting;
++
++ /*! \brief User-User information embedded in Q.931 IE (Optional) */
++ struct roseQ931ie q931ie;
++ /*! \brief q931ie.contents "allocated" after the stucture. */
++ unsigned char q931ie_contents[ROSE_Q931_MAX_USER + 1];
++
++ /*!
++ * \brief Last diverting reason (Optional)
++ *
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3),
++ * cdAlerting(4),
++ * cdImmediate(5)
++ */
++ u_int8_t last_diverting_reason;
++
++ /*! \brief TRUE if CallingAddress is present */
++ u_int8_t calling_present;
++
++ /*! \brief TRUE if OriginalCalled is present */
++ u_int8_t original_called_present;
++
++ /*! \brief TRUE if LastDiverting is present */
++ u_int8_t last_diverting_present;
++
++ /*! \brief TRUE if LastDivertingReason is present */
++ u_int8_t last_diverting_reason_present;
++
++ /*!
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3),
++ * cdAlerting(4),
++ * cdImmediate(5)
++ */
++ u_int8_t diversion_reason;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3k1Hz(3),
++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4),
++ * multirate(5),
++ * telephony3k1Hz(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * telephony7kHz(38),
++ * euroFileTransfer(39),
++ * fileTransferAndAccessManagement(40),
++ * videoconference(41),
++ * audioGraphicConference(42)
++ */
++ u_int8_t basic_service;
++};
++
++
++/*
++ * ARGUMENT SEQUENCE {
++ * deflectionAddress Address,
++ * presentationAllowedDivertedToUser PresentationAllowedIndicator OPTIONAL
++ * }
++ */
++struct roseEtsiCallDeflection_ARG {
++ /*! \brief Deflection address (Deflected-To address) */
++ struct roseAddress deflection;
++
++ /*! \brief TRUE if PresentationAllowedToDivertedToUser is present */
++ u_int8_t presentation_allowed_to_diverted_to_user_present;
++
++ /*! \brief TRUE if presentation is allowed (Optional) */
++ u_int8_t presentation_allowed_to_diverted_to_user;
++};
++
++
++/*
++ * ARGUMENT SEQUENCE {
++ * reroutingReason DiversionReason,
++ * calledAddress Address,
++ * reroutingCounter DiversionCounter,
++ *
++ * -- The User-user information element (optional),
++ * -- High layer compatibility information element (optional),
++ * -- Bearer capability information element
++ * -- and Low layer compatibility information element (optional)
++ * -- as specified in ETS 300 102-1 [11] subclause 4.5 shall be
++ * -- embedded in the q931InfoElement.
++ * q931InfoElement Q931InformationElement,
++ * lastReroutingNr [1] EXPLICIT PresentedNumberUnscreened,
++ * subscriptionOption [2] EXPLICIT SubscriptionOption DEFAULT noNotification,
++ * callingPartySubaddress [3] EXPLICIT PartySubaddress OPTIONAL
++ * }
++ */
++struct roseEtsiCallRerouting_ARG {
++ struct roseAddress called_address;
++
++ /*! \brief The BC, HLC (optional), LLC (optional), and User-user (optional) information */
++ struct roseQ931ie q931ie;
++ /*! \brief q931ie.contents "allocated" after the stucture. */
++ unsigned char q931ie_contents[ROSE_Q931_MAX_BC + ROSE_Q931_MAX_HLC +
++ ROSE_Q931_MAX_LLC + ROSE_Q931_MAX_USER + 1];
++
++ /*! \brief Last rerouting number */
++ struct rosePresentedNumberUnscreened last_rerouting;
++
++ /*! \brief Calling party subaddress (Optional) */
++ struct rosePartySubaddress calling_subaddress;
++
++ /*!
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3),
++ * cdAlerting(4),
++ * cdImmediate(5)
++ */
++ u_int8_t rerouting_reason;
++
++ /*! \brief Range 1-5 */
++ u_int8_t rerouting_counter;
++
++ /*!
++ * \details
++ * DEFAULT noNotification
++ *
++ * \details
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ */
++ u_int8_t subscription_option;
++};
++
++
++/*
++ * roseInterrogateServedUserNumbers_RES
++ * ServedUserNumberList ::= SET SIZE (0..99) OF PartyNumber
++ */
++struct roseEtsiServedUserNumberList {
++ /*!
++ * \brief SET SIZE (0..99) OF Served user numbers
++ * \note Reduced the size of the array to conserve
++ * potential stack usage.
++ */
++ struct rosePartyNumber number[20];
++
++ /*! \brief Number of Served user numbers present */
++ u_int8_t num_records;
++};
++
++
++/*
++ * ARGUMENT SEQUENCE {
++ * diversionReason DiversionReason,
++ * subscriptionOption SubscriptionOption,
++ * divertedToNumber PresentedNumberUnscreened OPTIONAL
++ * }
++ */
++struct roseEtsiDivertingLegInformation1_ARG {
++ /*! \brief Diverted to number (Optional) */
++ struct rosePresentedNumberUnscreened diverted_to;
++
++ /*! \brief TRUE if DivertedTo is present */
++ u_int8_t diverted_to_present;
++
++ /*!
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3),
++ * cdAlerting(4),
++ * cdImmediate(5)
++ */
++ u_int8_t diversion_reason;
++
++ /*!
++ * \details
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ */
++ u_int8_t subscription_option;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * diversionCounter DiversionCounter,
++ * diversionReason DiversionReason,
++ * divertingNr [1] EXPLICIT PresentedNumberUnscreened OPTIONAL,
++ * originalCalledNr [2] EXPLICIT PresentedNumberUnscreened OPTIONAL
++ * }
++ */
++struct roseEtsiDivertingLegInformation2_ARG {
++ /*! \brief Diverting number (Optional) */
++ struct rosePresentedNumberUnscreened diverting;
++
++ /*! \brief Original called number (Optional) */
++ struct rosePresentedNumberUnscreened original_called;
++
++ /*! \brief TRUE if Diverting number is present */
++ u_int8_t diverting_present;
++
++ /*! \brief TRUE if OriginalCalled is present */
++ u_int8_t original_called_present;
++
++ /*!
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3),
++ * cdAlerting(4),
++ * cdImmediate(5)
++ */
++ u_int8_t diversion_reason;
++
++ /*! \brief Range 1-5 */
++ u_int8_t diversion_counter;
++};
++
++/*
++ * ARGUMENT presentationAllowedIndicator PresentationAllowedIndicator
++ */
++struct roseEtsiDivertingLegInformation3_ARG {
++ /*! \brief TRUE if presentation is allowed */
++ u_int8_t presentation_allowed_indicator;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * ARGUMENT LinkId
++ */
++struct roseEtsiExplicitEctExecute_ARG {
++ int16_t link_id;
++};
++
++/*
++ * ARGUMENT transferredToSubaddress PartySubaddress
++ */
++struct roseEtsiSubaddressTransfer_ARG {
++ /*! \brief Transferred to subaddress */
++ struct rosePartySubaddress subaddress;
++};
++
++
++/*
++ * RESULT LinkId
++ */
++struct roseEtsiEctLinkIdRequest_RES {
++ int16_t link_id;
++};
++
++
++/*
++ * ARGUMENT SEQUENCE {
++ * ENUMERATED {
++ * alerting (0),
++ * active (1)
++ * },
++ * redirectionNumber PresentedNumberUnscreened OPTIONAL
++ * }
++ */
++struct roseEtsiEctInform_ARG {
++ /*! \brief Redirection Number (Optional) */
++ struct rosePresentedNumberUnscreened redirection;
++
++ /*! \brief TRUE if the Redirection Number is present */
++ u_int8_t redirection_present;
++
++ /*! \details alerting(0), active(1) */
++ u_int8_t status;
++};
++
++
++/*
++ * ARGUMENT CallTransferIdentity
++ */
++struct roseEtsiEctLoopTest_ARG {
++ int8_t call_transfer_id;
++};
++
++/*
++ * RESULT LoopResult
++ */
++struct roseEtsiEctLoopTest_RES {
++ /*!
++ * \details
++ * insufficientInformation(0),
++ * noLoopExists(1),
++ * simultaneousTransfer(2)
++ */
++ u_int8_t loop_result;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * Name ::= CHOICE {
++ * -- iso8859-1 is implied in namePresentationAllowedSimple.
++ * namePresentationAllowedSimple [0] IMPLICIT NameData,
++ * namePresentationAllowedExtended [1] IMPLICIT NameSet,
++ *
++ * -- iso8859-1 is implied in namePresentationRestrictedSimple.
++ * namePresentationRestrictedSimple [2] IMPLICIT NameData,
++ * namePresentationRestrictedExtended [3] IMPLICIT NameSet,
++ *
++ * -- namePresentationRestrictedNull shall only be used in the
++ * -- case of interworking where the other network provides an
++ * -- indication that the name is restricted without the name itself.
++ * namePresentationRestrictedNull [7] IMPLICIT NULL,
++ *
++ * nameNotAvailable [4] IMPLICIT NULL
++ * }
++ *
++ * NameSet ::= SEQUENCE {
++ * nameData NameData,
++ *
++ * -- If characterSet is not included, iso8859-1 is implied.
++ * characterSet CharacterSet OPTIONAL -- DEFAULT iso8859-1
++ * }
++ *
++ * -- The maximum allowed size of the name field is 50 octets.
++ * -- The minimum required size of the name field is 1 octet.
++ * NameData ::= OCTET STRING (SIZE (1..50))
++ */
++struct roseQsigName {
++ /*!
++ * \details
++ * optional_name_not_present(0),
++ * presentation_allowed(1),
++ * presentation_restricted(2),
++ * presentation_restricted_null(3),
++ * name_not_available(4)
++ */
++ u_int8_t presentation;
++
++ /*!
++ * \details
++ * Set to iso8859-1 if not present in the encoding.
++ *
++ * \details
++ * unknown(0),
++ * iso8859-1(1),
++ * enum-value-withdrawn-by-ITU-T(2)
++ * iso8859-2(3),
++ * iso8859-3(4),
++ * iso8859-4(5),
++ * iso8859-5(6),
++ * iso8859-7(7),
++ * iso10646-BmpString(8),
++ * iso10646-utf-8String(9)
++ */
++ u_int8_t char_set;
++
++ /*! \brief Length of name data */
++ u_int8_t length;
++
++ /*! \brief Name string data */
++ unsigned char data[50 + 1];
++};
++
++/*
++ * NOTE: We are not going to record the Extension information
++ * since it is manufacturer specific.
++ *
++ * ARGUMENT CHOICE {
++ * Name,
++ * SEQUENCE {
++ * Name,
++ * CHOICE {
++ * [5] IMPLICIT Extension,
++ * [6] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ * }
++ */
++struct roseQsigPartyName_ARG {
++ struct roseQsigName name;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * Time ::= SEQUENCE {
++ * lengthOfTimeUnit [1] IMPLICIT LengthOfTimeUnit,
++ * scale [2] IMPLICIT Scale
++ * }
++ */
++struct roseQsigAOCTime {
++ /*! LengthOfTimeUnit ::= INTEGER (0..16777215) -- 24 bit number */
++ u_int32_t length;
++ /*!
++ * \details
++ * oneHundredthSecond(0),
++ * oneTenthSecond(1),
++ * oneSecond(2),
++ * tenSeconds(3),
++ * oneMinute(4),
++ * oneHour(5),
++ * twentyFourHours(6)
++ */
++ u_int8_t scale;
++};
++
++/*
++ * Amount ::= SEQUENCE {
++ * currencyAmount [1] IMPLICIT CurrencyAmount,
++ * multiplier [2] IMPLICIT Multiplier
++ * }
++ */
++struct roseQsigAOCAmount {
++ /*! CurrencyAmount ::= INTEGER (0..16777215) -- 24 bit number */
++ u_int32_t currency;
++ /*!
++ * \details
++ * oneThousandth(0),
++ * oneHundredth(1),
++ * oneTenth(2),
++ * one(3),
++ * ten(4),
++ * hundred(5),
++ * thousand(6)
++ */
++ u_int8_t multiplier;
++};
++
++/*
++ * DurationCurrency ::= SEQUENCE {
++ * dCurrency [1] IMPLICIT Currency,
++ * dAmount [2] IMPLICIT Amount,
++ * dChargingType [3] IMPLICIT ChargingType,
++ * dTime [4] IMPLICIT Time,
++ * dGranularity [5] IMPLICIT Time OPTIONAL
++ * }
++ */
++struct roseQsigAOCDurationCurrency {
++ struct roseQsigAOCAmount amount;
++ struct roseQsigAOCTime time;
++ /*! \brief dGranularity (optional) */
++ struct roseQsigAOCTime granularity;
++ /*!
++ * \brief Name of currency
++ * \details
++ * Currency ::= IA5String (SIZE (0..10))
++ * \note The empty string is the default currency for the network.
++ */
++ unsigned char currency[10 + 1];
++ /*!
++ * \details
++ * continuousCharging(0),
++ * stepFunction(1)
++ */
++ u_int8_t charging_type;
++ /*! TRUE if granularity time is present */
++ u_int8_t granularity_present;
++};
++
++/*
++ * FlatRateCurrency ::= SEQUENCE {
++ * fRCurrency [1] IMPLICIT Currency,
++ * fRAmount [2] IMPLICIT Amount
++ * }
++ */
++struct roseQsigAOCFlatRateCurrency {
++ struct roseQsigAOCAmount amount;
++ /*!
++ * \brief Name of currency
++ * \details
++ * Currency ::= IA5String (SIZE (0..10))
++ * \note The empty string is the default currency for the network.
++ */
++ unsigned char currency[10 + 1];
++};
++
++/*
++ * VolumeRateCurrency ::= SEQUENCE {
++ * vRCurrency [1] IMPLICIT Currency,
++ * vRAmount [2] IMPLICIT Amount,
++ * vRVolumeUnit [3] IMPLICIT VolumeUnit
++ * }
++ */
++struct roseQsigAOCVolumeRateCurrency {
++ struct roseQsigAOCAmount amount;
++ /*!
++ * \brief Name of currency
++ * \details
++ * Currency ::= IA5String (SIZE (0..10))
++ * \note The empty string is the default currency for the network.
++ */
++ unsigned char currency[10 + 1];
++ /*!
++ * \brief Volume rate volume unit
++ * \details
++ * octet(0),
++ * segment(1),
++ * message(2)
++ */
++ u_int8_t unit;
++};
++
++/*
++ * AOCSCurrencyInfo ::= SEQUENCE {
++ * chargedItem ChargedItem,
++ * rateType CHOICE {
++ * durationCurrency [1] IMPLICIT DurationCurrency,
++ * flatRateCurrency [2] IMPLICIT FlatRateCurrency,
++ * volumeRateCurrency [3] IMPLICIT VolumeRateCurrency,
++ * specialChargingCode SpecialChargingCode,
++ * freeOfCharge [4] IMPLICIT NULL,
++ * currencyInfoNotAvailable [5] IMPLICIT NULL,
++ * freeOfChargefromBeginning [6] IMPLICIT NULL
++ * }
++ * }
++ */
++struct roseQsigAOCSCurrencyInfo {
++ union {
++ struct roseQsigAOCDurationCurrency duration;
++ struct roseQsigAOCFlatRateCurrency flat_rate;
++ struct roseQsigAOCVolumeRateCurrency volume_rate;
++ /*! SpecialChargingCode ::= INTEGER (1..10) */
++ u_int8_t special_charging_code;
++ } u;
++ /*!
++ * \brief Determine what is stored in the union.
++ * \details
++ * specialChargingCode(0),
++ * durationCurrency(1),
++ * flatRateCurrency(2),
++ * volumeRateCurrency(3),
++ * freeOfCharge(4),
++ * currencyInfoNotAvailable(5),
++ * freeOfChargeFromBeginning(6)
++ */
++ u_int8_t currency_type;
++ /*!
++ * \brief What service is being billed.
++ * \details
++ * basicCommunication(0),
++ * callAttempt(1),
++ * callSetup(2),
++ * userToUserInfo(3),
++ * operationOfSupplementaryServ(4)
++ */
++ u_int8_t charged_item;
++};
++
++/*
++ * AOCSCurrencyInfoList ::= SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo
++ */
++struct roseQsigAOCSCurrencyInfoList {
++ /*! \brief SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo */
++ struct roseQsigAOCSCurrencyInfo list[10];
++
++ /*! \brief Number of AOCSCurrencyInfo records present */
++ u_int8_t num_records;
++};
++
++/*
++ * RecordedCurrency ::= SEQUENCE {
++ * rCurrency [1] IMPLICIT Currency,
++ * rAmount [2] IMPLICIT Amount
++ * }
++ */
++struct roseQsigAOCRecordedCurrency {
++ /*! Amount of currency involved. */
++ struct roseQsigAOCAmount amount;
++ /*!
++ * \brief Name of currency
++ * \details
++ * Currency ::= IA5String (SIZE (0..10))
++ * \note The empty string is the default currency for the network.
++ */
++ unsigned char currency[10 + 1];
++};
++
++/*
++ * ChargingAssociation ::= CHOICE {
++ * chargedNumber [0] EXPLICIT PartyNumber,
++ * chargeIdentifier ChargeIdentifier
++ * }
++ */
++struct roseQsigAOCChargingAssociation {
++ /*! chargeIdentifier: INTEGER (-32768..32767) -- 16 bit number */
++ int16_t id;
++ /*! chargedNumber */
++ struct rosePartyNumber number;
++ /*!
++ * \details
++ * charge_identifier(0)
++ * charged_number(1),
++ */
++ u_int8_t type;
++};
++
++/*
++ * AocRateArg ::= SEQUENCE {
++ * aocRate CHOICE
++ * {
++ * chargeNotAvailable NULL,
++ * aocSCurrencyInfoList AOCSCurrencyInfoList
++ * },
++ * rateArgExtension CHOICE {
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigAocRateArg_ARG {
++ struct roseQsigAOCSCurrencyInfoList currency_info;
++ /*!
++ * \details
++ * charge_not_available(0),
++ * currency_info_list(1)
++ */
++ u_int8_t type;
++};
++
++/*
++ * AocInterimArg ::= SEQUENCE {
++ * interimCharge CHOICE {
++ * chargeNotAvailable [0] IMPLICIT NULL,
++ * freeOfCharge [1] IMPLICIT NULL,
++ * specificCurrency SEQUENCE {
++ * recordedCurrency [1] IMPLICIT RecordedCurrency,
++ * interimBillingId [2] IMPLICIT InterimBillingId OPTIONAL
++ * }
++ * },
++ * interimArgExtension CHOICE {
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigAocInterimArg_ARG {
++ struct {
++ /*! \brief recorded currency */
++ struct roseQsigAOCRecordedCurrency recorded;
++ /*!
++ * \brief InterimBillingId (optional)
++ * \details
++ * normalCharging(0),
++ * creditCardCharging(2)
++ */
++ u_int8_t billing_id;
++ /*! \brief TRUE if billing id is present */
++ u_int8_t billing_id_present;
++ } specific;
++ /*!
++ * \details
++ * charge_not_available(0),
++ * free_of_charge(1),
++ * specific_currency(2)
++ */
++ u_int8_t type;
++};
++
++/*
++ * AocFinalArg ::= SEQUENCE {
++ * finalCharge CHOICE {
++ * chargeNotAvailable [0] IMPLICIT NULL,
++ * freeOfCharge [1] IMPLICIT NULL,
++ * specificCurrency SEQUENCE {
++ * recordedCurrency [1] IMPLICIT RecordedCurrency,
++ * finalBillingId [2] IMPLICIT FinalBillingId OPTIONAL
++ * }
++ * },
++ * chargingAssociation ChargingAssociation OPTIONAL,
++ * finalArgExtension CHOICE {
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigAocFinalArg_ARG {
++ struct {
++ /*! \brief recorded currency */
++ struct roseQsigAOCRecordedCurrency recorded;
++ /*!
++ * \brief FinalBillingId (optional)
++ * \details
++ * normalCharging(0),
++ * creditCardCharging(2),
++ * callForwardingUnconditional(3),
++ * callForwardingBusy(4),
++ * callForwardingNoReply(5),
++ * callDeflection(6),
++ * callTransfer(7)
++ */
++ u_int8_t billing_id;
++ /*! \brief TRUE if billing id is present */
++ u_int8_t billing_id_present;
++ } specific;
++
++ /*! \brief chargingAssociation (optional) */
++ struct roseQsigAOCChargingAssociation charging_association;
++
++ /*! \brief TRUE if charging_association is present */
++ u_int8_t charging_association_present;
++
++ /*!
++ * \details
++ * charge_not_available(0),
++ * free_of_charge(1),
++ * specific_currency(2)
++ */
++ u_int8_t type;
++};
++
++/*
++ * ChargeRequestArg ::= SEQUENCE {
++ * adviceModeCombinations SEQUENCE SIZE(0..7) OF AdviceModeCombination,
++ * chargeReqArgExtension CHOICE {
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigChargeRequestArg_ARG {
++ /*!
++ * \brief SEQUENCE SIZE(0..7) OF AdviceModeCombination
++ * \details
++ * rate(0) <charge rate provision>,
++ * rateInterim(1) <charge rate and interim charge provision>,
++ * rateFinal(2) <charge rate and final charge provision>,
++ * interim(3) <interim charge provision>,
++ * final(4) <final charge provision>,
++ * interimFinal(5) <interim charge and final charge provision>,
++ * rateInterimFinal(6) <charge rate, interim charge and final charge provision>
++ */
++ u_int8_t advice_mode_combinations[7];
++
++ /*! \brief Number of AdviceModeCombination values present */
++ u_int8_t num_records;
++};
++
++/*
++ * ChargeRequestRes ::= SEQUENCE {
++ * adviceModeCombination AdviceModeCombination,
++ * chargeReqResExtension CHOICE {
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigChargeRequestRes_RES {
++ /*!
++ * \details
++ * rate(0) <charge rate provision>,
++ * rateInterim(1) <charge rate and interim charge provision>,
++ * rateFinal(2) <charge rate and final charge provision>,
++ * interim(3) <interim charge provision>,
++ * final(4) <final charge provision>,
++ * interimFinal(5) <interim charge and final charge provision>,
++ * rateInterimFinal(6) <charge rate, interim charge and final charge provision>
++ */
++ u_int8_t advice_mode_combination;
++};
++
++/*
++ * AocCompleteArg ::= SEQUENCE {
++ * chargedUser PartyNumber,
++ * chargingAssociation ChargingAssociation OPTIONAL,
++ * completeArgExtension CHOICE {
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigAocCompleteArg_ARG {
++ /*! \brief chargingAssociation (optional) */
++ struct roseQsigAOCChargingAssociation charging_association;
++
++ struct rosePartyNumber charged_user_number;
++
++ /*! \brief TRUE if charging_association is present */
++ u_int8_t charging_association_present;
++};
++
++/*
++ * AocCompleteRes ::= SEQUENCE {
++ * chargingOption ChargingOption,
++ * completeResExtension CHOICE {
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigAocCompleteRes_RES {
++ /*!
++ * \details
++ * aocFreeOfCharge(0),
++ * aocContinueCharging(1),
++ * aocStopCharging(2)
++ */
++ u_int8_t charging_option;
++};
++
++/*
++ * AocDivChargeReqArg ::= SEQUENCE {
++ * divertingUser PartyNumber,
++ * chargingAssociation ChargingAssociation OPTIONAL,
++ * diversionType DiversionType,
++ * aocDivChargeReqArgExt CHOICE {
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigAocDivChargeReqArg_ARG {
++ /*! \brief chargingAssociation (optional) */
++ struct roseQsigAOCChargingAssociation charging_association;
++
++ struct rosePartyNumber diverting_user_number;
++
++ /*! \brief TRUE if charging_association is present */
++ u_int8_t charging_association_present;
++
++ /*!
++ * \details
++ * callForwardingUnconditional(0),
++ * callForwardingBusy(1),
++ * callForwardingNoReply(2),
++ * callDeflection(3)
++ */
++ u_int8_t diversion_type;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * CTIdentifyRes ::= SEQUENCE {
++ * callIdentity CallIdentity,
++ * reroutingNumber PartyNumber,
++ * resultExtension CHOICE {
++ * [6] IMPLICIT Extension,
++ * [7] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigCTIdentifyRes_RES {
++ struct rosePartyNumber rerouting_number;
++
++ /*! \brief CallIdentity ::= NumericString (SIZE (1..4)) */
++ unsigned char call_id[4 + 1];
++};
++
++/*
++ * CTInitiateArg ::= SEQUENCE {
++ * callIdentity CallIdentity,
++ * reroutingNumber PartyNumber,
++ * argumentExtension CHOICE {
++ * [6] IMPLICIT Extension,
++ * [7] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigCTInitiateArg_ARG {
++ struct rosePartyNumber rerouting_number;
++
++ /*! \brief CallIdentity ::= NumericString (SIZE (1..4)) */
++ unsigned char call_id[4 + 1];
++};
++
++/*
++ * CTSetupArg ::= SEQUENCE {
++ * callIdentity CallIdentity,
++ * argumentExtension CHOICE {
++ * [0] IMPLICIT Extension,
++ * [1] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigCTSetupArg_ARG {
++ /*! \brief CallIdentity ::= NumericString (SIZE (1..4)) */
++ unsigned char call_id[4 + 1];
++};
++
++/*
++ * CTActiveArg ::= SEQUENCE {
++ * connectedAddress PresentedAddressScreened,
++ *
++ * -- ISO/IEC 11572 information elements Party
++ * -- category and Progress indicator are conveyed
++ * basicCallInfoElements PSS1InformationElement OPTIONAL,
++ * connectedName Name OPTIONAL,
++ * argumentExtension CHOICE {
++ * [9] IMPLICIT Extension,
++ * [10] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigCTActiveArg_ARG {
++ /*! \brief connectedAddress */
++ struct rosePresentedAddressScreened connected;
++
++ /*! \brief basicCallInfoElements (optional) */
++ struct roseQ931ie q931ie;
++ /*! \brief q931ie.contents "allocated" after the stucture. */
++ unsigned char q931ie_contents[ROSE_Q931_MAX_PROGRESS + 1];
++
++ /*! \brief connectedName (optional) */
++ struct roseQsigName connected_name;
++
++ /*! \brief TRUE if connected_name is present */
++ u_int8_t connected_name_present;
++};
++
++/*
++ * CTCompleteArg ::= SEQUENCE {
++ * endDesignation EndDesignation,
++ * redirectionNumber PresentedNumberScreened,
++ *
++ * -- ISO/IEC 11572 information elements Party
++ * -- category and Progress indicator are conveyed
++ * basicCallInfoElements PSS1InformationElement OPTIONAL,
++ * redirectionName Name OPTIONAL,
++ * callStatus CallStatus DEFAULT answered,
++ * argumentExtension CHOICE {
++ * [9] IMPLICIT Extension,
++ * [10] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigCTCompleteArg_ARG {
++ /*! \brief redirectionNumber */
++ struct rosePresentedNumberScreened redirection;
++
++ /*! \brief basicCallInfoElements (optional) */
++ struct roseQ931ie q931ie;
++ /*! \brief q931ie.contents "allocated" after the stucture. */
++ unsigned char q931ie_contents[ROSE_Q931_MAX_PROGRESS + 1];
++
++ /*! \brief redirectionName (optional) */
++ struct roseQsigName redirection_name;
++
++ /*! \brief TRUE if redirection_name is present */
++ u_int8_t redirection_name_present;
++
++ /*!
++ * \brief endDesignation
++ * \details
++ * primaryEnd(0),
++ * secondaryEnd(1)
++ */
++ u_int8_t end_designation;
++
++ /*!
++ * \brief callStatus
++ * \details
++ * DEFAULT answered
++ *
++ * \details
++ * answered(0),
++ * alerting(1)
++ */
++ u_int8_t call_status;
++};
++
++/*
++ * CTUpdateArg ::= SEQUENCE {
++ * redirectionNumber PresentedNumberScreened,
++ * redirectionName Name OPTIONAL,
++ *
++ * -- ISO/IEC 11572 information elements Party
++ * -- category and Progress indicator are conveyed
++ * basicCallInfoElements PSS1InformationElement OPTIONAL,
++ * argumentExtension CHOICE {
++ * [9] IMPLICIT Extension,
++ * [10] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigCTUpdateArg_ARG {
++ /*! \brief redirectionNumber */
++ struct rosePresentedNumberScreened redirection;
++
++ /*! \brief basicCallInfoElements (optional) */
++ struct roseQ931ie q931ie;
++ /*! \brief q931ie.contents "allocated" after the stucture. */
++ unsigned char q931ie_contents[ROSE_Q931_MAX_PROGRESS + 1];
++
++ /*! \brief redirectionName (optional) */
++ struct roseQsigName redirection_name;
++
++ /*! \brief TRUE if redirection_name is present */
++ u_int8_t redirection_name_present;
++};
++
++/*
++ * SubaddressTransferArg ::= SEQUENCE {
++ * redirectionSubaddress PartySubaddress,
++ * argumentExtension CHOICE {
++ * [0] IMPLICIT Extension,
++ * [1] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigSubaddressTransferArg_ARG {
++ struct rosePartySubaddress redirection_subaddress;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * IntResult ::= SEQUENCE {
++ * servedUserNr PartyNumber,
++ * basicService BasicService,
++ * procedure Procedure,
++ * divertedToAddress Address,
++ * remoteEnabled BOOLEAN DEFAULT FALSE,
++ * extension CHOICE {
++ * [1] IMPLICIT Extension,
++ * [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigForwardingRecord {
++ /*! \brief Diverted to address */
++ struct roseAddress diverted_to;
++
++ struct rosePartyNumber served_user_number;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3100Hz(3),
++ * telephony(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36)
++ */
++ u_int8_t basic_service;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*! \brief remoteEnabled BOOLEAN DEFAULT FALSE */
++ u_int8_t remote_enabled;
++};
++
++/*
++ * roseQsigInterrogateDiversionQ_REQ
++ * IntResultList ::= SET SIZE (0..29) OF IntResult
++ */
++struct roseQsigForwardingList {
++ /*!
++ * \brief SET SIZE (0..29) OF Forwarding Records
++ * \note Reduced the size of the array to conserve
++ * potential stack usage.
++ */
++ struct roseQsigForwardingRecord list[10];
++
++ /*! \brief Number of Forwarding records present */
++ u_int8_t num_records;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * procedure Procedure,
++ * basicService BasicService,
++ * divertedToAddress Address,
++ * servedUserNr PartyNumber,
++ * activatingUserNr PartyNumber,
++ * extension CHOICE {
++ * [1] IMPLICIT Extension,
++ * [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigActivateDiversionQ_ARG {
++ /*! \brief divertedToAddress */
++ struct roseAddress diverted_to;
++
++ struct rosePartyNumber served_user_number;
++ struct rosePartyNumber activating_user_number;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3100Hz(3),
++ * telephony(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36)
++ */
++ u_int8_t basic_service;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * procedure Procedure,
++ * basicService BasicService,
++ * servedUserNr PartyNumber,
++ * deactivatingUserNr PartyNumber,
++ * extension CHOICE {
++ * [1] IMPLICIT Extension,
++ * [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigDeactivateDiversionQ_ARG {
++ struct rosePartyNumber served_user_number;
++ struct rosePartyNumber deactivating_user_number;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3100Hz(3),
++ * telephony(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36)
++ */
++ u_int8_t basic_service;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * procedure Procedure,
++ * basicService BasicService DEFAULT allServices,
++ * servedUserNr PartyNumber,
++ * interrogatingUserNr PartyNumber,
++ * extension CHOICE {
++ * [1] IMPLICIT Extension,
++ * [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigInterrogateDiversionQ_ARG {
++ struct rosePartyNumber served_user_number;
++ struct rosePartyNumber interrogating_user_number;
++
++ /*! \details cfu(0), cfb(1), cfnr(2) */
++ u_int8_t procedure;
++
++ /*!
++ * \details
++ * DEFAULT allServices
++ *
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3100Hz(3),
++ * telephony(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36)
++ */
++ u_int8_t basic_service;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * servedUserNr PartyNumber,
++ * basicService BasicService,
++ * divertedToNr PartyNumber,
++ * extension CHOICE {
++ * [1] IMPLICIT Extension,
++ * [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigCheckRestriction_ARG {
++ struct rosePartyNumber served_user_number;
++ struct rosePartyNumber diverted_to_number;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3100Hz(3),
++ * telephony(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotexSyntaxBased(35),
++ * videotelephony(36)
++ */
++ u_int8_t basic_service;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * reroutingReason DiversionReason,
++ * originalReroutingReason [0] IMPLICIT DiversionReason OPTIONAL,
++ * calledAddress Address,
++ * diversionCounter INTEGER (1..15),
++ *
++ * -- The basic call information elements Bearer capability,
++ * -- High layer compatibility, Low layer compatibity
++ * -- and Progress indicator can be embedded in the
++ * -- pSS1InfoElement in accordance with 6.5.3.1.5.
++ * pSS1InfoElement PSS1InformationElement,
++ * lastReroutingNr [1] EXPLICIT PresentedNumberUnscreened,
++ * subscriptionOption [2] IMPLICIT SubscriptionOption,
++ * callingPartySubaddress [3] EXPLICIT PartySubaddress OPTIONAL,
++ * callingNumber [4] EXPLICIT PresentedNumberScreened,
++ * callingName [5] EXPLICIT Name OPTIONAL,
++ * originalCalledNr [6] EXPLICIT PresentedNumberUnscreened OPTIONAL,
++ * redirectingName [7] EXPLICIT Name OPTIONAL,
++ * originalCalledName [8] EXPLICIT Name OPTIONAL,
++ * extension CHOICE {
++ * [9] IMPLICIT Extension,
++ * [10] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigCallRerouting_ARG {
++ /*! \brief calledAddress */
++ struct roseAddress called;
++
++ /*! \brief lastReroutingNr */
++ struct rosePresentedNumberUnscreened last_rerouting;
++
++ /*! \brief originalCalledNr (optional) */
++ struct rosePresentedNumberUnscreened original_called;
++
++ /*!
++ * \brief callingPartySubaddress (optional)
++ * The subaddress is present if the length is nonzero.
++ */
++ struct rosePartySubaddress calling_subaddress;
++
++ /*! \brief callingNumber */
++ struct rosePresentedNumberScreened calling;
++
++ /*! \brief callingName (optional) */
++ struct roseQsigName calling_name;
++
++ /*! \brief redirectingName (optional) */
++ struct roseQsigName redirecting_name;
++
++ /*! \brief originalCalledName (optional) */
++ struct roseQsigName original_called_name;
++
++ /*!
++ * \brief The BC, HLC (optional), LLC (optional),
++ * and progress indicator(s) information.
++ */
++ struct roseQ931ie q931ie;
++ /*! \brief q931ie.contents "allocated" after the stucture. */
++ unsigned char q931ie_contents[ROSE_Q931_MAX_BC + ROSE_Q931_MAX_HLC +
++ ROSE_Q931_MAX_LLC + ROSE_Q931_MAX_PROGRESS + 1];
++
++ /*! \brief TRUE if calling_name is present */
++ u_int8_t calling_name_present;
++
++ /*! \brief TRUE if redirecting_name is present */
++ u_int8_t redirecting_name_present;
++
++ /*! \brief TRUE if original_called_name is present */
++ u_int8_t original_called_name_present;
++
++ /*! \brief TRUE if original_called number is present */
++ u_int8_t original_called_present;
++
++ /*!
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3)
++ *
++ * \note The value unknown is only used if received from
++ * another network when interworking.
++ */
++ u_int8_t rerouting_reason;
++
++ /*!
++ * \brief originalReroutingReason (optional)
++ *
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3)
++ *
++ * \note The value unknown is only used if received from
++ * another network when interworking.
++ */
++ u_int8_t original_rerouting_reason;
++
++ /*! \brief TRUE if original_rerouting_reason is present */
++ u_int8_t original_rerouting_reason_present;
++
++ /*! \brief diversionCounter INTEGER (1..15) */
++ u_int8_t diversion_counter;
++
++ /*!
++ * \brief subscriptionOption
++ *
++ * \details
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ */
++ u_int8_t subscription_option;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * diversionReason DiversionReason,
++ * subscriptionOption SubscriptionOption,
++ * nominatedNr PartyNumber,
++ * extension CHOICE {
++ * [9] IMPLICIT Extension,
++ * [10] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigDivertingLegInformation1_ARG {
++ struct rosePartyNumber nominated_number;
++
++ /*!
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3)
++ *
++ * \note The value unknown is only used if received from
++ * another network when interworking.
++ */
++ u_int8_t diversion_reason;
++
++ /*!
++ * \brief subscriptionOption
++ *
++ * \details
++ * noNotification(0),
++ * notificationWithoutDivertedToNr(1),
++ * notificationWithDivertedToNr(2)
++ */
++ u_int8_t subscription_option;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * diversionCounter INTEGER (1..15),
++ * diversionReason DiversionReason,
++ * originalDiversionReason [0] IMPLICIT DiversionReason OPTIONAL,
++ *
++ * -- The divertingNr element is mandatory except in the case
++ * -- of interworking.
++ * divertingNr [1] EXPLICIT PresentedNumberUnscreened OPTIONAL,
++ * originalCalledNr [2] EXPLICIT PresentedNumberUnscreened OPTIONAL,
++ * redirectingName [3] EXPLICIT Name OPTIONAL,
++ * originalCalledName [4] EXPLICIT Name OPTIONAL,
++ * extension CHOICE {
++ * [5] IMPLICIT Extension,
++ * [6] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigDivertingLegInformation2_ARG {
++ /*! \brief divertingNr (optional) */
++ struct rosePresentedNumberUnscreened diverting;
++
++ /*! \brief originalCalledNr (optional) */
++ struct rosePresentedNumberUnscreened original_called;
++
++ /*! \brief redirectingName (optional) */
++ struct roseQsigName redirecting_name;
++
++ /*! \brief originalCalledName (optional) */
++ struct roseQsigName original_called_name;
++
++ /*! \brief diversionCounter INTEGER (1..15) */
++ u_int8_t diversion_counter;
++
++ /*!
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3)
++ *
++ * \note The value unknown is only used if received from
++ * another network when interworking.
++ */
++ u_int8_t diversion_reason;
++
++ /*!
++ * \brief originalDiversionReason (optional)
++ *
++ * \details
++ * unknown(0),
++ * cfu(1),
++ * cfb(2),
++ * cfnr(3)
++ *
++ * \note The value unknown is only used if received from
++ * another network when interworking.
++ */
++ u_int8_t original_diversion_reason;
++
++ /*! \brief TRUE if original_diversion_reason is present */
++ u_int8_t original_diversion_reason_present;
++
++ /*! \brief TRUE if diverting number is present */
++ u_int8_t diverting_present;
++
++ /*! \brief TRUE if original_called number is present */
++ u_int8_t original_called_present;
++
++ /*! \brief TRUE if redirecting_name is present */
++ u_int8_t redirecting_name_present;
++
++ /*! \brief TRUE if original_called_name is present */
++ u_int8_t original_called_name_present;
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * presentationAllowedIndicator PresentationAllowedIndicator, -- BOOLEAN
++ * redirectionName [0] EXPLICIT Name OPTIONAL,
++ * extension CHOICE {
++ * [1] IMPLICIT Extension,
++ * [2] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigDivertingLegInformation3_ARG {
++ /*! \brief redirectionName (optional) */
++ struct roseQsigName redirection_name;
++
++ /*! \brief TRUE if redirection_name is present */
++ u_int8_t redirection_name_present;
++
++ /*! \brief TRUE if presentation is allowed */
++ u_int8_t presentation_allowed_indicator;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * MsgCentreId ::= CHOICE {
++ * integer [0] IMPLICIT INTEGER (0..65535),
++ *
++ * -- The party number must be a complete number as required
++ * -- for routing purposes.
++ * partyNumber [1] EXPLICIT PartyNumber,
++ * numericString [2] IMPLICIT NumericString (SIZE (1..10))
++ * }
++ */
++struct roseQsigMsgCentreId {
++ union {
++ /*! \brief INTEGER (0..65535) */
++ u_int16_t integer;
++
++ /*!
++ * \note The party number must be a complete number as required
++ * for routing purposes.
++ */
++ struct rosePartyNumber number;
++
++ /*! \brief NumericString (SIZE (1..10)) */
++ unsigned char str[10 + 1];
++ } u;
++
++ /*!
++ * \details
++ * integer(0),
++ * partyNumber(1),
++ * numericString(2)
++ */
++ u_int8_t type;
++};
++
++/*
++ * MWIActivateArg ::= SEQUENCE {
++ * servedUserNr PartyNumber,
++ * basicService BasicService,
++ * msgCentreId MsgCentreId OPTIONAL,
++ * nbOfMessages [3] IMPLICIT NbOfMessages OPTIONAL,
++ * originatingNr [4] EXPLICIT PartyNumber OPTIONAL,
++ * timestamp TimeStamp OPTIONAL,
++ *
++ * -- The value 0 means the highest priority and 9 the lowest
++ * priority [5] IMPLICIT INTEGER (0..9) OPTIONAL,
++ * argumentExt CHOICE {
++ * extension [6] IMPLICIT Extension,
++ * multipleExtension [7] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigMWIActivateArg {
++ /*! \brief NbOfMessages ::= INTEGER (0..65535) (optional) */
++ u_int16_t number_of_messages;
++
++ /*! \brief msgCentreId (optional) */
++ struct roseQsigMsgCentreId msg_centre_id;
++
++ struct rosePartyNumber served_user_number;
++
++ /*! \brief originatingNr (optional) (Number present if length is nonzero) */
++ struct rosePartyNumber originating_number;
++
++ /*! \brief GeneralizedTime (SIZE (12..19)) (optional) */
++ unsigned char timestamp[19 + 1];
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3100Hz(3),
++ * telephony(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotextSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * reservedNotUsed1(38),
++ * reservedNotUsed2(39),
++ * reservedNotUsed3(40),
++ * reservedNotUsed4(41),
++ * reservedNotUsed5(42),
++ * email(51),
++ * video(52),
++ * fileTransfer(53),
++ * shortMessageService(54),
++ * speechAndVideo(55),
++ * speechAndFax(56),
++ * speechAndEmail(57),
++ * videoAndFax(58),
++ * videoAndEmail(59),
++ * faxAndEmail(60),
++ * speechVideoAndFax(61),
++ * speechVideoAndEmail(62),
++ * speechFaxAndEmail(63),
++ * videoFaxAndEmail(64),
++ * speechVideoFaxAndEmail(65),
++ * multimediaUnknown(66),
++ * serviceUnknown(67),
++ * futureReserve1(68),
++ * futureReserve2(69),
++ * futureReserve3(70),
++ * futureReserve4(71),
++ * futureReserve5(72),
++ * futureReserve6(73),
++ * futureReserve7(74),
++ * futureReserve8(75)
++ */
++ u_int8_t basic_service;
++
++ /*!
++ * \brief INTEGER (0..9) (optional)
++ * \note The value 0 means the highest priority and 9 the lowest.
++ */
++ u_int8_t priority;
++
++ /*! \brief TRUE if msg_centre_id is present */
++ u_int8_t msg_centre_id_present;
++
++ /*! \brief TRUE if number_of_messages is present */
++ u_int8_t number_of_messages_present;
++
++ /*! \brief TRUE if timestamp is present */
++ u_int8_t timestamp_present;
++
++ /*! \brief TRUE if priority is present */
++ u_int8_t priority_present;
++};
++
++/*
++ * MWIDeactivateArg ::= SEQUENCE {
++ * servedUserNr PartyNumber,
++ * basicService BasicService,
++ * msgCentreId MsgCentreId OPTIONAL,
++ * argumentExt CHOICE {
++ * extension [3] IMPLICIT Extension,
++ * multipleExtension [4] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigMWIDeactivateArg {
++ /*! \brief msgCentreId (optional) */
++ struct roseQsigMsgCentreId msg_centre_id;
++
++ struct rosePartyNumber served_user_number;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3100Hz(3),
++ * telephony(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotextSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * reservedNotUsed1(38),
++ * reservedNotUsed2(39),
++ * reservedNotUsed3(40),
++ * reservedNotUsed4(41),
++ * reservedNotUsed5(42),
++ * email(51),
++ * video(52),
++ * fileTransfer(53),
++ * shortMessageService(54),
++ * speechAndVideo(55),
++ * speechAndFax(56),
++ * speechAndEmail(57),
++ * videoAndFax(58),
++ * videoAndEmail(59),
++ * faxAndEmail(60),
++ * speechVideoAndFax(61),
++ * speechVideoAndEmail(62),
++ * speechFaxAndEmail(63),
++ * videoFaxAndEmail(64),
++ * speechVideoFaxAndEmail(65),
++ * multimediaUnknown(66),
++ * serviceUnknown(67),
++ * futureReserve1(68),
++ * futureReserve2(69),
++ * futureReserve3(70),
++ * futureReserve4(71),
++ * futureReserve5(72),
++ * futureReserve6(73),
++ * futureReserve7(74),
++ * futureReserve8(75)
++ */
++ u_int8_t basic_service;
++
++ /*! \brief TRUE if msg_centre_id is present */
++ u_int8_t msg_centre_id_present;
++};
++
++/*
++ * MWIInterrogateArg ::= SEQUENCE {
++ * servedUserNr PartyNumber,
++ * basicService BasicService,
++ * msgCentreId MsgCentreId OPTIONAL,
++ * argumentExt CHOICE {
++ * extension [3] IMPLICIT Extension,
++ * multipleExtension [4] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigMWIInterrogateArg {
++ /*! \brief msgCentreId (optional) */
++ struct roseQsigMsgCentreId msg_centre_id;
++
++ struct rosePartyNumber served_user_number;
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3100Hz(3),
++ * telephony(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotextSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * reservedNotUsed1(38),
++ * reservedNotUsed2(39),
++ * reservedNotUsed3(40),
++ * reservedNotUsed4(41),
++ * reservedNotUsed5(42),
++ * email(51),
++ * video(52),
++ * fileTransfer(53),
++ * shortMessageService(54),
++ * speechAndVideo(55),
++ * speechAndFax(56),
++ * speechAndEmail(57),
++ * videoAndFax(58),
++ * videoAndEmail(59),
++ * faxAndEmail(60),
++ * speechVideoAndFax(61),
++ * speechVideoAndEmail(62),
++ * speechFaxAndEmail(63),
++ * videoFaxAndEmail(64),
++ * speechVideoFaxAndEmail(65),
++ * multimediaUnknown(66),
++ * serviceUnknown(67),
++ * futureReserve1(68),
++ * futureReserve2(69),
++ * futureReserve3(70),
++ * futureReserve4(71),
++ * futureReserve5(72),
++ * futureReserve6(73),
++ * futureReserve7(74),
++ * futureReserve8(75)
++ */
++ u_int8_t basic_service;
++
++ /*! \brief TRUE if msg_centre_id is present */
++ u_int8_t msg_centre_id_present;
++};
++
++/*
++ * MWIInterrogateResElt ::= SEQUENCE {
++ * basicService BasicService,
++ * msgCentreId MsgCentreId OPTIONAL,
++ * nbOfMessages [3] IMPLICIT NbOfMessages OPTIONAL,
++ * originatingNr [4] EXPLICIT PartyNumber OPTIONAL,
++ * timestamp TimeStamp OPTIONAL,
++ *
++ * -- The value 0 means the highest priority and 9 the lowest
++ * priority [5] IMPLICIT INTEGER (0..9) OPTIONAL,
++ * argumentExt CHOICE {
++ * extension [6] IMPLICIT Extension,
++ * multipleExtension [7] IMPLICIT SEQUENCE OF Extension
++ * } OPTIONAL
++ * }
++ */
++struct roseQsigMWIInterrogateResElt {
++ /*! \brief NbOfMessages ::= INTEGER (0..65535) (optional) */
++ u_int16_t number_of_messages;
++
++ /*! \brief msgCentreId (optional) */
++ struct roseQsigMsgCentreId msg_centre_id;
++
++ /*! \brief originatingNr (optional) (Number present if length is nonzero) */
++ struct rosePartyNumber originating_number;
++
++ /*! \brief GeneralizedTime (SIZE (12..19)) (optional) */
++ unsigned char timestamp[19 + 1];
++
++ /*!
++ * \details
++ * allServices(0),
++ * speech(1),
++ * unrestrictedDigitalInformation(2),
++ * audio3100Hz(3),
++ * telephony(32),
++ * teletex(33),
++ * telefaxGroup4Class1(34),
++ * videotextSyntaxBased(35),
++ * videotelephony(36),
++ * telefaxGroup2-3(37),
++ * reservedNotUsed1(38),
++ * reservedNotUsed2(39),
++ * reservedNotUsed3(40),
++ * reservedNotUsed4(41),
++ * reservedNotUsed5(42),
++ * email(51),
++ * video(52),
++ * fileTransfer(53),
++ * shortMessageService(54),
++ * speechAndVideo(55),
++ * speechAndFax(56),
++ * speechAndEmail(57),
++ * videoAndFax(58),
++ * videoAndEmail(59),
++ * faxAndEmail(60),
++ * speechVideoAndFax(61),
++ * speechVideoAndEmail(62),
++ * speechFaxAndEmail(63),
++ * videoFaxAndEmail(64),
++ * speechVideoFaxAndEmail(65),
++ * multimediaUnknown(66),
++ * serviceUnknown(67),
++ * futureReserve1(68),
++ * futureReserve2(69),
++ * futureReserve3(70),
++ * futureReserve4(71),
++ * futureReserve5(72),
++ * futureReserve6(73),
++ * futureReserve7(74),
++ * futureReserve8(75)
++ */
++ u_int8_t basic_service;
++
++ /*!
++ * \brief INTEGER (0..9) (optional)
++ * \note The value 0 means the highest priority and 9 the lowest.
++ */
++ u_int8_t priority;
++
++ /*! \brief TRUE if msg_centre_id is present */
++ u_int8_t msg_centre_id_present;
++
++ /*! \brief TRUE if number_of_messages is present */
++ u_int8_t number_of_messages_present;
++
++ /*! \brief TRUE if timestamp is present */
++ u_int8_t timestamp_present;
++
++ /*! \brief TRUE if priority is present */
++ u_int8_t priority_present;
++};
++
++/*
++ * MWIInterrogateRes ::= SEQUENCE SIZE(1..10) OF MWIInterrogateResElt
++ */
++struct roseQsigMWIInterrogateRes {
++ /*! \brief SEQUENCE SIZE(1..10) OF MWIInterrogateResElt */
++ struct roseQsigMWIInterrogateResElt list[10];
++
++ /*! \brief Number of MWIInterrogateResElt records present */
++ u_int8_t num_records;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*
++ * Northern Telecom DMS-100 transfer ability result
++ *
++ * callId [0] IMPLICIT INTEGER (0..16777215) -- 24 bit number
++ */
++struct roseDms100RLTOperationInd_RES {
++ /*! INTEGER (0..16777215) -- 24 bit number */
++ u_int32_t call_id;
++};
++
++/*
++ * Northern Telecom DMS-100 transfer invoke
++ *
++ * ARGUMENT SEQUENCE {
++ * callId [0] IMPLICIT INTEGER (0..16777215), -- 24 bit number
++ * reason [1] IMPLICIT INTEGER
++ * }
++ */
++struct roseDms100RLTThirdParty_ARG {
++ /*! INTEGER (0..16777215) -- 24 bit number */
++ u_int32_t call_id;
++
++ /*! Reason for redirect */
++ u_int8_t reason;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/* ARGUMENT ENUMERATED */
++struct roseNi2InformationFollowing_ARG {
++ u_int8_t value; /*!< Unknown enumerated value */
++};
++
++/*
++ * ARGUMENT SEQUENCE {
++ * callReference INTEGER -- 16 bit number
++ * }
++ */
++struct roseNi2InitiateTransfer_ARG {
++ u_int16_t call_reference;
++};
++
++
++/* ------------------------------------------------------------------- */
++
++
++/*! \brief Facility ie invoke etsi messages with arguments. */
++union rose_msg_invoke_etsi_args {
++ /* ETSI Advice Of Charge (AOC) */
++ struct roseEtsiChargingRequest_ARG ChargingRequest;
++ struct roseEtsiAOCSCurrency_ARG AOCSCurrency;
++ struct roseEtsiAOCSSpecialArr_ARG AOCSSpecialArr;
++ struct roseEtsiAOCDCurrency_ARG AOCDCurrency;
++ struct roseEtsiAOCDChargingUnit_ARG AOCDChargingUnit;
++ struct roseEtsiAOCECurrency_ARG AOCECurrency;
++ struct roseEtsiAOCEChargingUnit_ARG AOCEChargingUnit;
++
++ /* ETSI Call Diversion */
++ struct roseEtsiActivationDiversion_ARG ActivationDiversion;
++ struct roseEtsiDeactivationDiversion_ARG DeactivationDiversion;
++ struct roseEtsiActivationStatusNotificationDiv_ARG ActivationStatusNotificationDiv;
++ struct roseEtsiDeactivationStatusNotificationDiv_ARG
++ DeactivationStatusNotificationDiv;
++ struct roseEtsiInterrogationDiversion_ARG InterrogationDiversion;
++ struct roseEtsiDiversionInformation_ARG DiversionInformation;
++ struct roseEtsiCallDeflection_ARG CallDeflection;
++ struct roseEtsiCallRerouting_ARG CallRerouting;
++ struct roseEtsiDivertingLegInformation1_ARG DivertingLegInformation1;
++ struct roseEtsiDivertingLegInformation2_ARG DivertingLegInformation2;
++ struct roseEtsiDivertingLegInformation3_ARG DivertingLegInformation3;
++
++ /* ETSI Explicit Call Transfer (ECT) */
++ struct roseEtsiExplicitEctExecute_ARG ExplicitEctExecute;
++ struct roseEtsiSubaddressTransfer_ARG SubaddressTransfer;
++ struct roseEtsiEctInform_ARG EctInform;
++ struct roseEtsiEctLoopTest_ARG EctLoopTest;
++};
++
++/*! \brief Facility ie result etsi messages with arguments. */
++union rose_msg_result_etsi_args {
++ /* ETSI Advice Of Charge (AOC) */
++ struct roseEtsiChargingRequest_RES ChargingRequest;
++
++ /* ETSI Call Diversion */
++ struct roseEtsiForwardingList InterrogationDiversion;
++ struct roseEtsiServedUserNumberList InterrogateServedUserNumbers;
++
++ /* ETSI Explicit Call Transfer (ECT) */
++ struct roseEtsiEctLinkIdRequest_RES EctLinkIdRequest;
++ struct roseEtsiEctLoopTest_RES EctLoopTest;
++};
++
++/*! \brief Facility ie invoke qsig messages with arguments. */
++union rose_msg_invoke_qsig_args {
++ /* Q.SIG Name-Operations */
++ struct roseQsigPartyName_ARG CallingName;
++ struct roseQsigPartyName_ARG CalledName;
++ struct roseQsigPartyName_ARG ConnectedName;
++ struct roseQsigPartyName_ARG BusyName;
++
++ /* Q.SIG SS-AOC-Operations */
++ struct roseQsigChargeRequestArg_ARG ChargeRequest;
++ struct roseQsigAocFinalArg_ARG AocFinal;
++ struct roseQsigAocInterimArg_ARG AocInterim;
++ struct roseQsigAocRateArg_ARG AocRate;
++ struct roseQsigAocCompleteArg_ARG AocComplete;
++ struct roseQsigAocDivChargeReqArg_ARG AocDivChargeReq;
++
++ /* Q.SIG Call-Transfer-Operations */
++ struct roseQsigCTInitiateArg_ARG CallTransferInitiate;
++ struct roseQsigCTSetupArg_ARG CallTransferSetup;
++ struct roseQsigCTActiveArg_ARG CallTransferActive;
++ struct roseQsigCTCompleteArg_ARG CallTransferComplete;
++ struct roseQsigCTUpdateArg_ARG CallTransferUpdate;
++ struct roseQsigSubaddressTransferArg_ARG SubaddressTransfer;
++
++ /* Q.SIG Call-Diversion-Operations */
++ struct roseQsigActivateDiversionQ_ARG ActivateDiversionQ;
++ struct roseQsigDeactivateDiversionQ_ARG DeactivateDiversionQ;
++ struct roseQsigInterrogateDiversionQ_ARG InterrogateDiversionQ;
++ struct roseQsigCheckRestriction_ARG CheckRestriction;
++ struct roseQsigCallRerouting_ARG CallRerouting;
++ struct roseQsigDivertingLegInformation1_ARG DivertingLegInformation1;
++ struct roseQsigDivertingLegInformation2_ARG DivertingLegInformation2;
++ struct roseQsigDivertingLegInformation3_ARG DivertingLegInformation3;
++
++ /* Q.SIG SS-MWI-Operations */
++ struct roseQsigMWIActivateArg MWIActivate;
++ struct roseQsigMWIDeactivateArg MWIDeactivate;
++ struct roseQsigMWIInterrogateArg MWIInterrogate;
++};
++
++/*! \brief Facility ie result qsig messages with arguments. */
++union rose_msg_result_qsig_args {
++ /* Q.SIG SS-AOC-Operations */
++ struct roseQsigChargeRequestRes_RES ChargeRequest;
++ struct roseQsigAocCompleteRes_RES AocComplete;
++
++ /* Q.SIG Call-Transfer-Operations */
++ struct roseQsigCTIdentifyRes_RES CallTransferIdentify;
++
++ /* Q.SIG Call-Diversion-Operations */
++ struct roseQsigForwardingList InterrogateDiversionQ;
++
++ /* Q.SIG SS-MWI-Operations */
++ struct roseQsigMWIInterrogateRes MWIInterrogate;
++};
++
++/*! \brief Facility ie invoke DMS-100 messages with arguments. */
++union rose_msg_invoke_dms100_args {
++ struct roseDms100RLTThirdParty_ARG RLT_ThirdParty;
++};
++
++/*! \brief Facility ie result DMS-100 messages with arguments. */
++union rose_msg_result_dms100_args {
++ struct roseDms100RLTOperationInd_RES RLT_OperationInd;
++};
++
++/*! \brief Facility ie invoke NI2 messages with arguments. */
++union rose_msg_invoke_ni2_args {
++ struct roseNi2InformationFollowing_ARG InformationFollowing;
++ struct roseNi2InitiateTransfer_ARG InitiateTransfer;
++};
++
++/*! \brief Facility ie result NI2 messages with arguments. */
++union rose_msg_result_ni2_args {
++ int dummy; /*!< place holder until there are results with parameters */
++};
++
++/*! \brief Facility ie invoke messages with arguments. */
++union rose_msg_invoke_args {
++ union rose_msg_invoke_etsi_args etsi;
++ union rose_msg_invoke_qsig_args qsig;
++ union rose_msg_invoke_dms100_args dms100;
++ union rose_msg_invoke_ni2_args ni2;
++};
++
++/*! \brief Facility ie result messages with arguments. */
++union rose_msg_result_args {
++ union rose_msg_result_etsi_args etsi;
++ union rose_msg_result_qsig_args qsig;
++ union rose_msg_result_dms100_args dms100;
++ union rose_msg_result_ni2_args ni2;
++};
++
++/*! \brief Facility ie error messages with parameters. */
++union rose_msg_error_args {
++ int dummy; /*!< place holder until there are errors with parameters */
++};
++
++struct rose_msg_invoke {
++ /*! \brief Invoke ID (-32768..32767) */
++ int16_t invoke_id;
++ /*! \brief Linked ID (-32768..32767) (optional) */
++ int16_t linked_id;
++ /*! \brief library encoded operation-value */
++ enum rose_operation operation;
++ /*! \brief TRUE if the Linked ID is present */
++ u_int8_t linked_id_present;
++ union rose_msg_invoke_args args;
++};
++
++struct rose_msg_result {
++ /*! \brief Invoke ID (-32768..32767) */
++ int16_t invoke_id;
++ /*!
++ * \brief library encoded operation-value
++ * \note Set to ROSE_None if the operation sequence is not present.
++ * \note ETSI and Q.SIG imply that if a return result does not have
++ * any arguments then you must rely upon the invokeId value to
++ * distinguish between return results because the operation-value is
++ * not present.
++ */
++ enum rose_operation operation;
++ union rose_msg_result_args args;
++};
++
++struct rose_msg_error {
++ /*! \brief Invoke ID (-32768..32767) */
++ int16_t invoke_id;
++ /*! \brief library encoded error-value */
++ enum rose_error_code code;
++ union rose_msg_error_args args;
++};
++
++struct rose_msg_reject {
++ /*! \brief Invoke ID (-32768..32767) (optional) */
++ int16_t invoke_id;
++ /*! \brief TRUE if the Invoke ID is present */
++ u_int8_t invoke_id_present;
++ /*! \brief library encoded problem-value */
++ enum rose_reject_code code;
++};
++
++enum rose_component_type {
++ ROSE_COMP_TYPE_INVALID,
++ ROSE_COMP_TYPE_INVOKE,
++ ROSE_COMP_TYPE_RESULT,
++ ROSE_COMP_TYPE_ERROR,
++ ROSE_COMP_TYPE_REJECT
++};
++
++struct rose_message {
++ /*! \brief invoke, result, error, reject */
++ enum rose_component_type type;
++ union {
++ struct rose_msg_invoke invoke;
++ struct rose_msg_result result;
++ struct rose_msg_error error;
++ struct rose_msg_reject reject;
++ } component;
++};
++
++/*
++ * NetworkFacilityExtension ::= [10] IMPLICIT SEQUENCE {
++ * sourceEntity [0] IMPLICIT EntityType,
++ * sourceEntityAddress [1] EXPLICIT AddressInformation OPTIONAL,
++ * destinationEntity [2] IMPLICIT EntityType,
++ * destinationEntityAddress [3] EXPLICIT AddressInformation OPTIONAL
++ * }
++ *
++ * AddressInformation ::= PartyNumber
++ */
++struct facNetworkFacilityExtension {
++ /*! \brief sourceEntityAddress (optional) (Number present if length is nonzero) */
++ struct rosePartyNumber source_number;
++ /*! \brief destinationEntityAddress (optional) (Number present if length is nonzero) */
++ struct rosePartyNumber destination_number;
++
++ /*!
++ * \details
++ * endPINX(0),
++ * anyTypeOfPINX(1)
++ */
++ u_int8_t source_entity;
++
++ /*!
++ * \details
++ * endPINX(0),
++ * anyTypeOfPINX(1)
++ */
++ u_int8_t destination_entity;
++};
++
++/*
++ * The network extensions header is a sequence of the following components:
++ *
++ * nfe NetworkFacilityExtension OPTIONAL,
++ * npp NetworkProtocolProfile OPTIONAL,
++ * interpretation InterpretationApdu OPTIONAL
++ *
++ * NetworkProtocolProfile ::= [18] IMPLICIT INTEGER (0..254)
++ *
++ * InterpretationApdu ::= [11] IMPLICIT ENUMERATED {
++ * discardAnyUnrecognisedInvokePdu(0),
++ *
++ * -- this value also applies to Call independent signalling connections
++ * -- see clause 8.1.2 (ECMA-165)
++ * clearCallIfAnyInvokePduNotRecognised(1),
++ *
++ * -- this coding is implied by the absence of an
++ * -- interpretation APDU.
++ * rejectAnyUnrecognisedInvokePdu(2)
++ * }
++ */
++struct fac_extension_header {
++ /*! \brief Network Facility Extension component */
++ struct facNetworkFacilityExtension nfe;
++
++ /*! \brief Network Protocol Profile component */
++ u_int8_t npp;
++
++ /*!
++ * \brief interpretation component
++ *
++ * \details
++ * discardAnyUnrecognisedInvokePdu(0),
++ * clearCallIfAnyInvokePduNotRecognised(1),
++ * rejectAnyUnrecognisedInvokePdu(2)
++ */
++ u_int8_t interpretation;
++
++ /*! \brief TRUE if nfe is present */
++ u_int8_t nfe_present;
++
++ /*! \brief TRUE if npp is present */
++ u_int8_t npp_present;
++
++ /*! \brief TRUE if interpretation is present */
++ u_int8_t interpretation_present;
++};
++
++const char *rose_operation2str(enum rose_operation operation);
++const char *rose_error2str(enum rose_error_code code);
++const char *rose_reject2str(enum rose_reject_code code);
++
++unsigned char *rose_encode_invoke(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rose_msg_invoke *msg);
++unsigned char *rose_encode_result(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rose_msg_result *msg);
++unsigned char *rose_encode_error(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rose_msg_error *msg);
++unsigned char *rose_encode_reject(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rose_msg_reject *msg);
++
++unsigned char *rose_encode(struct pri *ctrl, unsigned char *pos, unsigned char *end,
++ const struct rose_message *msg);
++const unsigned char *rose_decode(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end, struct rose_message *msg);
++
++unsigned char *fac_enc_extension_header(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct fac_extension_header *header);
++unsigned char *facility_encode_header(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct fac_extension_header *header);
++
++const unsigned char *fac_dec_extension_header(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end, struct fac_extension_header *header);
++const unsigned char *facility_decode_header(struct pri *ctrl, const unsigned char *pos,
++ const unsigned char *end, struct fac_extension_header *header);
++
++void facility_decode_dump(struct pri *ctrl, const unsigned char *buf, size_t length);
++
++/* ------------------------------------------------------------------- */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _LIBPRI_ROSE_H */
++/* ------------------------------------------------------------------- */
++/* end rose.h */
+
+Property changes on: rose.h
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_address.c
+===================================================================
+--- a/rose_address.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_address.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,983 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief ROSE Addressing-Data-Elements
++ *
++ * Addressing-Data-Elements ETS 300 196-1 D.3
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Encode the public or private network PartyNumber type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param number
++ * \param length_of_number
++ * \param type_of_number
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_NetworkPartyNumber(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const unsigned char *number,
++ size_t length_of_number, u_int8_t type_of_number)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, type_of_number));
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_NUMERIC_STRING, number,
++ length_of_number));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the PartyNumber type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param party_number
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_PartyNumber(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePartyNumber *party_number)
++{
++ switch (party_number->plan) {
++ case 0: /* Unknown PartyNumber */
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ party_number->str, party_number->length));
++ break;
++ case 1: /* Public PartyNumber */
++ ASN1_CALL(pos, rose_enc_NetworkPartyNumber(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, party_number->str, party_number->length,
++ party_number->ton));
++ break;
++ case 2: /* NSAP encoded PartyNumber */
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ party_number->str, party_number->length));
++ break;
++ case 3: /* Data PartyNumber (Not used) */
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ party_number->str, party_number->length));
++ break;
++ case 4: /* Telex PartyNumber (Not used) */
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4,
++ party_number->str, party_number->length));
++ break;
++ case 5: /* Private PartyNumber */
++ ASN1_CALL(pos, rose_enc_NetworkPartyNumber(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 5, party_number->str, party_number->length,
++ party_number->ton));
++ break;
++ case 8: /* National Standard PartyNumber (Not used) */
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 8,
++ party_number->str, party_number->length));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown numbering plan");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the PartySubaddress type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param party_subaddress
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_PartySubaddress(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePartySubaddress *party_subaddress)
++{
++ unsigned char *seq_len;
++
++ switch (party_subaddress->type) {
++ case 0: /* UserSpecified */
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_OCTET_STRING,
++ party_subaddress->u.user_specified.information, party_subaddress->length));
++ if (party_subaddress->u.user_specified.odd_count_present) {
++ ASN1_CALL(pos, asn1_enc_boolean(pos, end, ASN1_TYPE_BOOLEAN,
++ party_subaddress->u.user_specified.odd_count));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++ break;
++ case 1: /* NSAP */
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_OCTET_STRING,
++ party_subaddress->u.nsap, party_subaddress->length));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown subaddress type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Address type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param address
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_Address(struct pri *ctrl, unsigned char *pos, unsigned char *end,
++ unsigned tag, const struct roseAddress *address)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &address->number));
++ if (address->subaddress.length) {
++ ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end, &address->subaddress));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the PresentedNumberUnscreened type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param party
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_PresentedNumberUnscreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePresentedNumberUnscreened *party)
++{
++ unsigned char *seq_len;
++
++ switch (party->presentation) {
++ case 0: /* presentationAllowedNumber */
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &party->number));
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++ break;
++ case 1: /* presentationRestricted */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
++ break;
++ case 2: /* numberNotAvailableDueToInterworking */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2));
++ break;
++ case 3: /* presentationRestrictedNumber */
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &party->number));
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown presentation type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the NumberScreened type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param screened
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_NumberScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseNumberScreened *screened)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &screened->number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ screened->screening_indicator));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the PresentedNumberScreened type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param party
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_PresentedNumberScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePresentedNumberScreened *party)
++{
++ switch (party->presentation) {
++ case 0: /* presentationAllowedNumber */
++ ASN1_CALL(pos, rose_enc_NumberScreened(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 0, &party->screened));
++ break;
++ case 1: /* presentationRestricted */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
++ break;
++ case 2: /* numberNotAvailableDueToInterworking */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2));
++ break;
++ case 3: /* presentationRestrictedNumber */
++ ASN1_CALL(pos, rose_enc_NumberScreened(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 3, &party->screened));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown presentation type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the AddressScreened type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param screened
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_AddressScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseAddressScreened *screened)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &screened->number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ screened->screening_indicator));
++ if (screened->subaddress.length) {
++ ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end, &screened->subaddress));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the PresentedAddressScreened type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param party
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_PresentedAddressScreened(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct rosePresentedAddressScreened *party)
++{
++ switch (party->presentation) {
++ case 0: /* presentationAllowedAddress */
++ ASN1_CALL(pos, rose_enc_AddressScreened(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 0, &party->screened));
++ break;
++ case 1: /* presentationRestricted */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
++ break;
++ case 2: /* numberNotAvailableDueToInterworking */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2));
++ break;
++ case 3: /* presentationRestrictedAddress */
++ ASN1_CALL(pos, rose_enc_AddressScreened(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 3, &party->screened));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown presentation type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the NumberDigits PartyNumber argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party_number Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_NumberDigits(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartyNumber *party_number)
++{
++ size_t str_len;
++
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, name, tag, pos, end,
++ sizeof(party_number->str), party_number->str, &str_len));
++ party_number->length = str_len;
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the NSAP PartyNumber argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party_number Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_NSAPPartyNumber(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartyNumber *party_number)
++{
++ size_t str_len;
++
++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end,
++ sizeof(party_number->str), party_number->str, &str_len));
++ party_number->length = str_len;
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the public or private network PartyNumber argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party_number Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_NetworkPartyNumber(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartyNumber *party_number)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "typeOfNumber", tag, pos, seq_end, &value));
++ party_number->ton = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_TYPE_NUMERIC_STRING);
++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "numberDigits", tag, pos, seq_end,
++ party_number));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the PartyNumber argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party_number Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_PartyNumber(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartyNumber *party_number)
++{
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s PartyNumber\n", name);
++ }
++ party_number->ton = 0; /* unknown */
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ party_number->plan = 0; /* Unknown PartyNumber */
++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "unknownPartyNumber", tag, pos, end,
++ party_number));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ /* Must be constructed but we will not check for it for simplicity. */
++ party_number->plan = 1; /* Public PartyNumber */
++ ASN1_CALL(pos, rose_dec_NetworkPartyNumber(ctrl, "publicPartyNumber", tag, pos,
++ end, party_number));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ party_number->plan = 2; /* NSAP encoded PartyNumber */
++ ASN1_CALL(pos, rose_dec_NSAPPartyNumber(ctrl, "nsapEncodedPartyNumber", tag, pos,
++ end, party_number));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ party_number->plan = 3; /* Data PartyNumber (Not used) */
++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "dataPartyNumber", tag, pos, end,
++ party_number));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ party_number->plan = 4; /* Telex PartyNumber (Not used) */
++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "telexPartyNumber", tag, pos, end,
++ party_number));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5:
++ /* Must be constructed but we will not check for it for simplicity. */
++ party_number->plan = 5; /* Private PartyNumber */
++ ASN1_CALL(pos, rose_dec_NetworkPartyNumber(ctrl, "privatePartyNumber", tag, pos,
++ end, party_number));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 8:
++ party_number->plan = 8; /* National Standard PartyNumber (Not used) */
++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "nationalStandardPartyNumber", tag,
++ pos, end, party_number));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the User PartySubaddress argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party_subaddress Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_UserSubaddress(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartySubaddress *party_subaddress)
++{
++ size_t str_len;
++ int32_t odd_count;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ party_subaddress->type = 0; /* UserSpecified */
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s UserSpecified %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ /* SubaddressInformation */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_TYPE_OCTET_STRING);
++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, "subaddressInformation", tag, pos, seq_end,
++ sizeof(party_subaddress->u.user_specified.information),
++ party_subaddress->u.user_specified.information, &str_len));
++ party_subaddress->length = str_len;
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ /*
++ * The optional odd count indicator must be present since there
++ * is something left.
++ */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_BOOLEAN);
++ ASN1_CALL(pos, asn1_dec_boolean(ctrl, "oddCount", tag, pos, seq_end,
++ &odd_count));
++ party_subaddress->u.user_specified.odd_count = odd_count;
++ party_subaddress->u.user_specified.odd_count_present = 1;
++ } else {
++ party_subaddress->u.user_specified.odd_count = 0;
++ party_subaddress->u.user_specified.odd_count_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the NSAP PartySubaddress argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party_subaddress Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_NSAPSubaddress(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartySubaddress *party_subaddress)
++{
++ size_t str_len;
++
++ party_subaddress->type = 1; /* NSAP */
++
++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end,
++ sizeof(party_subaddress->u.nsap), party_subaddress->u.nsap, &str_len));
++ party_subaddress->length = str_len;
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the PartySubaddress argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party_subaddress Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_PartySubaddress(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartySubaddress *party_subaddress)
++{
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s PartySubaddress\n", name);
++ }
++ switch (tag) {
++ case ASN1_TAG_SEQUENCE:
++ ASN1_CALL(pos, rose_dec_UserSubaddress(ctrl, "user", tag, pos, end,
++ party_subaddress));
++ break;
++ case ASN1_TYPE_OCTET_STRING:
++ case ASN1_TYPE_OCTET_STRING | ASN1_PC_CONSTRUCTED:
++ ASN1_CALL(pos, rose_dec_NSAPSubaddress(ctrl, "nsap", tag, pos, end,
++ party_subaddress));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Address argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param address Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_Address(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct roseAddress *address)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s Address %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, seq_end,
++ &address->number));
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ /* The optional subaddress must be present since there is something left. */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "partySubaddress", tag, pos,
++ seq_end, &address->subaddress));
++ } else {
++ address->subaddress.length = 0; /* Subaddress not present */
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the PresentedNumberUnscreened argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_PresentedNumberUnscreened(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePresentedNumberUnscreened *party)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s PresentedNumberUnscreened\n", name);
++ }
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ party->presentation = 0; /* presentationAllowedNumber */
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "presentationAllowedNumber", tag, pos,
++ seq_end, &party->number));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ party->presentation = 1; /* presentationRestricted */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "presentationRestricted", tag, pos, end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ party->presentation = 2; /* numberNotAvailableDueToInterworking */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "numberNotAvailableDueToInterworking", tag,
++ pos, end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ party->presentation = 3; /* presentationRestrictedNumber */
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "presentationRestrictedNumber", tag,
++ pos, seq_end, &party->number));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the NumberScreened argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param screened Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_NumberScreened(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseNumberScreened *screened)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s NumberScreened %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, seq_end,
++ &screened->number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "screeningIndicator", tag, pos, seq_end, &value));
++ screened->screening_indicator = value;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the PresentedNumberScreened argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_PresentedNumberScreened(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePresentedNumberScreened *party)
++{
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s PresentedNumberScreened\n", name);
++ }
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ party->presentation = 0; /* presentationAllowedNumber */
++ ASN1_CALL(pos, rose_dec_NumberScreened(ctrl, "presentationAllowedNumber", tag,
++ pos, end, &party->screened));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ party->presentation = 1; /* presentationRestricted */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "presentationRestricted", tag, pos, end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ party->presentation = 2; /* numberNotAvailableDueToInterworking */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "numberNotAvailableDueToInterworking", tag,
++ pos, end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
++ party->presentation = 3; /* presentationRestrictedNumber */
++ ASN1_CALL(pos, rose_dec_NumberScreened(ctrl, "presentationRestrictedNumber", tag,
++ pos, end, &party->screened));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the AddressScreened argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param screened Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_AddressScreened(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseAddressScreened *screened)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s AddressScreened %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, seq_end,
++ &screened->number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "screeningIndicator", tag, pos, seq_end, &value));
++ screened->screening_indicator = value;
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ /* The optional subaddress must be present since there is something left. */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "partySubaddress", tag, pos,
++ seq_end, &screened->subaddress));
++ } else {
++ screened->subaddress.length = 0; /* Subaddress not present */
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the PresentedAddressScreened argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_PresentedAddressScreened(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePresentedAddressScreened *party)
++{
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s PresentedAddressScreened\n", name);
++ }
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ party->presentation = 0; /* presentationAllowedAddress */
++ ASN1_CALL(pos, rose_dec_AddressScreened(ctrl, "presentationAllowedAddress", tag,
++ pos, end, &party->screened));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ party->presentation = 1; /* presentationRestricted */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "presentationRestricted", tag, pos, end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ party->presentation = 2; /* numberNotAvailableDueToInterworking */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "numberNotAvailableDueToInterworking", tag,
++ pos, end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
++ party->presentation = 3; /* presentationRestrictedAddress */
++ ASN1_CALL(pos, rose_dec_AddressScreened(ctrl, "presentationRestrictedAddress",
++ tag, pos, end, &party->screened));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_address.c */
+
+Property changes on: rose_address.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_qsig_aoc.c
+===================================================================
+--- a/rose_qsig_aoc.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_qsig_aoc.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,1714 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief Q.SIG ROSE Advice-Of-Charge (AOC) operations
++ *
++ * SS-AOC-Operations ECMA-212 Annex E Table E.1
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Encode the Time type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param time Time information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_AOC_Time(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseQsigAOCTime *time)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ time->length));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, time->scale));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the Amount type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param amount Amount information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_AOC_Amount(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseQsigAOCAmount *amount)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ amount->currency));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ amount->multiplier));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the RecordedCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param recorded Recorded currency information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_AOC_RecordedCurrency(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseQsigAOCRecordedCurrency *recorded)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ recorded->currency, sizeof(recorded->currency) - 1));
++ ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &recorded->amount));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the DurationCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param duration Duration currency information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_AOC_DurationCurrency(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseQsigAOCDurationCurrency *duration)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ duration->currency, sizeof(duration->currency) - 1));
++ ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &duration->amount));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ duration->charging_type));
++ ASN1_CALL(pos, rose_enc_qsig_AOC_Time(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 4, &duration->time));
++ if (duration->granularity_present) {
++ ASN1_CALL(pos, rose_enc_qsig_AOC_Time(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 5, &duration->granularity));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the FlatRateCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param flat_rate Flat rate currency information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_AOC_FlatRateCurrency(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseQsigAOCFlatRateCurrency *flat_rate)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ flat_rate->currency, sizeof(flat_rate->currency) - 1));
++ ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &flat_rate->amount));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the VolumeRateCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param volume_rate Volume rate currency information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_AOC_VolumeRateCurrency(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseQsigAOCVolumeRateCurrency *volume_rate)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ volume_rate->currency, sizeof(volume_rate->currency) - 1));
++ ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &volume_rate->amount));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ volume_rate->unit));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the AOCSCurrencyInfo type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param currency_info Currency information record to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_AOCSCurrencyInfo(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseQsigAOCSCurrencyInfo *currency_info)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ currency_info->charged_item));
++
++ switch (currency_info->currency_type) {
++ case 0: /* specialChargingCode */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ currency_info->u.special_charging_code));
++ break;
++ case 1: /* durationCurrency */
++ ASN1_CALL(pos, rose_enc_qsig_AOC_DurationCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, &currency_info->u.duration));
++ break;
++ case 2: /* flatRateCurrency */
++ ASN1_CALL(pos, rose_enc_qsig_AOC_FlatRateCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &currency_info->u.flat_rate));
++ break;
++ case 3: /* volumeRateCurrency */
++ ASN1_CALL(pos, rose_enc_qsig_AOC_VolumeRateCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 3, &currency_info->u.volume_rate));
++ break;
++ case 4: /* freeOfCharge */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4));
++ break;
++ case 5: /* currencyInfoNotAvailable */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5));
++ break;
++ case 6: /* freeOfChargeFromBeginning */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 6));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown currency type");
++ return NULL;
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the AOCSCurrencyInfoList type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param currency_info Currency information list to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_AOCSCurrencyInfoList(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseQsigAOCSCurrencyInfoList *currency_info)
++{
++ unsigned index;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ for (index = 0; index < currency_info->num_records; ++index) {
++ ASN1_CALL(pos, rose_enc_qsig_AOCSCurrencyInfo(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &currency_info->list[index]));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the ChargingAssociation type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param charging Charging association information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_AOC_ChargingAssociation(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end,
++ const struct roseQsigAOCChargingAssociation *charging)
++{
++ unsigned char *explicit_len;
++
++ switch (charging->type) {
++ case 0: /* charge_identifier */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, charging->id));
++ break;
++ case 1: /* charged_number */
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &charging->number));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown ChargingAssociation type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG ChargeRequest invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned index;
++ unsigned char *seq_len;
++ unsigned char *advice_len;
++ const struct roseQsigChargeRequestArg_ARG *charge_request;
++
++ charge_request = &args->qsig.ChargeRequest;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ /* SEQUENCE SIZE(0..7) OF AdviceModeCombination */
++ ASN1_CONSTRUCTED_BEGIN(advice_len, pos, end, ASN1_TAG_SEQUENCE);
++ for (index = 0; index < charge_request->num_records; ++index) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ charge_request->advice_mode_combinations[index]));
++ }
++ ASN1_CONSTRUCTED_END(advice_len, pos, end);
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG ChargeRequest result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigChargeRequestRes_RES *charge_request;
++
++ charge_request = &args->qsig.ChargeRequest;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ charge_request->advice_mode_combination));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG AocFinal invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_AocFinal_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ unsigned char *specific_len;
++ const struct roseQsigAocFinalArg_ARG *aoc_final;
++
++ aoc_final = &args->qsig.AocFinal;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ switch (aoc_final->type) {
++ case 0: /* charge_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0));
++ break;
++ case 1: /* free_of_charge */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
++ break;
++ case 2: /* specific_currency */
++ ASN1_CONSTRUCTED_BEGIN(specific_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_qsig_AOC_RecordedCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, &aoc_final->specific.recorded));
++
++ if (aoc_final->specific.billing_id_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ aoc_final->specific.billing_id));
++ }
++
++ ASN1_CONSTRUCTED_END(specific_len, pos, end);
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown AocFinal type");
++ return NULL;
++ }
++
++ if (aoc_final->charging_association_present) {
++ ASN1_CALL(pos, rose_enc_qsig_AOC_ChargingAssociation(ctrl, pos, end,
++ &aoc_final->charging_association));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG AocInterim invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_AocInterim_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ unsigned char *specific_len;
++ const struct roseQsigAocInterimArg_ARG *aoc_interim;
++
++ aoc_interim = &args->qsig.AocInterim;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ switch (aoc_interim->type) {
++ case 0: /* charge_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0));
++ break;
++ case 1: /* free_of_charge */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
++ break;
++ case 2: /* specific_currency */
++ ASN1_CONSTRUCTED_BEGIN(specific_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_qsig_AOC_RecordedCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, &aoc_interim->specific.recorded));
++
++ if (aoc_interim->specific.billing_id_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ aoc_interim->specific.billing_id));
++ }
++
++ ASN1_CONSTRUCTED_END(specific_len, pos, end);
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown AocInterim type");
++ return NULL;
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG AocRate invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_AocRate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigAocRateArg_ARG *aoc_rate;
++
++ aoc_rate = &args->qsig.AocRate;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ switch (aoc_rate->type) {
++ case 0: /* charge_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ break;
++ case 1: /* currency_info_list */
++ ASN1_CALL(pos, rose_enc_qsig_AOCSCurrencyInfoList(ctrl, pos, end,
++ ASN1_TAG_SEQUENCE, &aoc_rate->currency_info));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown AocRate type");
++ return NULL;
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG AocComplete invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_AocComplete_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigAocCompleteArg_ARG *aoc_complete;
++
++ aoc_complete = &args->qsig.AocComplete;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &aoc_complete->charged_user_number));
++
++ if (aoc_complete->charging_association_present) {
++ ASN1_CALL(pos, rose_enc_qsig_AOC_ChargingAssociation(ctrl, pos, end,
++ &aoc_complete->charging_association));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG AocComplete result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_AocComplete_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigAocCompleteRes_RES *aoc_complete;
++
++ aoc_complete = &args->qsig.AocComplete;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ aoc_complete->charging_option));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG AocDivChargeReq invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigAocDivChargeReqArg_ARG *aoc_div_charge_req;
++
++ aoc_div_charge_req = &args->qsig.AocDivChargeReq;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &aoc_div_charge_req->diverting_user_number));
++
++ if (aoc_div_charge_req->charging_association_present) {
++ ASN1_CALL(pos, rose_enc_qsig_AOC_ChargingAssociation(ctrl, pos, end,
++ &aoc_div_charge_req->charging_association));
++ }
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ aoc_div_charge_req->diversion_type));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the Time type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param time Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_AOC_Time(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigAOCTime *time)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s Time %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "lengthOfTimeUnit", tag, pos, seq_end, &value));
++ time->length = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "scale", tag, pos, seq_end, &value));
++ time->scale = value;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the Amount type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param amount Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_AOC_Amount(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigAOCAmount *amount)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s Amount %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "currencyAmount", tag, pos, seq_end, &value));
++ amount->currency = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "multiplier", tag, pos, seq_end, &value));
++ amount->multiplier = value;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the RecordedCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param recorded Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_AOC_RecordedCurrency(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigAOCRecordedCurrency *recorded)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ size_t str_len;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s RecordedCurrency %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "rCurrency", tag, pos, seq_end,
++ sizeof(recorded->currency), recorded->currency, &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2);
++ ASN1_CALL(pos, rose_dec_qsig_AOC_Amount(ctrl, "rAmount", tag, pos, seq_end,
++ &recorded->amount));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the DurationCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param duration Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_AOC_DurationCurrency(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigAOCDurationCurrency *duration)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ size_t str_len;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s DurationCurrency %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "dCurrency", tag, pos, seq_end,
++ sizeof(duration->currency), duration->currency, &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2);
++ ASN1_CALL(pos, rose_dec_qsig_AOC_Amount(ctrl, "dAmount", tag, pos, seq_end,
++ &duration->amount));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "dChargingType", tag, pos, seq_end, &value));
++ duration->charging_type = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4);
++ ASN1_CALL(pos, rose_dec_qsig_AOC_Time(ctrl, "dTime", tag, pos, seq_end,
++ &duration->time));
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5);
++ ASN1_CALL(pos, rose_dec_qsig_AOC_Time(ctrl, "dGranularity", tag, pos, seq_end,
++ &duration->granularity));
++ duration->granularity_present = 1;
++ } else {
++ duration->granularity_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the FlatRateCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param flat_rate Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_AOC_FlatRateCurrency(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigAOCFlatRateCurrency *flat_rate)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ size_t str_len;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s FlatRateCurrency %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "fRCurrency", tag, pos, seq_end,
++ sizeof(flat_rate->currency), flat_rate->currency, &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2);
++ ASN1_CALL(pos, rose_dec_qsig_AOC_Amount(ctrl, "fRAmount", tag, pos, seq_end,
++ &flat_rate->amount));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the VolumeRateCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param volume_rate Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_AOC_VolumeRateCurrency(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigAOCVolumeRateCurrency *volume_rate)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ size_t str_len;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s VolumeRateCurrency %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "vRCurrency", tag, pos, seq_end,
++ sizeof(volume_rate->currency), volume_rate->currency, &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2);
++ ASN1_CALL(pos, rose_dec_qsig_AOC_Amount(ctrl, "vRAmount", tag, pos, seq_end,
++ &volume_rate->amount));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "vRVolumeUnit", tag, pos, seq_end, &value));
++ volume_rate->unit = value;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the AOCSCurrencyInfo type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param currency_info Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_AOCSCurrencyInfo(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigAOCSCurrencyInfo *currency_info)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s AOCSCurrencyInfo %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "chargedItem", tag, pos, seq_end, &value));
++ currency_info->charged_item = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_TYPE_INTEGER:
++ currency_info->currency_type = 0; /* specialChargingCode */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "specialChargingCode", tag, pos, seq_end,
++ &value));
++ currency_info->u.special_charging_code = value;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ currency_info->currency_type = 1; /* durationCurrency */
++ ASN1_CALL(pos, rose_dec_qsig_AOC_DurationCurrency(ctrl, "durationCurrency", tag,
++ pos, seq_end, &currency_info->u.duration));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ currency_info->currency_type = 2; /* flatRateCurrency */
++ ASN1_CALL(pos, rose_dec_qsig_AOC_FlatRateCurrency(ctrl, "flatRateCurrency", tag,
++ pos, seq_end, &currency_info->u.flat_rate));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
++ currency_info->currency_type = 3; /* volumeRateCurrency */
++ ASN1_CALL(pos, rose_dec_qsig_AOC_VolumeRateCurrency(ctrl, "volumeRateCurrency",
++ tag, pos, seq_end, &currency_info->u.volume_rate));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ currency_info->currency_type = 4; /* freeOfCharge */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, seq_end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5:
++ currency_info->currency_type = 5; /* currencyInfoNotAvailable */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "currencyInfoNotAvailable", tag, pos,
++ seq_end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 6:
++ currency_info->currency_type = 6; /* freeOfChargeFromBeginning */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfChargeFromBeginning", tag, pos,
++ seq_end));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the AOCSCurrencyInfoList type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param currency_info Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_AOCSCurrencyInfoList(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigAOCSCurrencyInfoList *currency_info)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s AOCSCurrencyInfoList %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ currency_info->num_records = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ if (currency_info->num_records < ARRAY_LEN(currency_info->list)) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_qsig_AOCSCurrencyInfo(ctrl, "listEntry", tag, pos,
++ seq_end, &currency_info->list[currency_info->num_records]));
++ ++currency_info->num_records;
++ } else {
++ /* Too many records */
++ return NULL;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the ChargingAssociation type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param charging Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_AOC_ChargingAssociation(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigAOCChargingAssociation *charging)
++{
++ int32_t value;
++ int length;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s ChargingAssociation\n", name);
++ }
++ switch (tag) {
++ case ASN1_TYPE_INTEGER:
++ charging->type = 0; /* charge_identifier */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "chargeIdentifier", tag, pos, end, &value));
++ charging->id = value;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ charging->type = 1; /* charged_number */
++
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "chargedNumber", tag, pos,
++ explicit_end, &charging->number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, end);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG ChargeRequest invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ int advice_offset;
++ const unsigned char *seq_end;
++ const unsigned char *advice_end;
++ struct roseQsigChargeRequestArg_ARG *charge_request;
++
++ charge_request = &args->qsig.ChargeRequest;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " ChargeRequest %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ /* SEQUENCE SIZE(0..7) OF AdviceModeCombination */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " adviceModeCombinations %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(advice_end, advice_offset, length, pos, seq_end);
++
++ /* Decode SIZE(0..7) OF AdviceModeCombination */
++ charge_request->num_records = 0;
++ while (pos < advice_end && *pos != ASN1_INDEF_TERM) {
++ if (charge_request->num_records <
++ ARRAY_LEN(charge_request->advice_mode_combinations)) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, advice_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "adviceModeCombination", tag, pos,
++ advice_end, &value));
++ charge_request->advice_mode_combinations[charge_request->num_records] =
++ value;
++ ++charge_request->num_records;
++ } else {
++ /* Too many records */
++ return NULL;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, advice_offset, advice_end, seq_end);
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG ChargeRequest result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigChargeRequestRes_RES *charge_request;
++
++ charge_request = &args->qsig.ChargeRequest;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " ChargeRequest %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "adviceModeCombination", tag, pos, seq_end,
++ &value));
++ charge_request->advice_mode_combination = value;
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG AocFinal invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_AocFinal_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ int specific_offset;
++ const unsigned char *seq_end;
++ const unsigned char *specific_end;
++ const unsigned char *save_pos;
++ struct roseQsigAocFinalArg_ARG *aoc_final;
++
++ aoc_final = &args->qsig.AocFinal;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " AocFinal %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ aoc_final->type = 0; /* charge_not_available */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, seq_end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ aoc_final->type = 1; /* free_of_charge */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, seq_end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ aoc_final->type = 2; /* specific_currency */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " specificCurrency %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(specific_end, specific_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1);
++ ASN1_CALL(pos, rose_dec_qsig_AOC_RecordedCurrency(ctrl, "recordedCurrency", tag,
++ pos, specific_end, &aoc_final->specific.recorded));
++
++ if (pos < specific_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "finalBillingId", tag, pos, specific_end,
++ &value));
++ aoc_final->specific.billing_id = value;
++ aoc_final->specific.billing_id_present = 1;
++ } else {
++ aoc_final->specific.billing_id_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, specific_offset, specific_end, seq_end);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ aoc_final->charging_association_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ case ASN1_TYPE_INTEGER:
++ ASN1_CALL(pos, rose_dec_qsig_AOC_ChargingAssociation(ctrl,
++ "chargingAssociation", tag, pos, seq_end,
++ &aoc_final->charging_association));
++ aoc_final->charging_association_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " finalArgExtension %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG AocInterim invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_AocInterim_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ int specific_offset;
++ const unsigned char *seq_end;
++ const unsigned char *specific_end;
++ struct roseQsigAocInterimArg_ARG *aoc_interim;
++
++ aoc_interim = &args->qsig.AocInterim;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " AocInterim %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ aoc_interim->type = 0; /* charge_not_available */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, seq_end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ aoc_interim->type = 1; /* free_of_charge */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, seq_end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ aoc_interim->type = 2; /* specific_currency */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " specificCurrency %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(specific_end, specific_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1);
++ ASN1_CALL(pos, rose_dec_qsig_AOC_RecordedCurrency(ctrl, "recordedCurrency", tag,
++ pos, specific_end, &aoc_interim->specific.recorded));
++
++ if (pos < specific_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "interimBillingId", tag, pos, specific_end,
++ &value));
++ aoc_interim->specific.billing_id = value;
++ aoc_interim->specific.billing_id_present = 1;
++ } else {
++ aoc_interim->specific.billing_id_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, specific_offset, specific_end, seq_end);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG AocRate invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_AocRate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigAocRateArg_ARG *aoc_rate;
++
++ aoc_rate = &args->qsig.AocRate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " AocRate %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_TYPE_NULL:
++ aoc_rate->type = 0; /* charge_not_available */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, seq_end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ aoc_rate->type = 1; /* currency_info_list */
++ ASN1_CALL(pos, rose_dec_qsig_AOCSCurrencyInfoList(ctrl, "aocSCurrencyInfoList",
++ tag, pos, seq_end, &aoc_rate->currency_info));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG AocComplete invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_AocComplete_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigAocCompleteArg_ARG *aoc_complete;
++
++ aoc_complete = &args->qsig.AocComplete;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " AocComplete %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "chargedUser", tag, pos, seq_end,
++ &aoc_complete->charged_user_number));
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ aoc_complete->charging_association_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ case ASN1_TYPE_INTEGER:
++ ASN1_CALL(pos, rose_dec_qsig_AOC_ChargingAssociation(ctrl,
++ "chargingAssociation", tag, pos, seq_end,
++ &aoc_complete->charging_association));
++ aoc_complete->charging_association_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " completeArgExtension %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG AocComplete result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_AocComplete_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigAocCompleteRes_RES *aoc_complete;
++
++ aoc_complete = &args->qsig.AocComplete;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " AocComplete %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "chargingOption", tag, pos, seq_end, &value));
++ aoc_complete->charging_option = value;
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG AocDivChargeReq invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigAocDivChargeReqArg_ARG *aoc_div_charge_req;
++
++ aoc_div_charge_req = &args->qsig.AocDivChargeReq;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " AocDivChargeReq %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "divertingUser", tag, pos, seq_end,
++ &aoc_div_charge_req->diverting_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ case ASN1_TYPE_INTEGER:
++ ASN1_CALL(pos, rose_dec_qsig_AOC_ChargingAssociation(ctrl, "chargingAssociation",
++ tag, pos, seq_end, &aoc_div_charge_req->charging_association));
++ aoc_div_charge_req->charging_association_present = 1;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ break;
++ default:
++ aoc_div_charge_req->charging_association_present = 0;
++ break;
++ }
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionType", tag, pos, seq_end, &value));
++ aoc_div_charge_req->diversion_type = value;
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_qsig_aoc.c */
+
+Property changes on: rose_qsig_aoc.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_etsi_aoc.c
+===================================================================
+--- a/rose_etsi_aoc.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_etsi_aoc.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,1929 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief ROSE Advice Of Charge (AOC) operations
++ *
++ * Advice of Charge (AOC) supplementary service EN 300 182-1
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Encode the Time type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param time Time information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOC_Time(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseEtsiAOCTime *time)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ time->length));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, time->scale));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the Amount type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param amount Amount information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOC_Amount(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseEtsiAOCAmount *amount)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ amount->currency));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ amount->multiplier));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the RecordedCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param recorded Recorded currency information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOC_RecordedCurrency(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCRecordedCurrency *recorded)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ recorded->currency, sizeof(recorded->currency) - 1));
++ ASN1_CALL(pos, rose_enc_etsi_AOC_Amount(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &recorded->amount));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the DurationCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param duration Duration currency information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOC_DurationCurrency(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCDurationCurrency *duration)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ duration->currency, sizeof(duration->currency) - 1));
++ ASN1_CALL(pos, rose_enc_etsi_AOC_Amount(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &duration->amount));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ duration->charging_type));
++ ASN1_CALL(pos, rose_enc_etsi_AOC_Time(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 4, &duration->time));
++ if (duration->granularity_present) {
++ ASN1_CALL(pos, rose_enc_etsi_AOC_Time(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 5, &duration->granularity));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the FlatRateCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param flat_rate Flat rate currency information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOC_FlatRateCurrency(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCFlatRateCurrency *flat_rate)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ flat_rate->currency, sizeof(flat_rate->currency) - 1));
++ ASN1_CALL(pos, rose_enc_etsi_AOC_Amount(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &flat_rate->amount));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the VolumeRateCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param volume_rate Volume rate currency information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOC_VolumeRateCurrency(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCVolumeRateCurrency *volume_rate)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1,
++ volume_rate->currency, sizeof(volume_rate->currency) - 1));
++ ASN1_CALL(pos, rose_enc_etsi_AOC_Amount(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &volume_rate->amount));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ volume_rate->unit));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the AOCSCurrencyInfo type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param currency_info Currency information record to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOCSCurrencyInfo(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCSCurrencyInfo *currency_info)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ currency_info->charged_item));
++
++ switch (currency_info->currency_type) {
++ case 0: /* specialChargingCode */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ currency_info->u.special_charging_code));
++ break;
++ case 1: /* durationCurrency */
++ ASN1_CALL(pos, rose_enc_etsi_AOC_DurationCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, &currency_info->u.duration));
++ break;
++ case 2: /* flatRateCurrency */
++ ASN1_CALL(pos, rose_enc_etsi_AOC_FlatRateCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &currency_info->u.flat_rate));
++ break;
++ case 3: /* volumeRateCurrency */
++ ASN1_CALL(pos, rose_enc_etsi_AOC_VolumeRateCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 3, &currency_info->u.volume_rate));
++ break;
++ case 4: /* freeOfCharge */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4));
++ break;
++ case 5: /* currencyInfoNotAvailable */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown currency type");
++ return NULL;
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the AOCSCurrencyInfoList type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param currency_info Currency information list to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOCSCurrencyInfoList(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCSCurrencyInfoList *currency_info)
++{
++ unsigned index;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ for (index = 0; index < currency_info->num_records; ++index) {
++ ASN1_CALL(pos, rose_enc_etsi_AOCSCurrencyInfo(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &currency_info->list[index]));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the RecordedUnits type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param recorded Recorded units information record to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOC_RecordedUnits(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCRecordedUnits *recorded)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ if (recorded->not_available) {
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ } else {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ recorded->number_of_units));
++ }
++
++ if (recorded->type_of_unit_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ recorded->type_of_unit));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the RecordedUnitsList type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param recorded_info Recorded units information list to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOC_RecordedUnitsList(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCRecordedUnitsList *recorded_info)
++{
++ unsigned index;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ for (index = 0; index < recorded_info->num_records; ++index) {
++ ASN1_CALL(pos, rose_enc_etsi_AOC_RecordedUnits(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &recorded_info->list[index]));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the ChargingAssociation type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param charging Charging association information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOC_ChargingAssociation(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end,
++ const struct roseEtsiAOCChargingAssociation *charging)
++{
++ unsigned char *explicit_len;
++
++ switch (charging->type) {
++ case 0: /* charge_identifier */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, charging->id));
++ break;
++ case 1: /* charged_number */
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0);
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &charging->number));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown ChargingAssociation type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the AOCECurrencyInfo type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param currency_info Currency information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOCECurrencyInfo(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCECurrencyInfo *currency_info)
++{
++ unsigned char *seq_len;
++ unsigned char *specific_seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ if (currency_info->free_of_charge) {
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
++ } else {
++ ASN1_CONSTRUCTED_BEGIN(specific_seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_etsi_AOC_RecordedCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, &currency_info->specific.recorded));
++
++ if (currency_info->specific.billing_id_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ currency_info->specific.billing_id));
++ }
++
++ ASN1_CONSTRUCTED_END(specific_seq_len, pos, end);
++ }
++
++ if (currency_info->charging_association_present) {
++ ASN1_CALL(pos, rose_enc_etsi_AOC_ChargingAssociation(ctrl, pos, end,
++ &currency_info->charging_association));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the AOCEChargingUnitInfo type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param charging_unit Charging unit information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_AOCEChargingUnitInfo(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiAOCEChargingUnitInfo *charging_unit)
++{
++ unsigned char *seq_len;
++ unsigned char *specific_seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ if (charging_unit->free_of_charge) {
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
++ } else {
++ ASN1_CONSTRUCTED_BEGIN(specific_seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_etsi_AOC_RecordedUnitsList(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, &charging_unit->specific.recorded));
++
++ if (charging_unit->specific.billing_id_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ charging_unit->specific.billing_id));
++ }
++
++ ASN1_CONSTRUCTED_END(specific_seq_len, pos, end);
++ }
++
++ if (charging_unit->charging_association_present) {
++ ASN1_CALL(pos, rose_enc_etsi_AOC_ChargingAssociation(ctrl, pos, end,
++ &charging_unit->charging_association));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the ChargingRequest invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_ChargingRequest_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ args->etsi.ChargingRequest.charging_case);
++}
++
++/*!
++ * \brief Encode the ChargingRequest result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_ChargingRequest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args)
++{
++ switch (args->etsi.ChargingRequest.type) {
++ case 0: /* currency_info_list */
++ ASN1_CALL(pos, rose_enc_etsi_AOCSCurrencyInfoList(ctrl, pos, end,
++ ASN1_TAG_SEQUENCE, &args->etsi.ChargingRequest.u.currency_info));
++ break;
++ case 1: /* special_arrangement_info */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ args->etsi.ChargingRequest.u.special_arrangement));
++ break;
++ case 2: /* charging_info_follows */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown ChargingRequst type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the AOCSCurrency invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_AOCSCurrency_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ switch (args->etsi.AOCSCurrency.type) {
++ case 0: /* charge_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ break;
++ case 1: /* currency_info_list */
++ ASN1_CALL(pos, rose_enc_etsi_AOCSCurrencyInfoList(ctrl, pos, end,
++ ASN1_TAG_SEQUENCE, &args->etsi.AOCSCurrency.currency_info));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown AOCSCurrency type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the AOCSSpecialArr invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_AOCSSpecialArr_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ switch (args->etsi.AOCSSpecialArr.type) {
++ case 0: /* charge_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ break;
++ case 1: /* special_arrangement_info */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ args->etsi.AOCSSpecialArr.special_arrangement));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown AOCSSpecialArr type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the AOCDCurrency invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_AOCDCurrency_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiAOCDCurrency_ARG *aoc_d;
++ unsigned char *seq_len;
++
++ aoc_d = &args->etsi.AOCDCurrency;
++ switch (aoc_d->type) {
++ case 0: /* charge_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ break;
++ case 1: /* free_of_charge */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
++ break;
++ case 2: /* specific_currency */
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_etsi_AOC_RecordedCurrency(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, &aoc_d->specific.recorded));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ aoc_d->specific.type_of_charging_info));
++ if (aoc_d->specific.billing_id_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ aoc_d->specific.billing_id));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown AOCDCurrency type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the AOCDChargingUnit invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_AOCDChargingUnit_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiAOCDChargingUnit_ARG *aoc_d;
++ unsigned char *seq_len;
++
++ aoc_d = &args->etsi.AOCDChargingUnit;
++ switch (aoc_d->type) {
++ case 0: /* charge_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ break;
++ case 1: /* free_of_charge */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1));
++ break;
++ case 2: /* specific_charging_units */
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_etsi_AOC_RecordedUnitsList(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, &aoc_d->specific.recorded));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ aoc_d->specific.type_of_charging_info));
++ if (aoc_d->specific.billing_id_present) {
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3,
++ aoc_d->specific.billing_id));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown AOCDChargingUnit type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the AOCECurrency invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_AOCECurrency_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ switch (args->etsi.AOCECurrency.type) {
++ case 0: /* charge_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ break;
++ case 1: /* currency_info */
++ ASN1_CALL(pos, rose_enc_etsi_AOCECurrencyInfo(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &args->etsi.AOCECurrency.currency_info));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown AOCECurrency type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the AOCEChargingUnit invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_AOCEChargingUnit_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ switch (args->etsi.AOCEChargingUnit.type) {
++ case 0: /* charge_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL));
++ break;
++ case 1: /* charging_unit */
++ ASN1_CALL(pos, rose_enc_etsi_AOCEChargingUnitInfo(ctrl, pos, end,
++ ASN1_TAG_SEQUENCE, &args->etsi.AOCEChargingUnit.charging_unit));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown AOCEChargingUnit type");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the Time type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param time Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOC_Time(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCTime *time)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s Time %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "lengthOfTimeUnit", tag, pos, seq_end, &value));
++ time->length = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "scale", tag, pos, seq_end, &value));
++ time->scale = value;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the Amount type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param amount Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOC_Amount(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCAmount *amount)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s Amount %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "currencyAmount", tag, pos, seq_end, &value));
++ amount->currency = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "multiplier", tag, pos, seq_end, &value));
++ amount->multiplier = value;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the RecordedCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param recorded Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOC_RecordedCurrency(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCRecordedCurrency *recorded)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ size_t str_len;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s RecordedCurrency %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "rCurrency", tag, pos, seq_end,
++ sizeof(recorded->currency), recorded->currency, &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_Amount(ctrl, "rAmount", tag, pos, seq_end,
++ &recorded->amount));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the DurationCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param duration Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOC_DurationCurrency(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCDurationCurrency *duration)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ size_t str_len;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s DurationCurrency %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "dCurrency", tag, pos, seq_end,
++ sizeof(duration->currency), duration->currency, &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_Amount(ctrl, "dAmount", tag, pos, seq_end,
++ &duration->amount));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "dChargingType", tag, pos, seq_end, &value));
++ duration->charging_type = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_Time(ctrl, "dTime", tag, pos, seq_end,
++ &duration->time));
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_Time(ctrl, "dGranularity", tag, pos, seq_end,
++ &duration->granularity));
++ duration->granularity_present = 1;
++ } else {
++ duration->granularity_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the FlatRateCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param flat_rate Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOC_FlatRateCurrency(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCFlatRateCurrency *flat_rate)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ size_t str_len;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s FlatRateCurrency %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "fRCurrency", tag, pos, seq_end,
++ sizeof(flat_rate->currency), flat_rate->currency, &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_Amount(ctrl, "fRAmount", tag, pos, seq_end,
++ &flat_rate->amount));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the VolumeRateCurrency type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param volume_rate Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOC_VolumeRateCurrency(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCVolumeRateCurrency *volume_rate)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ size_t str_len;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s VolumeRateCurrency %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "vRCurrency", tag, pos, seq_end,
++ sizeof(volume_rate->currency), volume_rate->currency, &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_Amount(ctrl, "vRAmount", tag, pos, seq_end,
++ &volume_rate->amount));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "vRVolumeUnit", tag, pos, seq_end, &value));
++ volume_rate->unit = value;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the AOCSCurrencyInfo type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param currency_info Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOCSCurrencyInfo(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCSCurrencyInfo *currency_info)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s AOCSCurrencyInfo %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "chargedItem", tag, pos, seq_end, &value));
++ currency_info->charged_item = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_TYPE_INTEGER:
++ currency_info->currency_type = 0; /* specialChargingCode */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "specialChargingCode", tag, pos, seq_end,
++ &value));
++ currency_info->u.special_charging_code = value;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ currency_info->currency_type = 1; /* durationCurrency */
++ ASN1_CALL(pos, rose_dec_etsi_AOC_DurationCurrency(ctrl, "durationCurrency", tag,
++ pos, seq_end, &currency_info->u.duration));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ currency_info->currency_type = 2; /* flatRateCurrency */
++ ASN1_CALL(pos, rose_dec_etsi_AOC_FlatRateCurrency(ctrl, "flatRateCurrency", tag,
++ pos, seq_end, &currency_info->u.flat_rate));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
++ currency_info->currency_type = 3; /* volumeRateCurrency */
++ ASN1_CALL(pos, rose_dec_etsi_AOC_VolumeRateCurrency(ctrl, "volumeRateCurrency",
++ tag, pos, seq_end, &currency_info->u.volume_rate));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ currency_info->currency_type = 4; /* freeOfCharge */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, seq_end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5:
++ currency_info->currency_type = 5; /* currencyInfoNotAvailable */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "currencyInfoNotAvailable", tag, pos,
++ seq_end));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the AOCSCurrencyInfoList type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param currency_info Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOCSCurrencyInfoList(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCSCurrencyInfoList *currency_info)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s AOCSCurrencyInfoList %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ currency_info->num_records = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ if (currency_info->num_records < ARRAY_LEN(currency_info->list)) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_etsi_AOCSCurrencyInfo(ctrl, "listEntry", tag, pos,
++ seq_end, &currency_info->list[currency_info->num_records]));
++ ++currency_info->num_records;
++ } else {
++ /* Too many records */
++ return NULL;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the RecordedUnits type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param recorded Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOC_RecordedUnits(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCRecordedUnits *recorded)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s RecordedUnits %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_TYPE_INTEGER:
++ recorded->not_available = 0;
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "recordedNumberOfUnits", tag, pos, seq_end,
++ &value));
++ recorded->number_of_units = value;
++ break;
++ case ASN1_TYPE_NULL:
++ recorded->not_available = 1;
++ recorded->number_of_units = 0;
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "notAvailable", tag, pos, seq_end));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "recordedTypeOfUnits", tag, pos, seq_end,
++ &value));
++ recorded->type_of_unit = value;
++ recorded->type_of_unit_present = 1;
++ } else {
++ recorded->type_of_unit_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the RecordedUnitsList type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param recorded_info Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOC_RecordedUnitsList(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCRecordedUnitsList *recorded_info)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s RecordedUnitsList %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ recorded_info->num_records = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ if (recorded_info->num_records < ARRAY_LEN(recorded_info->list)) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_RecordedUnits(ctrl, "listEntry", tag, pos,
++ seq_end, &recorded_info->list[recorded_info->num_records]));
++ ++recorded_info->num_records;
++ } else {
++ /* Too many records */
++ return NULL;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the ChargingAssociation type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param charging Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOC_ChargingAssociation(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCChargingAssociation *charging)
++{
++ int32_t value;
++ int length;
++ int explicit_offset;
++ const unsigned char *explicit_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s ChargingAssociation\n", name);
++ }
++ switch (tag) {
++ case ASN1_TYPE_INTEGER:
++ charging->type = 0; /* charge_identifier */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "chargeIdentifier", tag, pos, end, &value));
++ charging->id = value;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ charging->type = 1; /* charged_number */
++
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "chargedNumber", tag, pos,
++ explicit_end, &charging->number));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, end);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the AOCECurrencyInfo type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param currency_info Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOCECurrencyInfo(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCECurrencyInfo *currency_info)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ int specific_offset;
++ const unsigned char *seq_end;
++ const unsigned char *specific_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s AOCECurrencyInfo %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ currency_info->free_of_charge = 1;
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, seq_end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ currency_info->free_of_charge = 0;
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " specificCurrency %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(specific_end, specific_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_RecordedCurrency(ctrl, "recordedCurrency", tag,
++ pos, specific_end, &currency_info->specific.recorded));
++
++ if (pos < specific_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "billingId", tag, pos, specific_end,
++ &value));
++ currency_info->specific.billing_id = value;
++ currency_info->specific.billing_id_present = 1;
++ } else {
++ currency_info->specific.billing_id_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, specific_offset, specific_end, seq_end);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_etsi_AOC_ChargingAssociation(ctrl, "chargingAssociation",
++ tag, pos, seq_end, &currency_info->charging_association));
++ currency_info->charging_association_present = 1;
++ } else {
++ currency_info->charging_association_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the AOCEChargingUnitInfo type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param charging_unit Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_AOCEChargingUnitInfo(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiAOCEChargingUnitInfo *charging_unit)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ int specific_offset;
++ const unsigned char *seq_end;
++ const unsigned char *specific_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s AOCEChargingUnitInfo %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ charging_unit->free_of_charge = 1;
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, seq_end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ charging_unit->free_of_charge = 0;
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " specificChargingUnits %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(specific_end, specific_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_RecordedUnitsList(ctrl, "recordedUnitsList",
++ tag, pos, specific_end, &charging_unit->specific.recorded));
++
++ if (pos < specific_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, specific_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "billingId", tag, pos, specific_end,
++ &value));
++ charging_unit->specific.billing_id = value;
++ charging_unit->specific.billing_id_present = 1;
++ } else {
++ charging_unit->specific.billing_id_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, specific_offset, specific_end, seq_end);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_etsi_AOC_ChargingAssociation(ctrl, "chargingAssociation",
++ tag, pos, seq_end, &charging_unit->charging_association));
++ charging_unit->charging_association_present = 1;
++ } else {
++ charging_unit->charging_association_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the ChargingRequest invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_ChargingRequest_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "chargingCase", tag, pos, end, &value));
++ args->etsi.ChargingRequest.charging_case = value;
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the ChargingRequest result parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_ChargingRequest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args)
++{
++ struct roseEtsiChargingRequest_RES *charging_request;
++ int32_t value;
++
++ charging_request = &args->etsi.ChargingRequest;
++ switch (tag) {
++ case ASN1_TAG_SEQUENCE:
++ charging_request->type = 0; /* currency_info_list */
++ ASN1_CALL(pos, rose_dec_etsi_AOCSCurrencyInfoList(ctrl, "currencyList", tag, pos,
++ end, &charging_request->u.currency_info));
++ break;
++ case ASN1_TYPE_INTEGER:
++ charging_request->type = 1; /* special_arrangement_info */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "specialArrangement", tag, pos, end, &value));
++ charging_request->u.special_arrangement = value;
++ break;
++ case ASN1_TYPE_NULL:
++ charging_request->type = 2; /* charging_info_follows */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargingInfoFollows", tag, pos, end));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the AOCSCurrency invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_AOCSCurrency_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ struct roseEtsiAOCSCurrency_ARG *aoc_s;
++
++ aoc_s = &args->etsi.AOCSCurrency;
++ switch (tag) {
++ case ASN1_TYPE_NULL:
++ aoc_s->type = 0; /* charge_not_available */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ aoc_s->type = 1; /* currency_info_list */
++ ASN1_CALL(pos, rose_dec_etsi_AOCSCurrencyInfoList(ctrl, "currencyInfo", tag, pos,
++ end, &aoc_s->currency_info));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the AOCSSpecialArr invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_AOCSSpecialArr_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ struct roseEtsiAOCSSpecialArr_ARG *aoc_s;
++ int32_t value;
++
++ aoc_s = &args->etsi.AOCSSpecialArr;
++ switch (tag) {
++ case ASN1_TYPE_NULL:
++ aoc_s->type = 0; /* charge_not_available */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, end));
++ break;
++ case ASN1_TYPE_INTEGER:
++ aoc_s->type = 1; /* special_arrangement_info */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "specialArrangement", tag, pos, end, &value));
++ aoc_s->special_arrangement = value;
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the AOCDCurrency invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_AOCDCurrency_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ struct roseEtsiAOCDCurrency_ARG *aoc_d;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ aoc_d = &args->etsi.AOCDCurrency;
++ switch (tag) {
++ case ASN1_TYPE_NULL:
++ aoc_d->type = 0; /* charge_not_available */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ aoc_d->type = 1; /* free_of_charge */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ aoc_d->type = 2; /* specific_currency */
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " specificCurrency %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_RecordedCurrency(ctrl, "recordedCurrency", tag,
++ pos, seq_end, &aoc_d->specific.recorded));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "typeOfChargingInfo", tag, pos, seq_end,
++ &value));
++ aoc_d->specific.type_of_charging_info = value;
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "billingId", tag, pos, seq_end, &value));
++ aoc_d->specific.billing_id = value;
++ aoc_d->specific.billing_id_present = 1;
++ } else {
++ aoc_d->specific.billing_id_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the AOCDChargingUnit invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_AOCDChargingUnit_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ struct roseEtsiAOCDChargingUnit_ARG *aoc_d;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ aoc_d = &args->etsi.AOCDChargingUnit;
++ switch (tag) {
++ case ASN1_TYPE_NULL:
++ aoc_d->type = 0; /* charge_not_available */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ aoc_d->type = 1; /* free_of_charge */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "freeOfCharge", tag, pos, end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ aoc_d->type = 2; /* specific_charging_units */
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " specificChargingUnits %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1);
++ ASN1_CALL(pos, rose_dec_etsi_AOC_RecordedUnitsList(ctrl, "recordedUnitsList",
++ tag, pos, seq_end, &aoc_d->specific.recorded));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "typeOfChargingInfo", tag, pos, seq_end,
++ &value));
++ aoc_d->specific.type_of_charging_info = value;
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "billingId", tag, pos, seq_end, &value));
++ aoc_d->specific.billing_id = value;
++ aoc_d->specific.billing_id_present = 1;
++ } else {
++ aoc_d->specific.billing_id_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the AOCECurrency invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_AOCECurrency_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ struct roseEtsiAOCECurrency_ARG *aoc_e;
++
++ aoc_e = &args->etsi.AOCECurrency;
++ switch (tag) {
++ case ASN1_TYPE_NULL:
++ aoc_e->type = 0; /* charge_not_available */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ aoc_e->type = 1; /* currency_info */
++ ASN1_CALL(pos, rose_dec_etsi_AOCECurrencyInfo(ctrl, "currencyInfo", tag, pos,
++ end, &aoc_e->currency_info));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the AOCEChargingUnit invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_AOCEChargingUnit_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ struct roseEtsiAOCEChargingUnit_ARG *aoc_e;
++
++ aoc_e = &args->etsi.AOCEChargingUnit;
++ switch (tag) {
++ case ASN1_TYPE_NULL:
++ aoc_e->type = 0; /* charge_not_available */
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "chargeNotAvailable", tag, pos, end));
++ break;
++ case ASN1_TAG_SEQUENCE:
++ aoc_e->type = 1; /* charging_unit */
++ ASN1_CALL(pos, rose_dec_etsi_AOCEChargingUnitInfo(ctrl, "chargingUnitInfo", tag,
++ pos, end, &aoc_e->charging_unit));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_etsi_aoc.c */
+
+Property changes on: rose_etsi_aoc.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_etsi_diversion.c
+===================================================================
+--- a/rose_etsi_diversion.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_etsi_diversion.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,1623 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief ROSE Call diversion operations
++ *
++ * Diversion Supplementary Services ETS 300 207-1 Table 3
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Encode the ServedUserNr type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param served_user_number Served user number information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_ServedUserNumber(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end,
++ const struct rosePartyNumber *served_user_number)
++{
++ if (served_user_number->length) {
++ /* Forward this number */
++ pos = rose_enc_PartyNumber(ctrl, pos, end, served_user_number);
++ } else {
++ /* Forward all numbers */
++ pos = asn1_enc_null(pos, end, ASN1_TYPE_NULL);
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the IntResult type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly
++ * tags it otherwise.
++ * \param int_result Forwarding record information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_IntResult(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseEtsiForwardingRecord *int_result)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, rose_enc_etsi_ServedUserNumber(ctrl, pos, end,
++ &int_result->served_user_number));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ int_result->basic_service));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, int_result->procedure));
++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &int_result->forwarded_to));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the IntResultList type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SET unless the caller implicitly
++ * tags it otherwise.
++ * \param int_result_list Forwarding record list information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_IntResultList(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag,
++ const struct roseEtsiForwardingList *int_result_list)
++{
++ unsigned index;
++ unsigned char *set_len;
++
++ ASN1_CONSTRUCTED_BEGIN(set_len, pos, end, tag);
++
++ for (index = 0; index < int_result_list->num_records; ++index) {
++ ASN1_CALL(pos, rose_enc_etsi_IntResult(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &int_result_list->list[index]));
++ }
++
++ ASN1_CONSTRUCTED_END(set_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the ServedUserNumberList type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SET unless the caller implicitly
++ * tags it otherwise.
++ * \param served_user_number_list Served user record list information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_etsi_ServedUserNumberList(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, unsigned tag,
++ const struct roseEtsiServedUserNumberList *served_user_number_list)
++{
++ unsigned index;
++ unsigned char *set_len;
++
++ ASN1_CONSTRUCTED_BEGIN(set_len, pos, end, tag);
++
++ for (index = 0; index < served_user_number_list->num_records; ++index) {
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &served_user_number_list->number[index]));
++ }
++
++ ASN1_CONSTRUCTED_END(set_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the ActivationDiversion invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_ActivationDiversion_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiActivationDiversion_ARG *activation_diversion;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ activation_diversion = &args->etsi.ActivationDiversion;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ activation_diversion->procedure));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ activation_diversion->basic_service));
++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &activation_diversion->forwarded_to));
++ ASN1_CALL(pos, rose_enc_etsi_ServedUserNumber(ctrl, pos, end,
++ &activation_diversion->served_user_number));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the DeactivationDiversion invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_DeactivationDiversion_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiDeactivationDiversion_ARG *deactivation_diversion;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ deactivation_diversion = &args->etsi.DeactivationDiversion;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ deactivation_diversion->procedure));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ deactivation_diversion->basic_service));
++ ASN1_CALL(pos, rose_enc_etsi_ServedUserNumber(ctrl, pos, end,
++ &deactivation_diversion->served_user_number));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the ActivationStatusNotificationDiv invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_ActivationStatusNotificationDiv_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiActivationStatusNotificationDiv_ARG
++ *activation_status_notification_div;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ activation_status_notification_div = &args->etsi.ActivationStatusNotificationDiv;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ activation_status_notification_div->procedure));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ activation_status_notification_div->basic_service));
++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &activation_status_notification_div->forwarded_to));
++ ASN1_CALL(pos, rose_enc_etsi_ServedUserNumber(ctrl, pos, end,
++ &activation_status_notification_div->served_user_number));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the DeactivationStatusNotificationDiv invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_DeactivationStatusNotificationDiv_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiDeactivationStatusNotificationDiv_ARG
++ *deactivation_status_notification_div;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ deactivation_status_notification_div = &args->etsi.DeactivationStatusNotificationDiv;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ deactivation_status_notification_div->procedure));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ deactivation_status_notification_div->basic_service));
++ ASN1_CALL(pos, rose_enc_etsi_ServedUserNumber(ctrl, pos, end,
++ &deactivation_status_notification_div->served_user_number));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the InterrogationDiversion invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_InterrogationDiversion_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiInterrogationDiversion_ARG *interrogation_diversion;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ interrogation_diversion = &args->etsi.InterrogationDiversion;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ interrogation_diversion->procedure));
++ if (interrogation_diversion->basic_service) {
++ /* Not the DEFAULT value */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ interrogation_diversion->basic_service));
++ }
++ ASN1_CALL(pos, rose_enc_etsi_ServedUserNumber(ctrl, pos, end,
++ &interrogation_diversion->served_user_number));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the InterrogationDiversion result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_InterrogationDiversion_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args)
++{
++ return rose_enc_etsi_IntResultList(ctrl, pos, end, ASN1_TAG_SET,
++ &args->etsi.InterrogationDiversion);
++}
++
++/*!
++ * \brief Encode the DiversionInformation invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_DiversionInformation_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiDiversionInformation_ARG *diversion_information;
++ unsigned char *seq_len;
++ unsigned char *explicit_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ diversion_information = &args->etsi.DiversionInformation;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ diversion_information->diversion_reason));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ diversion_information->basic_service));
++ if (diversion_information->served_user_subaddress.length) {
++ ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end,
++ &diversion_information->served_user_subaddress));
++ }
++ if (diversion_information->calling_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0);
++ ASN1_CALL(pos, rose_enc_PresentedAddressScreened(ctrl, pos, end,
++ &diversion_information->calling));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++ if (diversion_information->original_called_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &diversion_information->original_called));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++ if (diversion_information->last_diverting_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &diversion_information->last_diverting));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++ if (diversion_information->last_diverting_reason_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ diversion_information->last_diverting_reason));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++ if (diversion_information->q931ie.length) {
++ ASN1_CALL(pos, rose_enc_Q931ie(ctrl, pos, end, ASN1_CLASS_APPLICATION | 0,
++ &diversion_information->q931ie));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the CallDeflection invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_CallDeflection_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiCallDeflection_ARG *call_deflection;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ call_deflection = &args->etsi.CallDeflection;
++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &call_deflection->deflection));
++ if (call_deflection->presentation_allowed_to_diverted_to_user_present) {
++ ASN1_CALL(pos, asn1_enc_boolean(pos, end, ASN1_TYPE_BOOLEAN,
++ call_deflection->presentation_allowed_to_diverted_to_user));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the CallRerouting invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_CallRerouting_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiCallRerouting_ARG *call_rerouting;
++ unsigned char *seq_len;
++ unsigned char *explicit_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ call_rerouting = &args->etsi.CallRerouting;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ call_rerouting->rerouting_reason));
++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE,
++ &call_rerouting->called_address));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ call_rerouting->rerouting_counter));
++ ASN1_CALL(pos, rose_enc_Q931ie(ctrl, pos, end, ASN1_CLASS_APPLICATION | 0,
++ &call_rerouting->q931ie));
++
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &call_rerouting->last_rerouting));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++
++ if (call_rerouting->subscription_option) {
++ /* Not the DEFAULT value */
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ call_rerouting->subscription_option));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++
++ if (call_rerouting->calling_subaddress.length) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3);
++ ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end,
++ &call_rerouting->calling_subaddress));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the InterrogateServedUserNumbers result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_InterrogateServedUserNumbers_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args)
++{
++ return rose_enc_etsi_ServedUserNumberList(ctrl, pos, end, ASN1_TAG_SET,
++ &args->etsi.InterrogateServedUserNumbers);
++}
++
++/*!
++ * \brief Encode the DivertingLegInformation1 invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiDivertingLegInformation1_ARG *diverting_leg_information_1;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ diverting_leg_information_1 = &args->etsi.DivertingLegInformation1;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ diverting_leg_information_1->diversion_reason));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ diverting_leg_information_1->subscription_option));
++ if (diverting_leg_information_1->diverted_to_present) {
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &diverting_leg_information_1->diverted_to));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the DivertingLegInformation2 invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiDivertingLegInformation2_ARG *diverting_leg_information_2;
++ unsigned char *seq_len;
++ unsigned char *explicit_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ diverting_leg_information_2 = &args->etsi.DivertingLegInformation2;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ diverting_leg_information_2->diversion_counter));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ diverting_leg_information_2->diversion_reason));
++
++ if (diverting_leg_information_2->diverting_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1);
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &diverting_leg_information_2->diverting));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++
++ if (diverting_leg_information_2->original_called_present) {
++ /* EXPLICIT tag */
++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2);
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &diverting_leg_information_2->original_called));
++ ASN1_CONSTRUCTED_END(explicit_len, pos, end);
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the DivertingLegInformation3 invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return asn1_enc_boolean(pos, end, ASN1_TYPE_BOOLEAN,
++ args->etsi.DivertingLegInformation3.presentation_allowed_indicator);
++}
++
++/*!
++ * \internal
++ * \brief Decode the ServedUserNr argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param served_user_number Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_ServedUserNumber(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct rosePartyNumber *served_user_number)
++{
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s ServedUserNumber\n", name);
++ }
++ if (tag == ASN1_TYPE_NULL) {
++ served_user_number->length = 0;
++ pos = asn1_dec_null(ctrl, "allNumbers", tag, pos, end);
++ } else {
++ /* Must be a PartyNumber (Which is itself a CHOICE) */
++ pos =
++ rose_dec_PartyNumber(ctrl, "individualNumber", tag, pos, end,
++ served_user_number);
++ }
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the IntResult argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param int_result Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_IntResult(struct pri *ctrl, const char *name,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiForwardingRecord *int_result)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s IntResult %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_etsi_ServedUserNumber(ctrl, "servedUserNr", tag, pos,
++ seq_end, &int_result->served_user_number));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ int_result->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ int_result->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_Address(ctrl, "forwardedToAddress", tag, pos, seq_end,
++ &int_result->forwarded_to));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the IntResultList argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param int_result_list Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_IntResultList(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiForwardingList *int_result_list)
++{
++ int length;
++ int set_offset;
++ const unsigned char *set_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s IntResultList %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(set_end, set_offset, length, pos, end);
++
++ int_result_list->num_records = 0;
++ while (pos < set_end && *pos != ASN1_INDEF_TERM) {
++ if (int_result_list->num_records < ARRAY_LEN(int_result_list->list)) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, set_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_etsi_IntResult(ctrl, "listEntry", tag, pos, set_end,
++ &int_result_list->list[int_result_list->num_records]));
++ ++int_result_list->num_records;
++ } else {
++ /* Too many records */
++ return NULL;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, set_offset, set_end, end);
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the ServedUserNumberList argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param served_user_number_list Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_etsi_ServedUserNumberList(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseEtsiServedUserNumberList *served_user_number_list)
++{
++ int length;
++ int set_offset;
++ const unsigned char *set_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s ServedUserNumberList %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(set_end, set_offset, length, pos, end);
++
++ served_user_number_list->num_records = 0;
++ while (pos < set_end && *pos != ASN1_INDEF_TERM) {
++ if (served_user_number_list->num_records <
++ ARRAY_LEN(served_user_number_list->number)) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, set_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "listEntry", tag, pos, set_end,
++ &served_user_number_list->number[served_user_number_list->num_records]));
++ ++served_user_number_list->num_records;
++ } else {
++ /* Too many records */
++ return NULL;
++ }
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, set_offset, set_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the ActivationDiversion invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_ActivationDiversion_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ struct roseEtsiActivationDiversion_ARG *activation_diversion;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " ActivationDiversion %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ activation_diversion = &args->etsi.ActivationDiversion;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ activation_diversion->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ activation_diversion->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_Address(ctrl, "forwardedToAddress", tag, pos, seq_end,
++ &activation_diversion->forwarded_to));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_etsi_ServedUserNumber(ctrl, "servedUserNr", tag, pos,
++ seq_end, &activation_diversion->served_user_number));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the DeactivationDiversion invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_DeactivationDiversion_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ struct roseEtsiDeactivationDiversion_ARG *deactivation_diversion;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " DeactivationDiversion %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ deactivation_diversion = &args->etsi.DeactivationDiversion;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ deactivation_diversion->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ deactivation_diversion->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_etsi_ServedUserNumber(ctrl, "servedUserNr", tag, pos,
++ seq_end, &deactivation_diversion->served_user_number));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the ActivationStatusNotificationDiv invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_ActivationStatusNotificationDiv_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ struct roseEtsiActivationStatusNotificationDiv_ARG
++ *activation_status_notification_div;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " ActivationStatusNotificationDiv %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ activation_status_notification_div = &args->etsi.ActivationStatusNotificationDiv;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ activation_status_notification_div->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ activation_status_notification_div->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_Address(ctrl, "forwardedToAddress", tag, pos, seq_end,
++ &activation_status_notification_div->forwarded_to));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_etsi_ServedUserNumber(ctrl, "servedUserNr", tag, pos,
++ seq_end, &activation_status_notification_div->served_user_number));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the DeactivationStatusNotificationDiv invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_DeactivationStatusNotificationDiv_ARG(struct pri
++ *ctrl, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ struct roseEtsiDeactivationStatusNotificationDiv_ARG
++ *deactivation_status_notification_div;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " DeactivationStatusNotificationDiv %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ deactivation_status_notification_div = &args->etsi.DeactivationStatusNotificationDiv;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ deactivation_status_notification_div->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ deactivation_status_notification_div->basic_service = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_etsi_ServedUserNumber(ctrl, "forwardedToAddress", tag, pos,
++ seq_end, &deactivation_status_notification_div->served_user_number));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the InterrogationDiversion invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_InterrogationDiversion_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ struct roseEtsiInterrogationDiversion_ARG *interrogation_diversion;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " InterrogationDiversion %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ interrogation_diversion = &args->etsi.InterrogationDiversion;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value));
++ interrogation_diversion->procedure = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ if (tag == ASN1_TYPE_ENUMERATED) {
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ } else {
++ value = 0; /* DEFAULT BasicService value (allServices) */
++ }
++ interrogation_diversion->basic_service = value;
++
++ ASN1_CALL(pos, rose_dec_etsi_ServedUserNumber(ctrl, "servedUserNr", tag, pos,
++ seq_end, &interrogation_diversion->served_user_number));
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the InterrogationDiversion result parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_InterrogationDiversion_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args)
++{
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SET);
++ return rose_dec_etsi_IntResultList(ctrl, "diversionList", tag, pos, end,
++ &args->etsi.InterrogationDiversion);
++}
++
++/*!
++ * \brief Decode the DiversionInformation invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_DiversionInformation_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ struct roseEtsiDiversionInformation_ARG *diversion_information;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *seq_end;
++ const unsigned char *explicit_end;
++ const unsigned char *save_pos;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " DiversionInformation %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ diversion_information = &args->etsi.DiversionInformation;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionReason", tag, pos, seq_end, &value));
++ diversion_information->diversion_reason = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value));
++ diversion_information->basic_service = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ diversion_information->served_user_subaddress.length = 0;
++ diversion_information->calling_present = 0;
++ diversion_information->original_called_present = 0;
++ diversion_information->last_diverting_present = 0;
++ diversion_information->last_diverting_reason_present = 0;
++ diversion_information->q931ie.length = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_TAG_SEQUENCE:
++ case ASN1_TYPE_OCTET_STRING:
++ case ASN1_TYPE_OCTET_STRING | ASN1_PC_CONSTRUCTED:
++ ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "servedUserSubaddress", tag,
++ pos, seq_end, &diversion_information->served_user_subaddress));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedAddressScreened(ctrl, "callingAddress", tag,
++ pos, explicit_end, &diversion_information->calling));
++ diversion_information->calling_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "originalCalledNr",
++ tag, pos, explicit_end, &diversion_information->original_called));
++ diversion_information->original_called_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "lastDivertingNr",
++ tag, pos, explicit_end, &diversion_information->last_diverting));
++ diversion_information->last_diverting_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "lastDivertingReason", tag, pos,
++ explicit_end, &value));
++ diversion_information->last_diverting_reason = value;
++ diversion_information->last_diverting_reason_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_APPLICATION | 0:
++ case ASN1_CLASS_APPLICATION | ASN1_PC_CONSTRUCTED | 0:
++ ASN1_CALL(pos, rose_dec_Q931ie(ctrl, "userInfo", tag, pos, seq_end,
++ &diversion_information->q931ie,
++ sizeof(diversion_information->q931ie_contents)));
++ break;
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the CallDeflection invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_CallDeflection_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ struct roseEtsiCallDeflection_ARG *call_deflection;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CallDeflection %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ call_deflection = &args->etsi.CallDeflection;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_Address(ctrl, "deflectionAddress", tag, pos, seq_end,
++ &call_deflection->deflection));
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_BOOLEAN);
++ ASN1_CALL(pos, asn1_dec_boolean(ctrl, "presentationAllowedDivertedToUser", tag,
++ pos, seq_end, &value));
++ call_deflection->presentation_allowed_to_diverted_to_user = value;
++ call_deflection->presentation_allowed_to_diverted_to_user_present = 1;
++ } else {
++ call_deflection->presentation_allowed_to_diverted_to_user_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the CallRerouting invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_CallRerouting_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ struct roseEtsiCallRerouting_ARG *call_rerouting;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *seq_end;
++ const unsigned char *explicit_end;
++ const unsigned char *save_pos;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CallRerouting %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ call_rerouting = &args->etsi.CallRerouting;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "reroutingReason", tag, pos, seq_end, &value));
++ call_rerouting->rerouting_reason = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ ASN1_CALL(pos, rose_dec_Address(ctrl, "calledAddress", tag, pos, seq_end,
++ &call_rerouting->called_address));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "reroutingCounter", tag, pos, seq_end, &value));
++ call_rerouting->rerouting_counter = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_CLASS_APPLICATION | 0);
++ ASN1_CALL(pos, rose_dec_Q931ie(ctrl, "q931ie", tag, pos, seq_end,
++ &call_rerouting->q931ie, sizeof(call_rerouting->q931ie_contents)));
++
++ /* Remove EXPLICIT tag */
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag,
++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "lastReroutingNr", tag, pos,
++ explicit_end, &call_rerouting->last_rerouting));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ call_rerouting->subscription_option = 0; /* DEFAULT value noNotification */
++ call_rerouting->calling_subaddress.length = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "subscriptionOption", tag, pos,
++ explicit_end, &value));
++ call_rerouting->subscription_option = value;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "callingPartySubaddress", tag,
++ pos, explicit_end, &call_rerouting->calling_subaddress));
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the InterrogateServedUserNumbers result parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_InterrogateServedUserNumbers_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args)
++{
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SET);
++ return rose_dec_etsi_ServedUserNumberList(ctrl, "interrogateServedUserNumbers", tag,
++ pos, end, &args->etsi.InterrogateServedUserNumbers);
++}
++
++/*!
++ * \brief Decode the DivertingLegInformation1 invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_DivertingLegInformation1_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ struct roseEtsiDivertingLegInformation1_ARG *diverting_leg_informtion_1;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " DivertingLegInformation1 %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ diverting_leg_informtion_1 = &args->etsi.DivertingLegInformation1;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionReason", tag, pos, seq_end, &value));
++ diverting_leg_informtion_1->diversion_reason = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "subscriptionOption", tag, pos, seq_end, &value));
++ diverting_leg_informtion_1->subscription_option = value;
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "divertedToNumber", tag,
++ pos, seq_end, &diverting_leg_informtion_1->diverted_to));
++ diverting_leg_informtion_1->diverted_to_present = 1;
++ } else {
++ diverting_leg_informtion_1->diverted_to_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the DivertingLegInformation2 invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_DivertingLegInformation2_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ struct roseEtsiDivertingLegInformation2_ARG *diverting_leg_information_2;
++ int length;
++ int seq_offset;
++ int explicit_offset;
++ const unsigned char *seq_end;
++ const unsigned char *explicit_end;
++ const unsigned char *save_pos;
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " DivertingLegInformation2 %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ diverting_leg_information_2 = &args->etsi.DivertingLegInformation2;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionCounter", tag, pos, seq_end, &value));
++ diverting_leg_information_2->diversion_counter = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionReason", tag, pos, seq_end, &value));
++ diverting_leg_information_2->diversion_reason = value;
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ diverting_leg_information_2->diverting_present = 0;
++ diverting_leg_information_2->original_called_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "divertingNr", tag,
++ pos, explicit_end, &diverting_leg_information_2->diverting));
++ diverting_leg_information_2->diverting_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ /* Remove EXPLICIT tag */
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length));
++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "originalCalledNr",
++ tag, pos, explicit_end, &diverting_leg_information_2->original_called));
++ diverting_leg_information_2->original_called_present = 1;
++
++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end);
++ break;
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the DivertingLegInformation3 invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_DivertingLegInformation3_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_BOOLEAN);
++ ASN1_CALL(pos, asn1_dec_boolean(ctrl, "presentationAllowedIndicator", tag, pos, end,
++ &value));
++ args->etsi.DivertingLegInformation3.presentation_allowed_indicator = value;
++
++ return pos;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_etsi_diversion.c */
+
+Property changes on: rose_etsi_diversion.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_qsig_ct.c
+===================================================================
+--- a/rose_qsig_ct.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_qsig_ct.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,883 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief Q.SIG ROSE Call-Transfer-Operations (CT)
++ *
++ * Call-Transfer-Operations ECMA-178 Annex F Table F.1
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \brief Encode the Q.SIG CallTransferIdentify result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CallTransferIdentify_RES(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigCTIdentifyRes_RES *call_transfer_identify;
++
++ call_transfer_identify = &args->qsig.CallTransferIdentify;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_NUMERIC_STRING,
++ call_transfer_identify->call_id, sizeof(call_transfer_identify->call_id) - 1));
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &call_transfer_identify->rerouting_number));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG CallTransferInitiate invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CallTransferInitiate_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigCTInitiateArg_ARG *call_transfer_initiate;
++
++ call_transfer_initiate = &args->qsig.CallTransferInitiate;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_NUMERIC_STRING,
++ call_transfer_initiate->call_id, sizeof(call_transfer_initiate->call_id) - 1));
++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end,
++ &call_transfer_initiate->rerouting_number));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG CallTransferSetup invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CallTransferSetup_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigCTSetupArg_ARG *call_transfer_setup;
++
++ call_transfer_setup = &args->qsig.CallTransferSetup;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_NUMERIC_STRING,
++ call_transfer_setup->call_id, sizeof(call_transfer_setup->call_id) - 1));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG CallTransferActive invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CallTransferActive_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigCTActiveArg_ARG *call_transfer_active;
++
++ call_transfer_active = &args->qsig.CallTransferActive;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_PresentedAddressScreened(ctrl, pos, end,
++ &call_transfer_active->connected));
++
++ if (call_transfer_active->q931ie.length) {
++ ASN1_CALL(pos, rose_enc_Q931ie(ctrl, pos, end, ASN1_CLASS_APPLICATION | 0,
++ &call_transfer_active->q931ie));
++ }
++
++ if (call_transfer_active->connected_name_present) {
++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end,
++ &call_transfer_active->connected_name));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG CallTransferComplete invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CallTransferComplete_ARG(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigCTCompleteArg_ARG *call_transfer_complete;
++
++ call_transfer_complete = &args->qsig.CallTransferComplete;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ call_transfer_complete->end_designation));
++
++ ASN1_CALL(pos, rose_enc_PresentedNumberScreened(ctrl, pos, end,
++ &call_transfer_complete->redirection));
++
++ if (call_transfer_complete->q931ie.length) {
++ ASN1_CALL(pos, rose_enc_Q931ie(ctrl, pos, end, ASN1_CLASS_APPLICATION | 0,
++ &call_transfer_complete->q931ie));
++ }
++
++ if (call_transfer_complete->redirection_name_present) {
++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end,
++ &call_transfer_complete->redirection_name));
++ }
++
++ if (call_transfer_complete->call_status) {
++ /* Not the DEFAULT value */
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ call_transfer_complete->call_status));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG CallTransferUpdate invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CallTransferUpdate_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigCTUpdateArg_ARG *call_transfer_update;
++
++ call_transfer_update = &args->qsig.CallTransferUpdate;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_PresentedNumberScreened(ctrl, pos, end,
++ &call_transfer_update->redirection));
++
++ if (call_transfer_update->redirection_name_present) {
++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end,
++ &call_transfer_update->redirection_name));
++ }
++
++ if (call_transfer_update->q931ie.length) {
++ ASN1_CALL(pos, rose_enc_Q931ie(ctrl, pos, end, ASN1_CLASS_APPLICATION | 0,
++ &call_transfer_update->q931ie));
++ }
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG SubaddressTransfer invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_SubaddressTransfer_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ unsigned char *seq_len;
++ const struct roseQsigSubaddressTransferArg_ARG *subaddress_transfer;
++
++ subaddress_transfer = &args->qsig.SubaddressTransfer;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end,
++ &subaddress_transfer->redirection_subaddress));
++
++ /* No extension to encode */
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG DummyArg invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ *
++ * \details
++ * DummyArg ::= CHOICE {
++ * none NULL,
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * }
++ */
++unsigned char *rose_enc_qsig_DummyArg_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return asn1_enc_null(pos, end, ASN1_TYPE_NULL);
++}
++
++/*!
++ * \brief Encode the Q.SIG DummyRes result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ *
++ * \details
++ * DummyRes ::= CHOICE {
++ * none NULL,
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * }
++ */
++unsigned char *rose_enc_qsig_DummyRes_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args)
++{
++ return asn1_enc_null(pos, end, ASN1_TYPE_NULL);
++}
++
++/*!
++ * \brief Decode the Q.SIG CallTransferIdentify result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CallTransferIdentify_RES(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_result_args *args)
++{
++ size_t str_len;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigCTIdentifyRes_RES *call_transfer_identify;
++
++ call_transfer_identify = &args->qsig.CallTransferIdentify;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CallTransferIdentify %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_TYPE_NUMERIC_STRING);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "callIdentity", tag, pos, seq_end,
++ sizeof(call_transfer_identify->call_id), call_transfer_identify->call_id,
++ &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "reroutingNumber", tag, pos, seq_end,
++ &call_transfer_identify->rerouting_number));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG CallTransferInitiate invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CallTransferInitiate_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ size_t str_len;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigCTInitiateArg_ARG *call_transfer_initiate;
++
++ call_transfer_initiate = &args->qsig.CallTransferInitiate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CallTransferInitiate %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_TYPE_NUMERIC_STRING);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "callIdentity", tag, pos, seq_end,
++ sizeof(call_transfer_initiate->call_id), call_transfer_initiate->call_id,
++ &str_len));
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "reroutingNumber", tag, pos, seq_end,
++ &call_transfer_initiate->rerouting_number));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG CallTransferSetup invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CallTransferSetup_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ size_t str_len;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigCTSetupArg_ARG *call_transfer_setup;
++
++ call_transfer_setup = &args->qsig.CallTransferSetup;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CallTransferSetup %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag & ~ASN1_PC_MASK, tag, ASN1_TYPE_NUMERIC_STRING);
++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "callIdentity", tag, pos, seq_end,
++ sizeof(call_transfer_setup->call_id), call_transfer_setup->call_id, &str_len));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG CallTransferActive invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CallTransferActive_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigCTActiveArg_ARG *call_transfer_active;
++
++ call_transfer_active = &args->qsig.CallTransferActive;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CallTransferActive %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedAddressScreened(ctrl, "connectedAddress", tag, pos,
++ seq_end, &call_transfer_active->connected));
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ call_transfer_active->q931ie.length = 0;
++ call_transfer_active->connected_name_present = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_APPLICATION | 0:
++ ASN1_CALL(pos, rose_dec_Q931ie(ctrl, "basicCallInfoElements", tag, pos,
++ seq_end, &call_transfer_active->q931ie,
++ sizeof(call_transfer_active->q931ie_contents)));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7:
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "connectedName", tag, pos, seq_end,
++ &call_transfer_active->connected_name));
++ call_transfer_active->connected_name_present = 1;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 9:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 10:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExtension %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG CallTransferComplete invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CallTransferComplete_ARG(struct pri *ctrl,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ union rose_msg_invoke_args *args)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigCTCompleteArg_ARG *call_transfer_complete;
++
++ call_transfer_complete = &args->qsig.CallTransferComplete;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CallTransferComplete %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "endDesignation", tag, pos, seq_end, &value));
++ call_transfer_complete->end_designation = value;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberScreened(ctrl, "redirectionNumber", tag, pos,
++ seq_end, &call_transfer_complete->redirection));
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ call_transfer_complete->q931ie.length = 0;
++ call_transfer_complete->redirection_name_present = 0;
++ call_transfer_complete->call_status = 0; /* DEFAULT answered */
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_APPLICATION | 0:
++ ASN1_CALL(pos, rose_dec_Q931ie(ctrl, "basicCallInfoElements", tag, pos,
++ seq_end, &call_transfer_complete->q931ie,
++ sizeof(call_transfer_complete->q931ie_contents)));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7:
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "redirectionName", tag, pos, seq_end,
++ &call_transfer_complete->redirection_name));
++ call_transfer_complete->redirection_name_present = 1;
++ break;
++ case ASN1_TYPE_ENUMERATED:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "callStatus", tag, pos, seq_end, &value));
++ call_transfer_complete->call_status = value;
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 9:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 10:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExtension %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG CallTransferUpdate invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CallTransferUpdate_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ const unsigned char *save_pos;
++ struct roseQsigCTUpdateArg_ARG *call_transfer_update;
++
++ call_transfer_update = &args->qsig.CallTransferUpdate;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " CallTransferUpdate %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberScreened(ctrl, "redirectionNumber", tag, pos,
++ seq_end, &call_transfer_update->redirection));
++
++ /*
++ * A sequence specifies an ordered list of component types.
++ * However, for simplicity we are not checking the order of
++ * the remaining optional components.
++ */
++ call_transfer_update->redirection_name_present = 0;
++ call_transfer_update->q931ie.length = 0;
++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ save_pos = pos;
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7:
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "redirectionName", tag, pos, seq_end,
++ &call_transfer_update->redirection_name));
++ call_transfer_update->redirection_name_present = 1;
++ break;
++ case ASN1_CLASS_APPLICATION | 0:
++ ASN1_CALL(pos, rose_dec_Q931ie(ctrl, "basicCallInfoElements", tag, pos,
++ seq_end, &call_transfer_update->q931ie,
++ sizeof(call_transfer_update->q931ie_contents)));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 9:
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 10:
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " argumentExtension %s\n", asn1_tag2str(tag));
++ }
++ /* Fixup will skip over the manufacturer extension information */
++ default:
++ pos = save_pos;
++ goto cancel_options;
++ }
++ }
++cancel_options:;
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG SubaddressTransfer invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_SubaddressTransfer_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ struct roseQsigSubaddressTransferArg_ARG *subaddress_transfer;
++
++ subaddress_transfer = &args->qsig.SubaddressTransfer;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE);
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " SubaddressTransfer %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "redirectionSubaddress", tag, pos,
++ seq_end, &subaddress_transfer->redirection_subaddress));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG DummyArg invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ *
++ * \details
++ * DummyArg ::= CHOICE {
++ * none NULL,
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * }
++ */
++const unsigned char *rose_dec_qsig_DummyArg_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ const char *name;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ switch (tag) {
++ case ASN1_TYPE_NULL:
++ return asn1_dec_null(ctrl, "none", tag, pos, end);
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ name = "extension Extension";
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ name = "multipleExtension SEQUENCE OF Extension";
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ /* Fixup will skip over the manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG DummyRes result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ *
++ * \details
++ * DummyRes ::= CHOICE {
++ * none NULL,
++ * extension [1] IMPLICIT Extension,
++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension
++ * }
++ */
++const unsigned char *rose_dec_qsig_DummyRes_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args)
++{
++ const char *name;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ switch (tag) {
++ case ASN1_TYPE_NULL:
++ return asn1_dec_null(ctrl, "none", tag, pos, end);
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1:
++ name = "extension Extension";
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2:
++ name = "multipleExtension SEQUENCE OF Extension";
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ /* Fixup will skip over the manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_qsig_ct.c */
+
+Property changes on: rose_qsig_ct.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_q931.c
+===================================================================
+--- a/rose_q931.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_q931.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,100 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief ROSE Q.931 ie encode/decode functions
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \brief Encode the Q.931 ie value.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_CLASS_APPLICATION | 0 unless the caller
++ * implicitly tags it otherwise.
++ * \param q931ie Q931 ie information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_Q931ie(struct pri *ctrl, unsigned char *pos, unsigned char *end,
++ unsigned tag, const struct roseQ931ie *q931ie)
++{
++ return asn1_enc_string_bin(pos, end, tag, q931ie->contents, q931ie->length);
++}
++
++/*!
++ * \brief Decode the Q.931 ie value.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param q931ie Parameter storage to fill.
++ * \param contents_size Amount of space "allocated" for the q931ie->contents
++ * element. Must have enough room for a null terminator.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_Q931ie(struct pri *ctrl, const char *name, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, struct roseQ931ie *q931ie,
++ size_t contents_size)
++{
++ size_t str_len;
++
++ /* NOTE: The q931ie->contents memory is "allocated" after the struct. */
++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end, contents_size,
++ q931ie->contents, &str_len));
++ q931ie->length = str_len;
++
++ /*
++ * NOTE: We may want to do some basic decoding of the Q.931 ie list
++ * for debug purposes.
++ */
++
++ return pos;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_q931.c */
+
+Property changes on: rose_q931.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: rose_etsi_ect.c
+===================================================================
+--- a/rose_etsi_ect.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_etsi_ect.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,332 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief ROSE Explicit Call Transfer operations.
++ *
++ * Explicit Call Transfer (ECT) Supplementary Services ETS 300 369-1
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \brief Encode the ExplicitEctExecute invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_ExplicitEctExecute_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ args->etsi.ExplicitEctExecute.link_id);
++}
++
++/*!
++ * \brief Encode the SubaddressTransfer invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_SubaddressTransfer_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return rose_enc_PartySubaddress(ctrl, pos, end,
++ &args->etsi.SubaddressTransfer.subaddress);
++}
++
++/*!
++ * \brief Encode the EctLinkIdRequest result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_EctLinkIdRequest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args)
++{
++ return asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ args->etsi.EctLinkIdRequest.link_id);
++}
++
++/*!
++ * \brief Encode the EctInform invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_EctInform_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ const struct roseEtsiEctInform_ARG *ect_inform;
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE);
++
++ ect_inform = &args->etsi.EctInform;
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ect_inform->status));
++ if (ect_inform->redirection_present) {
++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end,
++ &ect_inform->redirection));
++ }
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the EctLoopTest invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_EctLoopTest_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return asn1_enc_int(pos, end, ASN1_TYPE_INTEGER,
++ args->etsi.EctLoopTest.call_transfer_id);
++}
++
++/*!
++ * \brief Encode the EctLoopTest result facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_etsi_EctLoopTest_RES(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_result_args *args)
++{
++ return asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED,
++ args->etsi.EctLoopTest.loop_result);
++}
++
++/*!
++ * \brief Decode the ExplicitEctExecute invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_ExplicitEctExecute_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "linkId", tag, pos, end, &value));
++ args->etsi.ExplicitEctExecute.link_id = value;
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the SubaddressTransfer invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_SubaddressTransfer_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ return rose_dec_PartySubaddress(ctrl, "transferredToSubaddress", tag, pos, end,
++ &args->etsi.SubaddressTransfer.subaddress);
++}
++
++/*!
++ * \brief Decode the EctLinkIdRequest result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_EctLinkIdRequest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args)
++{
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "linkId", tag, pos, end, &value));
++ args->etsi.EctLinkIdRequest.link_id = value;
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the EctInform invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_EctInform_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ struct roseEtsiEctInform_ARG *ect_inform;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++ int32_t value;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " EctInform %s\n", asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ect_inform = &args->etsi.EctInform;
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "callStatus", tag, pos, seq_end, &value));
++ ect_inform->status = value;
++
++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "redirectionNumber", tag,
++ pos, seq_end, &ect_inform->redirection));
++ ect_inform->redirection_present = 1;
++ } else {
++ ect_inform->redirection_present = 0;
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the EctLoopTest invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_EctLoopTest_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "callTransferId", tag, pos, end, &value));
++ args->etsi.EctLoopTest.call_transfer_id = value;
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the EctLoopTest result argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_etsi_EctLoopTest_RES(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args)
++{
++ int32_t value;
++
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "loopResult", tag, pos, end, &value));
++ args->etsi.EctLoopTest.loop_result = value;
++
++ return pos;
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_etsi_ect.c */
+
+Property changes on: rose_etsi_ect.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: pri_internal.h
+===================================================================
+--- a/pri_internal.h (.../tags/1.4.10.2) (revision 1357)
++++ b/pri_internal.h (.../branches/1.4) (revision 1357)
+@@ -32,30 +32,45 @@
+
+ #include <stddef.h>
+ #include <sys/time.h>
++#include "pri_q921.h"
++#include "pri_q931.h"
+
++#define ARRAY_LEN(arr) (sizeof(arr) / sizeof((arr)[0]))
++
+ #define DBGHEAD __FILE__ ":%d %s: "
+ #define DBGINFO __LINE__,__PRETTY_FUNCTION__
+
++/* Forward declare some structs */
++struct apdu_event;
++
+ struct pri_sched {
+ struct timeval when;
+ void (*callback)(void *data);
+ void *data;
+ };
+
+-struct q921_frame;
+-enum q931_state;
+-enum q931_mode;
+-
+-/* No more than 128 scheduled events */
++/*! Maximum number of scheduled events active at the same time. */
+ #define MAX_SCHED 128
+
+-#define MAX_TIMERS 32
++/*! Maximum number of facility ie's to handle per incoming message. */
++#define MAX_FACILITY_IES 8
+
++/*! Accumulated pri_message() line until a '\n' is seen on the end. */
++struct pri_msg_line {
++ /*! Accumulated buffer used. */
++ unsigned length;
++ /*! Accumulated pri_message() contents. */
++ char str[2048];
++};
++
++/*! \brief D channel controller structure */
+ struct pri {
+ int fd; /* File descriptor for D-Channel */
+ pri_io_cb read_func; /* Read data callback */
+ pri_io_cb write_func; /* Write data callback */
+ void *userdata;
++ /*! Accumulated pri_message() line. (Valid in master record only) */
++ struct pri_msg_line *msg_line;
+ struct pri *subchannel; /* Sub-channel if appropriate */
+ struct pri *master; /* Master channel if appropriate */
+ struct pri_sched pri_sched[MAX_SCHED]; /* Scheduled events */
+@@ -71,7 +86,9 @@
+ int protodisc;
+ unsigned int bri:1;
+ unsigned int acceptinbanddisconnect:1; /* Should we allow inband progress after DISCONNECT? */
+-
++ unsigned int hold_support:1;/* TRUE if upper layer supports call hold. */
++ unsigned int deflection_support:1;/* TRUE if upper layer supports call deflection/rerouting. */
++
+ /* Q.921 State */
+ int q921_state;
+ int window; /* Max window size */
+@@ -97,12 +114,14 @@
+ int ri;
+ int t200_timer; /* T-200 retransmission timer */
+ /* All ISDN Timer values */
+- int timers[MAX_TIMERS];
++ int timers[PRI_MAX_TIMERS];
+
+ /* Used by scheduler */
+ struct timeval tv;
+ int schedev;
+ pri_event ev; /* Static event thingy */
++ /*! Subcommands for static event thingy. */
++ struct pri_subcommands subcmds;
+
+ /* Q.921 Re-transmission queue */
+ struct q921_frame *txqueue;
+@@ -111,9 +130,19 @@
+ q931_call **callpool;
+ q931_call *localpool;
+
++ /*!
++ * \brief Q.931 Dummy call reference call associated with this TEI.
++ * \note If present then this call is allocated as part of the
++ * D channel control structure.
++ */
++ q931_call *dummy_call;
++
+ /* do we do overlap dialing */
+ int overlapdial;
+
++ /* do we support SERVICE messages */
++ int service_message_support;
++
+ /* do not skip channel 16 */
+ int chan_mapping_logical;
+
+@@ -125,52 +154,227 @@
+ unsigned int q931_rxcount;
+ #endif
+
+- unsigned char last_invoke; /* Last ROSE invoke ID */
++ short last_invoke; /* Last ROSE invoke ID (Valid in master record only) */
+ unsigned char sendfacility;
++
++ /*! For delayed processing of facility ie's. */
++ struct {
++ /*! Array of facility ie locations in the current received message. */
++ q931_ie *ie[MAX_FACILITY_IES];
++ /*! Codeset facility ie found within. */
++ unsigned char codeset[MAX_FACILITY_IES];
++ /*! Number of facility ie's in the array from the current received message. */
++ unsigned char count;
++ } facility;
+ };
+
++/*! \brief Maximum name length plus null terminator (From ECMA-164) */
++#define PRI_MAX_NAME_LEN (50 + 1)
++
++/*! \brief Q.SIG name information. */
++struct q931_party_name {
++ /*! \brief TRUE if name data is valid */
++ unsigned char valid;
++ /*!
++ * \brief Q.931 presentation-indicator encoded field
++ * \note Must tollerate the Q.931 screening-indicator field values being present.
++ */
++ unsigned char presentation;
++ /*!
++ * \brief Character set the name is using.
++ * \details
++ * unknown(0),
++ * iso8859-1(1),
++ * enum-value-withdrawn-by-ITU-T(2)
++ * iso8859-2(3),
++ * iso8859-3(4),
++ * iso8859-4(5),
++ * iso8859-5(6),
++ * iso8859-7(7),
++ * iso10646-BmpString(8),
++ * iso10646-utf-8String(9)
++ */
++ unsigned char char_set;
++ /*! \brief Name data with null terminator. */
++ char str[PRI_MAX_NAME_LEN];
++};
++
++/*! \brief Maximum phone number (address) length plus null terminator */
++#define PRI_MAX_NUMBER_LEN (31 + 1)
++
++struct q931_party_number {
++ /*! \brief TRUE if number data is valid */
++ unsigned char valid;
++ /*! \brief Q.931 presentation-indicator and screening-indicator encoded fields */
++ unsigned char presentation;
++ /*! \brief Q.931 Type-Of-Number and numbering-plan encoded fields */
++ unsigned char plan;
++ /*! \brief Number data with terminator. */
++ char str[PRI_MAX_NUMBER_LEN];
++};
++
++/*! \brief Maximum subaddress length plus null terminator */
++#define PRI_MAX_SUBADDRESS_LEN (20 + 1)
++
++struct q931_party_subaddress {
++ /*! \brief TRUE if the subaddress information is valid/present */
++ unsigned char valid;
++ /*!
++ * \brief Subaddress type.
++ * \details
++ * nsap(0),
++ * user_specified(2)
++ */
++ unsigned char type;
++ /*!
++ * \brief TRUE if odd number of address signals
++ * \note The odd/even indicator is used when the type of subaddress is
++ * user_specified and the coding is BCD.
++ */
++ unsigned char odd_even_indicator;
++ /*! \brief Length of the subaddress data */
++ unsigned char length;
++ /*!
++ * \brief Subaddress data with null terminator.
++ * \note The null terminator is a convenience only since the data could be
++ * BCD/binary and thus have a null byte as part of the contents.
++ */
++ unsigned char data[PRI_MAX_SUBADDRESS_LEN];
++};
++
++struct q931_party_address {
++ /*! \brief Subscriber phone number */
++ struct q931_party_number number;
++ /*! \brief Subscriber subaddress */
++ struct q931_party_subaddress subaddress;
++};
++
++/*! \brief Information needed to identify an endpoint in a call. */
++struct q931_party_id {
++ /*! \brief Subscriber name */
++ struct q931_party_name name;
++ /*! \brief Subscriber phone number */
++ struct q931_party_number number;
++ /*! \brief Subscriber subaddress */
++ struct q931_party_subaddress subaddress;
++};
++
++enum Q931_REDIRECTING_STATE {
++ /*!
++ * \details
++ * CDO-Idle/CDF-Inv-Idle
++ */
++ Q931_REDIRECTING_STATE_IDLE,
++ /*!
++ * \details
++ * CDF-Inv-Wait - A DivLeg2 has been received and
++ * we are waiting for valid presentation restriction information to send.
++ */
++ Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3,
++ /*!
++ * \details
++ * CDO-Divert - A DivLeg1 has been received and
++ * we are waiting for the presentation restriction information to come in.
++ */
++ Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3,
++};
++
++/*!
++ * \brief Do not increment above this count.
++ * \details
++ * It is not our responsibility to enforce the maximum number of redirects.
++ * However, we cannot allow an increment past this number without breaking things.
++ * Besides, more than 255 redirects is probably not a good thing.
++ */
++#define PRI_MAX_REDIRECTS 0xFF
++
++/*! \brief Redirecting information struct */
++struct q931_party_redirecting {
++ enum Q931_REDIRECTING_STATE state;
++ /*! \brief Who is redirecting the call (Sent to the party the call is redirected toward) */
++ struct q931_party_id from;
++ /*! \brief Call is redirecting to a new party (Sent to the caller) */
++ struct q931_party_id to;
++ /*! Originally called party (in cases of multiple redirects) */
++ struct q931_party_id orig_called;
++ /*!
++ * \brief Number of times the call was redirected
++ * \note The call is being redirected if the count is non-zero.
++ */
++ unsigned char count;
++ /*! Original reason for redirect (in cases of multiple redirects) */
++ unsigned char orig_reason;
++ /*! \brief Redirection reasons */
++ unsigned char reason;
++};
++
++/*! \brief New call setup parameter structure */
+ struct pri_sr {
+ int transmode;
+ int channel;
+ int exclusive;
+ int nonisdn;
+- char *caller;
+- int callerplan;
+- char *callername;
+- int callerpres;
+- char *called;
+- int calledplan;
++ struct q931_party_redirecting redirecting;
++ struct q931_party_id caller;
++ struct q931_party_address called;
+ int userl1;
+ int numcomplete;
+- char *redirectingnum;
+- int redirectingplan;
+- int redirectingpres;
+- int redirectingreason;
+- int justsignalling;
++ int cis_call;
++ int cis_auto_disconnect;
+ const char *useruserinfo;
++ const char *keypad_digits;
+ int transferable;
++ int reversecharge;
+ };
+
+ /* Internal switch types */
+ #define PRI_SWITCH_GR303_EOC_PATH 19
+ #define PRI_SWITCH_GR303_TMC_SWITCHING 20
+
+-struct apdu_event {
+- int message; /* What message to send the ADPU in */
+- void (*callback)(void *data); /* Callback function for when response is received */
+- void *data; /* Data to callback */
+- unsigned char apdu[255]; /* ADPU to send */
+- int apdu_len; /* Length of ADPU */
+- int sent; /* Have we been sent already? */
+- struct apdu_event *next; /* Linked list pointer */
++#define Q931_MAX_TEI 8
++
++/*! \brief Incoming call transfer states. */
++enum INCOMING_CT_STATE {
++ /*!
++ * \details
++ * Incoming call transfer is not active.
++ */
++ INCOMING_CT_STATE_IDLE,
++ /*!
++ * \details
++ * We have seen an incoming CallTransferComplete(alerting)
++ * so we are waiting for the expected CallTransferActive
++ * before updating the connected line about the remote party id.
++ */
++ INCOMING_CT_STATE_EXPECT_CT_ACTIVE,
++ /*!
++ * \details
++ * A call transfer message came in that updated the remote party id
++ * that we need to post a connected line update.
++ */
++ INCOMING_CT_STATE_POST_CONNECTED_LINE
+ };
+
++/*! Call hold supplementary states. */
++enum Q931_HOLD_STATE {
++ /*! \brief No call hold activity. */
++ Q931_HOLD_STATE_IDLE,
++ /*! \brief Request made to hold call. */
++ Q931_HOLD_STATE_HOLD_REQ,
++ /*! \brief Request received to hold call. */
++ Q931_HOLD_STATE_HOLD_IND,
++ /*! \brief Call is held. */
++ Q931_HOLD_STATE_CALL_HELD,
++ /*! \brief Request made to retrieve call. */
++ Q931_HOLD_STATE_RETRIEVE_REQ,
++ /*! \brief Request received to retrieve call. */
++ Q931_HOLD_STATE_RETRIEVE_IND,
++};
++
+ /* q931_call datastructure */
+-
+ struct q931_call {
+ struct pri *pri; /* PRI */
+ int cr; /* Call Reference */
+- int forceinvert; /* Force inversion of call number even if 0 */
+ q931_call *next;
+ /* Slotmap specified (bitmap of channels 31/24-1) (Channel Identifier IE) (-1 means not specified) */
+ int slotmap;
+@@ -199,73 +403,144 @@
+ int userl2;
+ int userl3;
+ int rateadaption;
+-
+- int sentchannel;
+- int justsignalling; /* for a signalling-only connection */
+
++ /*!
++ * \brief TRUE if the call is a Call Independent Signalling connection.
++ * \note The call has no B channel associated with it. (Just signalling)
++ */
++ int cis_call;
++ /*! \brief TRUE if we will auto disconnect the cis_call we originated. */
++ int cis_auto_disconnect;
++
+ int progcode; /* Progress coding */
+ int progloc; /* Progress Location */
+ int progress; /* Progress indicator */
+ int progressmask; /* Progress Indicator bitmask */
+
+- int notify; /* Notification */
++ int notify; /* Notification indicator. */
+
+ int causecode; /* Cause Coding */
+ int causeloc; /* Cause Location */
+ int cause; /* Cause of clearing */
+
+- int peercallstate; /* Call state of peer as reported */
+- int ourcallstate; /* Our call state */
+- int sugcallstate; /* Status call state */
+-
+- int callerplan;
+- int callerplanani;
+- int callerpres; /* Caller presentation */
+- char callerani[256]; /* Caller */
+- char callernum[256];
+- char callername[256];
++ enum Q931_CALL_STATE peercallstate; /* Call state of peer as reported */
++ enum Q931_CALL_STATE ourcallstate; /* Our call state */
++ enum Q931_CALL_STATE sugcallstate; /* Status call state */
+
+- char keypad_digits[64]; /* Buffer for digits that come in KEYPAD_FACILITY */
++ int ani2; /* ANI II */
+
+- int ani2; /* ANI II */
+-
+- int calledplan;
++ /*! Buffer for digits that come in KEYPAD_FACILITY */
++ char keypad_digits[32 + 1];
++
++ /*! Current dialed digits to be sent or just received. */
++ char overlap_digits[PRI_MAX_NUMBER_LEN];
++
++ /*!
++ * \brief Local party ID
++ * \details
++ * The Caller-ID and connected-line ID are just roles the local and remote party
++ * play while a call is being established. Which roll depends upon the direction
++ * of the call.
++ * Outgoing party info is to identify the local party to the other end.
++ * (Caller-ID for originated or connected-line for answered calls.)
++ * Incoming party info is to identify the remote party to us.
++ * (Caller-ID for answered or connected-line for originated calls.)
++ */
++ struct q931_party_id local_id;
++ /*!
++ * \brief Remote party ID
++ * \details
++ * The Caller-ID and connected-line ID are just roles the local and remote party
++ * play while a call is being established. Which roll depends upon the direction
++ * of the call.
++ * Outgoing party info is to identify the local party to the other end.
++ * (Caller-ID for originated or connected-line for answered calls.)
++ * Incoming party info is to identify the remote party to us.
++ * (Caller-ID for answered or connected-line for originated calls.)
++ */
++ struct q931_party_id remote_id;
++
++ /*!
++ * \brief Staging place for the Q.931 redirection number ie.
++ * \note
++ * The number could be the remote_id.number or redirecting.to.number
++ * depending upon the notification indicator.
++ */
++ struct q931_party_number redirection_number;
++
++ /*!
++ * \brief Called party address.
++ * \note The called.number.str is the accumulated overlap dial digits
++ * and enbloc digits.
++ * \note The called.number.presentation value is not used.
++ */
++ struct q931_party_address called;
+ int nonisdn;
+- char callednum[256]; /* Called Number */
+ int complete; /* no more digits coming */
+ int newcall; /* if the received message has a new call reference value */
+
+ int retranstimer; /* Timer for retransmitting DISC */
+ int t308_timedout; /* Whether t308 timed out once */
+
+- int redirectingplan;
+- int redirectingpres;
+- int redirectingreason;
+- char redirectingnum[256]; /* Number of redirecting party */
+- char redirectingname[256]; /* Name of redirecting party */
++ struct q931_party_redirecting redirecting;
+
+- /* Filled in cases of multiple diversions */
+- int origcalledplan;
+- int origcalledpres;
+- int origredirectingreason; /* Original reason for redirect (in cases of multiple redirects) */
+- char origcalledname[256]; /* Original name of person being called */
+- char origcallednum[256]; /* Orignal number of person being called */
++ /*! \brief Incoming call transfer state. */
++ enum INCOMING_CT_STATE incoming_ct_state;
++ /*! Call hold supplementary state. */
++ enum Q931_HOLD_STATE hold_state;
++ /*! Call hold event timer */
++ int hold_timer;
+
++ int deflection_in_progress; /*!< CallDeflection for NT PTMP in progress. */
++ /*! TRUE if the connected number ie was in the current received message. */
++ int connected_number_in_message;
++ /*! TRUE if the redirecting number ie was in the current received message. */
++ int redirecting_number_in_message;
++
+ int useruserprotocoldisc;
+ char useruserinfo[256];
+- char callingsubaddr[256]; /* Calling parties sub address */
+
+ long aoc_units; /* Advice of Charge Units */
+
+ struct apdu_event *apdus; /* APDU queue for call */
+
+- int transferable;
++ int transferable; /* RLT call is transferable */
+ unsigned int rlt_call_id; /* RLT call id */
+
+ /* Bridged call info */
+- q931_call *bridged_call; /* Pointer to other leg of bridged call */
++ q931_call *bridged_call; /* Pointer to other leg of bridged call (Used by Q.SIG when eliminating tromboned calls) */
++
++ int changestatus; /* SERVICE message changestatus */
++ int reversecharge; /* Reverse charging indication:
++ -1 - No reverse charging
++ 1 - Reverse charging
++ 0,2-7 - Reserved for future use */
++ int t303_timer;
++ int t303_expirycnt;
++
++ int hangupinitiated;
++ /*! \brief TRUE if we broadcast this call's SETUP message. */
++ int outboundbroadcast;
++ int performing_fake_clearing;
++ /*!
++ * \brief Master call controlling this call.
++ * \note Always valid. Master and normal calls point to self.
++ */
++ struct q931_call *master_call;
++
++ /* These valid in master call only */
++ struct q931_call *subcalls[Q931_MAX_TEI];
++ int pri_winner;
+ };
+
++/*! D channel control structure with associated dummy call reference record. */
++struct d_ctrl_dummy {
++ /*! D channel control structure. Must be first in the structure. */
++ struct pri ctrl;
++ /*! Dummy call reference call record. */
++ struct q931_call dummy_call;
++};
++
+ extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
+
+ extern pri_event *pri_schedule_run(struct pri *pri);
+@@ -274,14 +549,104 @@
+
+ extern pri_event *pri_mkerror(struct pri *pri, char *errstr);
+
+-extern void pri_message(struct pri *pri, char *fmt, ...);
++void pri_message(struct pri *ctrl, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
++void pri_error(struct pri *ctrl, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+
+-extern void pri_error(struct pri *pri, char *fmt, ...);
+-
+ void libpri_copy_string(char *dst, const char *src, size_t size);
+
+ struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int tei, int bri);
+
+ void __pri_free_tei(struct pri *p);
+
++void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr);
++
++void q931_party_name_init(struct q931_party_name *name);
++void q931_party_number_init(struct q931_party_number *number);
++void q931_party_subaddress_init(struct q931_party_subaddress *subaddr);
++void q931_party_address_init(struct q931_party_address *address);
++void q931_party_id_init(struct q931_party_id *id);
++void q931_party_redirecting_init(struct q931_party_redirecting *redirecting);
++
++static inline void q931_party_address_to_id(struct q931_party_id *id, struct q931_party_address *address)
++{
++ id->number = address->number;
++ id->subaddress = address->subaddress;
++}
++
++int q931_party_name_cmp(const struct q931_party_name *left, const struct q931_party_name *right);
++int q931_party_number_cmp(const struct q931_party_number *left, const struct q931_party_number *right);
++int q931_party_subaddress_cmp(const struct q931_party_subaddress *left, const struct q931_party_subaddress *right);
++int q931_party_id_cmp(const struct q931_party_id *left, const struct q931_party_id *right);
++
++void q931_party_name_copy_to_pri(struct pri_party_name *pri_name, const struct q931_party_name *q931_name);
++void q931_party_number_copy_to_pri(struct pri_party_number *pri_number, const struct q931_party_number *q931_number);
++void q931_party_subaddress_copy_to_pri(struct pri_party_subaddress *pri_subaddress, const struct q931_party_subaddress *q931_subaddress);
++void q931_party_id_copy_to_pri(struct pri_party_id *pri_id, const struct q931_party_id *q931_id);
++void q931_party_redirecting_copy_to_pri(struct pri_party_redirecting *pri_redirecting, const struct q931_party_redirecting *q931_redirecting);
++
++void q931_party_id_fixup(const struct pri *ctrl, struct q931_party_id *id);
++int q931_party_id_presentation(const struct q931_party_id *id);
++
++const char *q931_call_state_str(enum Q931_CALL_STATE callstate);
++const char *msg2str(int msg);
++
++int q931_is_ptmp(const struct pri *ctrl);
++int q931_master_pass_event(struct pri *ctrl, struct q931_call *subcall, int msg_type);
++struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl);
++
++int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number);
++
++static inline struct pri * PRI_MASTER(struct pri *mypri)
++{
++ struct pri *pri = mypri;
++
++ if (!pri)
++ return NULL;
++
++ while (pri->master)
++ pri = pri->master;
++
++ return pri;
++}
++
++static inline int BRI_NT_PTMP(struct pri *mypri)
++{
++ struct pri *pri;
++
++ pri = PRI_MASTER(mypri);
++
++ return pri->bri && (((pri)->localtype == PRI_NETWORK) && ((pri)->tei == Q921_TEI_GROUP));
++}
++
++static inline int BRI_TE_PTMP(struct pri *mypri)
++{
++ struct pri *pri;
++
++ pri = PRI_MASTER(mypri);
++
++ return pri->bri && (((pri)->localtype == PRI_CPE) && ((pri)->tei == Q921_TEI_GROUP));
++}
++
++static inline int PRI_PTP(struct pri *mypri)
++{
++ struct pri *pri;
++
++ pri = PRI_MASTER(mypri);
++
++ return !pri->bri;
++}
++
++#define Q931_DUMMY_CALL_REFERENCE -1
++
++/*!
++ * \brief Deterimine if the given call control pointer is a dummy call.
++ *
++ * \retval TRUE if given call is a dummy call.
++ * \retval FALSE otherwise.
++ */
++static inline int q931_is_dummy_call(const q931_call *call)
++{
++ return (call->cr == Q931_DUMMY_CALL_REFERENCE) ? 1 : 0;
++}
++
+ #endif
+Index: rose_qsig_name.c
+===================================================================
+--- a/rose_qsig_name.c (.../tags/1.4.10.2) (revision 0)
++++ b/rose_qsig_name.c (.../branches/1.4) (revision 1357)
+@@ -0,0 +1,474 @@
++/*
++ * libpri: An implementation of Primary Rate ISDN
++ *
++ * Copyright (C) 2009 Digium, Inc.
++ *
++ * Richard Mudgett <rmudgett@digium.com>
++ *
++ * See http://www.asterisk.org for more information about
++ * the Asterisk project. Please do not directly contact
++ * any of the maintainers of this project for assistance;
++ * the project provides a web site, mailing lists and IRC
++ * channels for your use.
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License Version 2 as published by the
++ * Free Software Foundation. See the LICENSE file included with
++ * this program for more details.
++ *
++ * In addition, when this program is distributed with Asterisk in
++ * any form that would qualify as a 'combined work' or as a
++ * 'derivative work' (but not mere aggregation), you can redistribute
++ * and/or modify the combination under the terms of the license
++ * provided with that copy of Asterisk, instead of the license
++ * terms granted here.
++ */
++
++/*!
++ * \file
++ * \brief Q.SIG ROSE Name operations and elements
++ *
++ * Name-Operations ECMA-164 Annex C
++ *
++ * \author Richard Mudgett <rmudgett@digium.com>
++ */
++
++
++#include "compat.h"
++#include "libpri.h"
++#include "pri_internal.h"
++#include "rose.h"
++#include "rose_internal.h"
++#include "asn1.h"
++
++
++/* ------------------------------------------------------------------- */
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG NameSet type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param tag Component tag to identify the encoded component.
++ * The tag should be ASN1_TAG_SEQUENCE unless the caller
++ * implicitly tags it otherwise.
++ * \param name
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_NameSet(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, unsigned tag, const struct roseQsigName *name)
++{
++ unsigned char *seq_len;
++
++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag);
++
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_OCTET_STRING, name->data,
++ name->length));
++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, name->char_set));
++
++ ASN1_CONSTRUCTED_END(seq_len, pos, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Encode the Q.SIG Name type.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param name
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_Name(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const struct roseQsigName *name)
++{
++ switch (name->presentation) {
++ case 0: /* optional_name_not_present */
++ /* Do not encode anything */
++ break;
++ case 1: /* presentation_allowed */
++ if (name->char_set == 1) {
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0,
++ name->data, name->length));
++ } else {
++ ASN1_CALL(pos, rose_enc_qsig_NameSet(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, name));
++ }
++ break;
++ case 2: /* presentation_restricted */
++ if (name->char_set == 1) {
++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2,
++ name->data, name->length));
++ } else {
++ ASN1_CALL(pos, rose_enc_qsig_NameSet(ctrl, pos, end,
++ ASN1_CLASS_CONTEXT_SPECIFIC | 3, name));
++ }
++ break;
++ case 3: /* presentation_restricted_null */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 7));
++ break;
++ case 4: /* name_not_available */
++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4));
++ break;
++ default:
++ ASN1_ENC_ERROR(ctrl, "Unknown name presentation");
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Encode the Q.SIG party-Name invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param party Information to encode.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++static unsigned char *rose_enc_qsig_PartyName_ARG_Backend(struct pri *ctrl,
++ unsigned char *pos, unsigned char *end, const struct roseQsigPartyName_ARG *party)
++{
++ return rose_enc_qsig_Name(ctrl, pos, end, &party->name);
++}
++
++/*!
++ * \brief Encode the Q.SIG CallingName invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CallingName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return rose_enc_qsig_PartyName_ARG_Backend(ctrl, pos, end, &args->qsig.CallingName);
++}
++
++/*!
++ * \brief Encode the Q.SIG CalledName invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_CalledName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return rose_enc_qsig_PartyName_ARG_Backend(ctrl, pos, end, &args->qsig.CalledName);
++}
++
++/*!
++ * \brief Encode the Q.SIG ConnectedName invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_ConnectedName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return rose_enc_qsig_PartyName_ARG_Backend(ctrl, pos, end,
++ &args->qsig.ConnectedName);
++}
++
++/*!
++ * \brief Encode the Q.SIG BusyName invoke facility ie arguments.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param pos Starting position to encode ASN.1 component.
++ * \param end End of ASN.1 encoding data buffer.
++ * \param args Arguments to encode in the buffer.
++ *
++ * \retval Start of the next ASN.1 component to encode on success.
++ * \retval NULL on error.
++ */
++unsigned char *rose_enc_qsig_BusyName_ARG(struct pri *ctrl, unsigned char *pos,
++ unsigned char *end, const union rose_msg_invoke_args *args)
++{
++ return rose_enc_qsig_PartyName_ARG_Backend(ctrl, pos, end, &args->qsig.BusyName);
++}
++
++/*!
++ * \internal
++ * \brief Decode the Q.SIG NameData Name argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param fname Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param name Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_NameData(struct pri *ctrl, const char *fname,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigName *name)
++{
++ size_t str_len;
++
++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, fname, tag, pos, end, sizeof(name->data),
++ name->data, &str_len));
++ name->length = str_len;
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the Q.SIG NameSet Name argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param fname Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param name Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_NameSet(struct pri *ctrl, const char *fname,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigName *name)
++{
++ int32_t value;
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s NameSet %s\n", fname, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_TYPE_OCTET_STRING);
++ ASN1_CALL(pos, rose_dec_qsig_NameData(ctrl, "nameData", tag, pos, seq_end, name));
++
++ if (pos < end && *pos != ASN1_INDEF_TERM) {
++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag));
++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER);
++ ASN1_CALL(pos, asn1_dec_int(ctrl, "characterSet", tag, pos, seq_end, &value));
++ name->char_set = value;
++ } else {
++ name->char_set = 1; /* default to iso8859-1 */
++ }
++
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG Name argument parameters.
++ *
++ * \param ctrl D channel controller for any diagnostic messages.
++ * \param fname Field name
++ * \param tag Component tag that identified this production.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param name Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_Name(struct pri *ctrl, const char *fname,
++ unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigName *name)
++{
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s Name\n", fname);
++ }
++ name->char_set = 1; /* default to iso8859-1 */
++ switch (tag & ~ASN1_PC_MASK) {
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0:
++ name->presentation = 1; /* presentation_allowed */
++ ASN1_CALL(pos, rose_dec_qsig_NameData(ctrl, "namePresentationAllowedSimple", tag,
++ pos, end, name));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1:
++ /* Must be constructed but we will not check for it for simplicity. */
++ name->presentation = 1; /* presentation_allowed */
++ ASN1_CALL(pos, rose_dec_qsig_NameSet(ctrl, "namePresentationAllowedExtended",
++ tag, pos, end, name));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2:
++ name->presentation = 2; /* presentation_restricted */
++ ASN1_CALL(pos, rose_dec_qsig_NameData(ctrl, "namePresentationRestrictedSimple",
++ tag, pos, end, name));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3:
++ /* Must be constructed but we will not check for it for simplicity. */
++ name->presentation = 2; /* presentation_restricted */
++ ASN1_CALL(pos, rose_dec_qsig_NameSet(ctrl, "namePresentationRestrictedExtended",
++ tag, pos, end, name));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ name->presentation = 4; /* name_not_available */
++ name->length = 0;
++ name->data[0] = 0;
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "nameNotAvailable", tag, pos, end));
++ break;
++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7:
++ /* Must not be constructed but we will not check for it for simplicity. */
++ name->presentation = 3; /* presentation_restricted_null */
++ name->length = 0;
++ name->data[0] = 0;
++ ASN1_CALL(pos, asn1_dec_null(ctrl, "namePresentationRestrictedNull", tag, pos,
++ end));
++ break;
++ default:
++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag);
++ return NULL;
++ }
++
++ return pos;
++}
++
++/*!
++ * \internal
++ * \brief Decode the Q.SIG party-Name invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param name Field name
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param party Parameter storage to fill.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++static const unsigned char *rose_dec_qsig_PartyName_ARG_Backend(struct pri *ctrl,
++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end,
++ struct roseQsigPartyName_ARG *party)
++{
++ int length;
++ int seq_offset;
++ const unsigned char *seq_end;
++
++ if (tag == ASN1_TAG_SEQUENCE) {
++ if (ctrl->debug & PRI_DEBUG_APDU) {
++ pri_message(ctrl, " %s %s\n", name, asn1_tag2str(tag));
++ }
++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length));
++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end);
++
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "name", tag, pos, seq_end,
++ &party->name));
++
++ /* Fixup will skip over any OPTIONAL manufacturer extension information */
++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end);
++ } else {
++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, name, tag, pos, end, &party->name));
++ }
++
++ return pos;
++}
++
++/*!
++ * \brief Decode the Q.SIG CallingName invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CallingName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ return rose_dec_qsig_PartyName_ARG_Backend(ctrl, "callingName", tag, pos, end,
++ &args->qsig.CallingName);
++}
++
++/*!
++ * \brief Decode the Q.SIG CalledName invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_CalledName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ return rose_dec_qsig_PartyName_ARG_Backend(ctrl, "calledName", tag, pos, end,
++ &args->qsig.CalledName);
++}
++
++/*!
++ * \brief Decode the Q.SIG ConnectedName invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_ConnectedName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ return rose_dec_qsig_PartyName_ARG_Backend(ctrl, "connectedName", tag, pos, end,
++ &args->qsig.ConnectedName);
++}
++
++/*!
++ * \brief Decode the Q.SIG BusyName invoke argument parameters.
++ *
++ * \param ctrl D channel controller for diagnostic messages or global options.
++ * \param tag Component tag that identified this structure.
++ * \param pos Starting position of the ASN.1 component length.
++ * \param end End of ASN.1 decoding data buffer.
++ * \param args Arguments to fill in from the decoded buffer.
++ *
++ * \retval Start of the next ASN.1 component on success.
++ * \retval NULL on error.
++ */
++const unsigned char *rose_dec_qsig_BusyName_ARG(struct pri *ctrl, unsigned tag,
++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args)
++{
++ return rose_dec_qsig_PartyName_ARG_Backend(ctrl, "busyName", tag, pos, end,
++ &args->qsig.BusyName);
++}
++
++/* ------------------------------------------------------------------- */
++/* end rose_qsig_name.c */
+
+Property changes on: rose_qsig_name.c
+___________________________________________________________________
+Added: svn:eol-style
+ + native
+Added: svn:mime-type
+ + text/plain
+Added: svn:keywords
+ + 'Author Date Id Revision'
+
+Index: q921.c
+===================================================================
+--- a/q921.c (.../tags/1.4.10.2) (revision 1357)
++++ b/q921.c (.../branches/1.4) (revision 1357)
+@@ -27,6 +27,7 @@
+ * terms granted here.
+ */
+
++#include <stdint.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+@@ -139,8 +140,7 @@
+ #endif
+ pri->ri = random() % 65535;
+ q921_send_tei(pri, Q921_TEI_IDENTITY_REQUEST, pri->ri, Q921_TEI_GROUP, 1);
+- if (pri->t202_timer)
+- pri_schedule_del(pri, pri->t202_timer);
++ pri_schedule_del(pri, pri->t202_timer);
+ pri->t202_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T202], q921_tei_request, pri);
+ }
+
+@@ -174,8 +174,8 @@
+ {
+ struct pri *pri = vpri;
+ q921_h h;
++
+ pri_schedule_del(pri, pri->sabme_timer);
+- pri->sabme_timer = 0;
+ pri->sabme_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], q921_send_sabme_now, pri);
+ if (!now)
+ return;
+@@ -248,14 +248,12 @@
+
+ static void t203_expire(void *);
+ static void t200_expire(void *);
+-static pri_event *q921_dchannel_down(struct pri *pri);
+
+ static void reschedule_t200(struct pri *pri)
+ {
+ if (pri->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(pri, "-- Restarting T200 timer\n");
+- if (pri->t200_timer)
+- pri_schedule_del(pri, pri->t200_timer);
++ pri_schedule_del(pri, pri->t200_timer);
+ pri->t200_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
+ }
+
+@@ -263,8 +261,7 @@
+ {
+ if (pri->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(pri, "-- Restarting T203 timer\n");
+- if (pri->t203_timer)
+- pri_schedule_del(pri, pri->t203_timer);
++ pri_schedule_del(pri, pri->t203_timer);
+ pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
+ }
+
+@@ -312,10 +309,8 @@
+ if (pri->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(pri, "-- Since there was nothing left, stopping T200 counter\n");
+ /* Something was ACK'd. Stop T200 counter */
+- if (pri->t200_timer) {
+- pri_schedule_del(pri, pri->t200_timer);
+- pri->t200_timer = 0;
+- }
++ pri_schedule_del(pri, pri->t200_timer);
++ pri->t200_timer = 0;
+ }
+ if (pri->t203_timer) {
+ if (pri->debug & PRI_DEBUG_Q921_DUMP)
+@@ -483,6 +478,45 @@
+ }
+ }
+
++int q921_transmit_uiframe(struct pri *pri, void *buf, int len)
++{
++ uint8_t ubuf[512];
++ q921_h *h = (void *)&ubuf[0];
++
++ if (len >= 512) {
++ pri_error(pri, "Requested to send UI frame larger than 512 bytes!\n");
++ return -1;
++ }
++
++ memset(ubuf, 0, sizeof(ubuf));
++ h->h.sapi = 0;
++ h->h.ea1 = 0;
++ h->h.ea2 = 1;
++ h->h.tei = pri->tei;
++ h->u.m3 = 0;
++ h->u.m2 = 0;
++ h->u.p_f = 0; /* Poll bit set */
++ h->u.ft = Q921_FRAMETYPE_U;
++
++ switch(pri->localtype) {
++ case PRI_NETWORK:
++ h->h.c_r = 1;
++ break;
++ case PRI_CPE:
++ h->h.c_r = 0;
++ break;
++ default:
++ pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
++ return -1;
++ }
++
++ memcpy(h->u.data, buf, len);
++
++ q921_transmit(pri, h, len + 3);
++
++ return 0;
++}
++
+ int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
+ {
+ q921_frame *f, *prev=NULL;
+@@ -521,6 +555,10 @@
+ pri->txqueue = f;
+ /* Immediately transmit unless we're in a recovery state, or the window
+ size is too big */
++ if (pri->debug & PRI_DEBUG_Q921_DUMP) {
++ pri_message(pri, "TEI/SAPI: %d/%d state %d retran %d busy %d\n",
++ pri->tei, pri->sapi, pri->q921_state, pri->retrans, pri->busy);
++ }
+ if ((pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) && (!pri->retrans && !pri->busy)) {
+ if (pri->windowlen < pri->window) {
+ q921_send_queued_iframes(pri);
+@@ -564,11 +602,15 @@
+ /* Start timer T200 to resend our RR if we don't get it */
+ pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
+ } else {
+- if (pri->debug & PRI_DEBUG_Q921_DUMP)
+- pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state);
++ if (pri->debug & PRI_DEBUG_Q921_DUMP) {
++ pri_message(pri,
++ "T203 counter expired in weird state %d on pri with SAPI/TEI of %d/%d\n",
++ pri->q921_state, pri->sapi, pri->tei);
++ }
+ pri->t203_timer = 0;
+ }
+ }
++
+ static pri_event *q921_handle_iframe(struct pri *pri, q921_i *i, int len)
+ {
+ int res;
+@@ -622,33 +664,34 @@
+ char *buf = malloc(len * 3 + 1);
+ int buflen = 0;
+ if (buf) {
++ pri_message(pri, "\n");
+ for (x=0;x<len;x++)
+ buflen += sprintf(buf + buflen, "%02x ", h->raw[x]);
+- pri_message(pri, "\n%c [ %s]\n", direction_tag, buf);
++ pri_message(pri, "%c [ %s]\n", direction_tag, buf);
+ free(buf);
+ }
+ }
+
++ pri_message(pri, "\n");
+ switch (h->h.data[0] & Q921_FRAMETYPE_MASK) {
+ case 0:
+ case 2:
+- pri_message(pri, "\n%c Informational frame:\n", direction_tag);
++ pri_message(pri, "%c Informational frame:\n", direction_tag);
+ break;
+ case 1:
+- pri_message(pri, "\n%c Supervisory frame:\n", direction_tag);
++ pri_message(pri, "%c Supervisory frame:\n", direction_tag);
+ break;
+ case 3:
+- pri_message(pri, "\n%c Unnumbered frame:\n", direction_tag);
++ pri_message(pri, "%c Unnumbered frame:\n", direction_tag);
+ break;
+ }
+
+- pri_message(pri,
+-"%c SAPI: %02d C/R: %d EA: %d\n"
+-"%c TEI: %03d EA: %d\n",
++ pri_message(pri, "%c SAPI: %02d C/R: %d EA: %d\n",
+ direction_tag,
+ h->h.sapi,
+ h->h.c_r,
+- h->h.ea1,
++ h->h.ea1);
++ pri_message(pri, "%c TEI: %03d EA: %d\n",
+ direction_tag,
+ h->h.tei,
+ h->h.ea2);
+@@ -658,15 +701,17 @@
+ case 2:
+ /* Informational frame */
+ pri_message(pri,
+-"%c N(S): %03d 0: %d\n"
+-"%c N(R): %03d P: %d\n"
+-"%c %d bytes of data\n",
++"%c N(S): %03d 0: %d\n",
+ direction_tag,
+ h->i.n_s,
+- h->i.ft,
++ h->i.ft);
++ pri_message(pri,
++"%c N(R): %03d P: %d\n",
+ direction_tag,
+ h->i.n_r,
+- h->i.p_f,
++ h->i.p_f);
++ pri_message(pri,
++"%c %d bytes of data\n",
+ direction_tag,
+ len - 4);
+ break;
+@@ -685,17 +730,19 @@
+ break;
+ }
+ pri_message(pri,
+-"%c Zero: %d S: %d 01: %d [ %s ]\n"
+-"%c N(R): %03d P/F: %d\n"
+-"%c %d bytes of data\n",
++"%c Zero: %d S: %d 01: %d [ %s ]\n",
+ direction_tag,
+ h->s.x0,
+ h->s.ss,
+ h->s.ft,
+- type,
++ type);
++ pri_message(pri,
++"%c N(R): %03d P/F: %d\n",
+ direction_tag,
+ h->s.n_r,
+- h->s.p_f,
++ h->s.p_f);
++ pri_message(pri,
++"%c %d bytes of data\n",
+ direction_tag,
+ len - 4);
+ break;
+@@ -731,14 +778,15 @@
+ }
+ }
+ pri_message(pri,
+-"%c M3: %d P/F: %d M2: %d 11: %d [ %s ]\n"
+-"%c %d bytes of data\n",
++"%c M3: %d P/F: %d M2: %d 11: %d [ %s ]\n",
+ direction_tag,
+ h->u.m3,
+ h->u.p_f,
+ h->u.m2,
+ h->u.ft,
+- type,
++ type);
++ pri_message(pri,
++"%c %d bytes of data\n",
+ direction_tag,
+ len - 3);
+ break;
+@@ -783,7 +831,7 @@
+ }
+ }
+
+-static pri_event *q921_dchannel_up(struct pri *pri)
++pri_event *q921_dchannel_up(struct pri *pri)
+ {
+ if (pri->tei == Q921_TEI_PRI) {
+ q921_reset(pri, 1);
+@@ -792,10 +840,8 @@
+ }
+
+ /* Stop any SABME retransmissions */
+- if (pri->sabme_timer) {
+- pri_schedule_del(pri, pri->sabme_timer);
+- pri->sabme_timer = 0;
+- }
++ pri_schedule_del(pri, pri->sabme_timer);
++ pri->sabme_timer = 0;
+
+ /* Reset any rejects */
+ pri->sentrej = 0;
+@@ -805,7 +851,12 @@
+ pri_message(pri, DBGHEAD "q921_state now is Q921_LINK_CONNECTION_ESTABLISHED\n", DBGINFO);
+ pri->q921_state = Q921_LINK_CONNECTION_ESTABLISHED;
+
++ /* Ensure that we do not have T200 or T203 running when the link comes up */
++ pri_schedule_del(pri, pri->t200_timer);
++ pri->t200_timer = 0;
++
+ /* Start the T203 timer */
++ pri_schedule_del(pri, pri->t203_timer);
+ pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
+
+ /* Notify Layer 3 */
+@@ -818,7 +869,7 @@
+ return &pri->ev;
+ }
+
+-static pri_event *q921_dchannel_down(struct pri *pri)
++pri_event *q921_dchannel_down(struct pri *pri)
+ {
+ /* Reset counters, reset sabme timer etc */
+ q921_reset(pri, 1);
+@@ -826,7 +877,7 @@
+ /* Notify Layer 3 */
+ q931_dl_indication(pri, PRI_EVENT_DCHAN_DOWN);
+
+- /* Report event that D-Channel is now up */
++ /* Report event that D-Channel is now down */
+ pri->ev.gen.e = PRI_EVENT_DCHAN_DOWN;
+ return &pri->ev;
+ }
+@@ -842,12 +893,9 @@
+ pri->v_na = 0;
+ pri->window = pri->timers[PRI_TIMER_K];
+ pri->windowlen = 0;
+- if (pri->sabme_timer)
+- pri_schedule_del(pri, pri->sabme_timer);
+- if (pri->t203_timer)
+- pri_schedule_del(pri, pri->t203_timer);
+- if (pri->t200_timer)
+- pri_schedule_del(pri, pri->t200_timer);
++ pri_schedule_del(pri, pri->sabme_timer);
++ pri_schedule_del(pri, pri->t203_timer);
++ pri_schedule_del(pri, pri->t200_timer);
+ pri->sabme_timer = 0;
+ pri->sabme_count = 0;
+ pri->t203_timer = 0;
+@@ -879,8 +927,14 @@
+ static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
+ {
+ int ri;
+- struct pri *sub;
++ struct pri *sub = pri;
+ int tei;
++
++ if (!BRI_NT_PTMP(pri) && !BRI_TE_PTMP(pri)) {
++ pri_error(pri, "Received MDL/TEI managemement message, but configured for mode other than PTMP!\n");
++ return NULL;
++ }
++
+ if (pri->debug & PRI_DEBUG_Q921_STATE)
+ pri_message(pri, "Received MDL message\n");
+ if (h->data[0] != 0x0f) {
+@@ -895,16 +949,19 @@
+ tei = (h->data[4] >> 1);
+ switch(h->data[3]) {
+ case Q921_TEI_IDENTITY_REQUEST:
++ if (!BRI_NT_PTMP(pri)) {
++ return NULL;
++ }
++
+ if (tei != 127) {
+ pri_error(pri, "Received TEI identity request with invalid TEI %d\n", tei);
+ q921_send_tei(pri, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
+ }
+- /* Go to master */
+- for (sub = pri; sub->master; sub = sub->master);
+ tei = 64;
+- while(sub->subchannel) {
+- if(sub->subchannel->tei == tei)
++ while (sub->subchannel) {
++ if (sub->subchannel->tei == tei)
+ ++tei;
++ sub = sub->subchannel;
+ }
+ sub->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1);
+ if (!sub->subchannel) {
+@@ -914,14 +971,15 @@
+ q921_send_tei(pri, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
+ break;
+ case Q921_TEI_IDENTITY_ASSIGNED:
++ if (!BRI_TE_PTMP(pri))
++ return NULL;
++
+ if (ri != pri->ri) {
+ pri_message(pri, "TEI assignment received for invalid Ri %02x (our is %02x)\n", ri, pri->ri);
+ return NULL;
+ }
+- if (pri->t202_timer) {
+- pri_schedule_del(pri, pri->t202_timer);
+- pri->t202_timer = 0;
+- }
++ pri_schedule_del(pri, pri->t202_timer);
++ pri->t202_timer = 0;
+ if (pri->subchannel && (pri->subchannel->tei == tei)) {
+ pri_error(pri, "TEI already assigned (new is %d, current is %d)\n", tei, pri->subchannel->tei);
+ q921_tei_release_and_reacquire(pri);
+@@ -937,6 +995,8 @@
+ pri->q921_state = Q921_TEI_ASSIGNED;
+ break;
+ case Q921_TEI_IDENTITY_CHECK_REQUEST:
++ if (!BRI_TE_PTMP(pri))
++ return NULL;
+ /* We're assuming one TEI per PRI in TE PTMP mode */
+
+ /* If no subchannel (TEI) ignore */
+@@ -949,6 +1009,8 @@
+
+ break;
+ case Q921_TEI_IDENTITY_REMOVE:
++ if (!BRI_TE_PTMP(pri))
++ return NULL;
+ /* XXX: Assuming multiframe mode has been disconnected already */
+ if (!pri->subchannel)
+ return NULL;
+@@ -990,6 +1052,10 @@
+ pri_error(pri, "!! Received short I-frame (expected 4, got %d)\n", len);
+ break;
+ }
++
++ /* T203 is rescheduled only on reception of I frames or S frames */
++ reschedule_t203(pri);
++
+ return q921_handle_iframe(pri, &h->i, len);
+ break;
+ case 1:
+@@ -1001,6 +1067,10 @@
+ pri_error(pri, "!! Received short S-frame (expected 4, got %d)\n", len);
+ break;
+ }
++
++ /* T203 is rescheduled only on reception of I frames or S frames */
++ reschedule_t203(pri);
++
+ switch(h->s.ss) {
+ case 0:
+ /* Receiver Ready */
+@@ -1091,10 +1161,8 @@
+ }
+ }
+ /* Reset t200 timer if it was somehow going */
+- if (pri->t200_timer) {
+- pri_schedule_del(pri, pri->t200_timer);
+- pri->t200_timer = 0;
+- }
++ pri_schedule_del(pri, pri->t200_timer);
++ pri->t200_timer = 0;
+ /* Reset and restart t203 timer */
+ reschedule_t203(pri);
+ }
+@@ -1152,7 +1220,9 @@
+ /* Acknowledge */
+ q921_send_ua(pri, h->u.p_f);
+ ev = q921_dchannel_down(pri);
+- q921_restart(pri, 0);
++ if (BRI_TE_PTMP(pri) || PRI_PTP(pri)) {
++ q921_restart(pri, PRI_PTP(pri) ? 1 : 0);
++ }
+ return ev;
+ case 3:
+ if (h->u.m2 == 3) {
+@@ -1212,6 +1282,34 @@
+ return NULL;
+ }
+
++static pri_event *q921_handle_unmatched_frame(struct pri *pri, q921_h *h, int len)
++{
++ pri = PRI_MASTER(pri);
++
++ if (h->h.tei < 64) {
++ pri_error(pri, "Do not support manual TEI range. Discarding\n");
++ return NULL;
++ }
++
++ if (h->h.sapi != Q921_SAPI_CALL_CTRL) {
++ pri_error(pri, "Message with SAPI other than CALL CTRL is discarded\n");
++ return NULL;
++ }
++
++ if (pri->debug & PRI_DEBUG_Q921_DUMP) {
++ pri_message(pri,
++ "Could not find candidate subchannel for received frame with SAPI/TEI of %d/%d.\n",
++ h->h.sapi, h->h.tei);
++ pri_message(pri, "Sending TEI release, in order to re-establish TEI state\n");
++ }
++
++ /* Q.921 says we should send the remove message twice, in case of link corruption */
++ q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1);
++ q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1);
++
++ return NULL;
++}
++
+ static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
+ {
+ pri_event *ev;
+@@ -1225,26 +1323,22 @@
+ if (h->h.ea1 || !(h->h.ea2))
+ return NULL;
+
+-#if 0 /* Will be rejected by subchannel analyzis */
+- /* Check for broadcasts - not yet handled */
+- if (h->h.tei == Q921_TEI_GROUP)
+- return NULL;
+-#endif
+-
+ if (!((h->h.sapi == pri->sapi) && ((h->h.tei == pri->tei) || (h->h.tei == Q921_TEI_GROUP)))) {
+ /* Check for SAPIs we don't yet handle */
+ /* If it's not us, try any subchannels we have */
+ if (pri->subchannel)
+ return q921_receive(pri->subchannel, h, len + 2);
+ else {
+- return NULL;
++ /* This means we couldn't find a candidate subchannel for it...
++ * Time for some corrective action */
++
++ return q921_handle_unmatched_frame(pri, h, len);
+ }
+
+ }
+ if (pri->debug & PRI_DEBUG_Q921_DUMP)
+ pri_message(pri, "Handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei);
+ ev = __q921_receive_qualified(pri, h, len);
+- reschedule_t203(pri);
+ return ev;
+ }
+
+
+Property changes on: .
+___________________________________________________________________
+Added: reviewboard:url
+ + https://reviewboard.asterisk.org
+
diff --git a/main/libpri/libpri-1.4.9-i14292.patch b/main/libpri/libpri-1.4.9-i14292.patch
deleted file mode 100644
index 27ed1b8d43..0000000000
--- a/main/libpri/libpri-1.4.9-i14292.patch
+++ /dev/null
@@ -1,5668 +0,0 @@
-Index: .version
-===================================================================
---- a/.version (.../tags/1.4.9) (revision 700)
-+++ b/.version (.../team/group/issue14292) (revision 700)
-@@ -1 +1 @@
--1.4.9
-+1.4.9-issue14292
-Index: pri_facility.c
-===================================================================
---- a/pri_facility.c (.../tags/1.4.9) (revision 700)
-+++ b/pri_facility.c (.../team/group/issue14292) (revision 700)
-@@ -171,7 +171,7 @@
-
- struct addressingdataelements_presentednumberunscreened {
- char partyaddress[21];
-- char partysubaddress[21];
-+ char notused[21];
- int npi; /* Numbering Plan Indicator */
- int ton; /* Type Of Number */
- int pres; /* Presentation */
-@@ -179,6 +179,15 @@
-
- struct addressingdataelements_presentednumberscreened {
- char partyaddress[21];
-+ char notused[21];
-+ int npi; /* Numbering Plan Indicator */
-+ int ton; /* Type Of Number */
-+ int pres; /* Presentation */
-+ int scrind; /* Screening Indicator */
-+};
-+
-+struct addressingdataelements_presentedaddressscreened {
-+ char partyaddress[21];
- char partysubaddress[21];
- int npi; /* Numbering Plan Indicator */
- int ton; /* Type Of Number */
-@@ -186,6 +195,35 @@
- int scrind; /* Screening Indicator */
- };
-
-+struct addressingdataelements_addressscreened {
-+ char partyaddress[21];
-+ char partysubaddress[21];
-+ int npi; /* Numbering Plan Indicator */
-+ int ton; /* Type Of Number */
-+ int notused;
-+ int scrind; /* Screening Indicator */
-+};
-+
-+struct addressingdataelements_partysubaddress {
-+ char notused[21];
-+ char partysubaddress[21];
-+};
-+
-+struct nameelements_name {
-+ char name[51];
-+ int characterset;
-+ int namepres;
-+};
-+
-+struct nameelements_nameset {
-+ char name[51];
-+ int characterset;
-+};
-+
-+struct nameelements_namedata {
-+ char name[51];
-+};
-+
- #define PRI_CHECKOVERFLOW(size) \
- if (msgptr - message + (size) >= sizeof(message)) { \
- *msgptr = '\0'; \
-@@ -225,6 +263,92 @@
- }
- #undef PRI_CHECKOVERFLOW
-
-+static const char *namepres_to_str(int namepres)
-+{
-+ return (namepres == 0) ? "Restricted" : "Allowed";
-+}
-+
-+static const char *characterset_to_str(int characterset)
-+{
-+ switch (characterset) {
-+ case CHARACTER_SET_UNKNOWN:
-+ return "Unknown";
-+ case CHARACTER_SET_ISO8859_1:
-+ return "ISO8859-1";
-+ case CHARACTER_SET_ISO8859_2:
-+ return "ISO8859-2";
-+ case CHARACTER_SET_ISO8859_3:
-+ return "ISO8859-3";
-+ case CHARACTER_SET_ISO8859_4:
-+ return "ISO8859-4";
-+ case CHARACTER_SET_ISO8859_5:
-+ return "ISO8859-5";
-+ case CHARACTER_SET_ISO8859_7:
-+ return "ISO8859-7";
-+ default:
-+ return "illegal value";
-+ }
-+}
-+
-+static const char *diversionreason_to_str(struct pri *pri, int diversionreason)
-+{
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ switch (diversionreason) {
-+ case QSIG_DIVERT_REASON_UNKNOWN:
-+ return "Unknown";
-+ case QSIG_DIVERT_REASON_CFU:
-+ return "Call Forwarding Unconditional";
-+ case QSIG_DIVERT_REASON_CFB:
-+ return "Call Forwarding Busy";
-+ case QSIG_DIVERT_REASON_CFNR:
-+ return "Call Forwarding No Reply";
-+ default:
-+ return "invalid value";
-+ }
-+ } else {
-+ switch(diversionreason) {
-+ case Q952_DIVERT_REASON_UNKNOWN:
-+ return "Unknown";
-+ case Q952_DIVERT_REASON_CFU:
-+ return "Call Forwarding Unconditional";
-+ case Q952_DIVERT_REASON_CFB:
-+ return "Call Forwarding Busy";
-+ case Q952_DIVERT_REASON_CFNR:
-+ return "Call Forwarding No Reply";
-+ case Q952_DIVERT_REASON_CD:
-+ return "Call Deflection";
-+ case Q952_DIVERT_REASON_IMMEDIATE:
-+ return "Call Deflection Immediate";
-+ default:
-+ return "invalid value";
-+ }
-+ }
-+}
-+
-+static const char *callstatus_to_str(int callstatus)
-+{
-+ switch (callstatus) {
-+ case 0:
-+ return "answered";
-+ case 1:
-+ return "alerting";
-+ default:
-+ return "illegal value";
-+ }
-+}
-+
-+static const char *enddesignation_to_str(int enddesignation)
-+{
-+ switch (enddesignation) {
-+ case 0:
-+ return "primaryEnd";
-+ case 1:
-+ return "secondaryEnd";
-+ default:
-+ return "illegal value";
-+ }
-+}
-+
- int redirectingreason_from_q931(struct pri *pri, int redirectingreason)
- {
- switch(pri->switchtype) {
-@@ -350,8 +474,25 @@
- }
- }
-
--int asn1_name_decode(void * data, int len, char *namebuf, int buflen)
-+static int presentation_to_subscription(struct pri *pri, int presentation)
- {
-+ /* derive subscription value from presentation value */
-+
-+ switch (presentation & PRES_RESTRICTION) {
-+ case PRES_ALLOWED:
-+ return QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR;
-+ case PRES_RESTRICTED:
-+ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR;
-+ case PRES_UNAVAILABLE: /* Number not available due to interworking */
-+ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR; /* ?? QSIG_NO_NOTIFICATION */
-+ default:
-+ pri_message(pri, "!! Unknown Q.SIG presentationIndicator 0x%02x\n", presentation);
-+ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR;
-+ }
-+}
-+
-+int asn1_name_decode(void *data, int len, char *namebuf, int buflen)
-+{
- struct rose_component *comp = (struct rose_component*)data;
- int datalen = 0, res = 0;
-
-@@ -361,11 +502,13 @@
- } else
- datalen = res = comp->len;
-
-- if (datalen > buflen) {
-+ if (datalen > buflen - 1) {
- /* Truncate */
- datalen = buflen;
- }
- memcpy(namebuf, comp->data, datalen);
-+ namebuf[datalen] = '\0';
-+
- return res + 2;
- }
-
-@@ -407,42 +550,230 @@
- return res;
- }
-
--static int rose_number_digits_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
-+static int rose_namedata_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct nameelements_namedata *value)
- {
- int i = 0;
- struct rose_component *comp = NULL;
- unsigned char *vdata = data;
-- int datalen = 0;
-- int res = 0;
-+ int res;
-
- do {
-+ /* NameData */
-+ if (!implicit) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if NameData is of type 0x%x\n");
-+
-+ data = comp->data;
-+ if (comp->len == ASN1_LEN_INDEF) {
-+ len = strlen((char *)comp->data);
-+ res = len + 2 + 2;
-+ } else {
-+ len = comp->len;
-+ res = len + 2;
-+ }
-+ } else
-+ res = len;
-+
-+ if (len > sizeof(value->name)-1) {
-+ pri_message(pri, "!! Oversized NameData component (%d)\n", len);
-+ return -1;
-+ }
-+
-+ memcpy(value->name, data, len);
-+ value->name[len] = '\0';
-+
-+ return res;
-+ }
-+ while(0);
-+
-+ return -1;
-+}
-+
-+static int rose_namedata_encode(struct pri *pri, unsigned char *dst, int implicit, char *name)
-+{
-+ int size = 0;
-+ struct rose_component *comp;
-+ int namesize;
-+
-+ namesize = strlen(name);
-+ if (namesize > 50 ) {
-+ pri_message(pri, "!! Encoding of oversized NameData component failed (%d)\n", namesize);
-+ return -1;
-+ } else if (namesize == 0){
-+ pri_message(pri, "!! Encoding of undersized NameData component failed (%d)\n", namesize);
-+ return -1;
-+ }
-+
-+ if (!implicit) {
-+ /* constructor component (0x04,len) */
-+ comp = (struct rose_component *)dst;
-+ comp->type = ASN1_OCTETSTRING;
-+ comp->len = 2 + namesize;
-+ size += 2;
-+ dst += 2;
-+ }
-+
-+ memcpy(dst, name, namesize);
-+ size += namesize;
-+
-+ return size;
-+}
-+
-+static int rose_nameset_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct nameelements_nameset *value)
-+{
-+ int size;
-+ int i = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = data;
-+ int characterset;
-+
-+ value->characterset = CHARACTER_SET_ISO8859_1;
-+
-+ do {
-+ /* NameSet */
-+ if (!implicit) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Don't know what to do if NameSet is of type 0x%x\n");
-+ SUB_COMPONENT(comp, i);
-+ }
-+
-+ /* nameData NameData */
- GET_COMPONENT(comp, i, vdata, len);
-- CHECK_COMPONENT(comp, ASN1_NUMERICSTRING, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n");
-- if(comp->len > 20 && comp->len != ASN1_LEN_INDEF) {
-- pri_message(pri, "!! Oversized NumberDigits component (%d)\n", comp->len);
-+ size = rose_namedata_decode(pri, (u_int8_t *)comp, len, 0, (struct nameelements_namedata *)value);
-+ if (size < 0)
- return -1;
-+ i += size;
-+
-+ if (i < len) {
-+ /* characterSet CharacterSet OPTIONAL */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if CharacterSet is of type 0x%x\n");
-+ ASN1_GET_INTEGER(comp, characterset);
-+ NEXT_COMPONENT(comp, i);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " NameSet: Received characterSet=%s(%d)\n", characterset_to_str(characterset), characterset);
-+ value->characterset = characterset;
- }
-- if (comp->len == ASN1_LEN_INDEF) {
-- datalen = strlen((char *)comp->data);
-- res = datalen + 2;
-- } else
-- res = datalen = comp->len;
--
-- memcpy(value->partyaddress, comp->data, datalen);
-- value->partyaddress[datalen] = '\0';
-
-- return res + 2;
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " NameSet: '%s', characterSet=%s(%d) i=%d len=%d\n", value->name, characterset_to_str(value->characterset), value->characterset, i, len);
-+
-+ return i;
- }
- while(0);
-
- return -1;
- }
-
--static int rose_public_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
-+static int rose_name_decode(struct pri *pri, unsigned char *data, int len, struct nameelements_name *value)
- {
- int i = 0;
-+ int size = 0;
- struct rose_component *comp = NULL;
- unsigned char *vdata = data;
-+
-+ value->name[0] = '\0';
-+ value->characterset = CHARACTER_SET_UNKNOWN;
-+ value->namepres = -1;
-+
-+ do {
-+ GET_COMPONENT(comp, i, vdata, len);
-+
-+ switch(comp->type) {
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] namePresentationAllowedSimple */
-+ size = rose_namedata_decode(pri, comp->data, comp->len, 1, (struct nameelements_namedata *)value);
-+ if (size < 0)
-+ return -1;
-+ i += (size + 2);
-+ value->characterset = CHARACTER_SET_ISO8859_1;
-+ value->namepres = 1;
-+ break;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] namePresentationAllowedExtended */
-+ size = rose_nameset_decode(pri, comp->data, comp->len, 1, (struct nameelements_nameset *)value);
-+ if (size < 0)
-+ return -1;
-+ i += (size + 2);
-+ value->namepres = 1;
-+ break;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] namePresentationRestrictedSimple */
-+ size = rose_namedata_decode(pri, comp->data, comp->len, 1, (struct nameelements_namedata *)value);
-+ if (size < 0)
-+ return -1;
-+ i += (size + 2);
-+ value->characterset = CHARACTER_SET_ISO8859_1;
-+ value->namepres = 0;
-+ break;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] namePresentationRestrictedExtended */
-+ size = rose_nameset_decode(pri, comp->data, comp->len, 1, (struct nameelements_nameset *)value);
-+ if (size < 0)
-+ return -1;
-+ i += (size + 2);
-+ value->namepres = 0;
-+ break;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] nameNotAvailable */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_7): /* [7] namePresentationRestrictedNull */
-+ i += (comp->len + 2);
-+ value->name[0] = '\0';
-+ value->characterset = CHARACTER_SET_UNKNOWN;
-+ value->namepres = 0;
-+ break;
-+ default:
-+ pri_message(pri, "!! Unknown Name component received 0x%x\n", comp->type);
-+ return -1;
-+ }
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Name: '%s' i=%d len=%d\n", value->name, i, len);
-+ return i;
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+static int rose_number_digits_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct addressingdataelements_presentednumberunscreened *value)
-+{
-+ int i = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = data;
-+ int res = 0;
-+
-+ do {
-+ if (!implicit) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_NUMERICSTRING, "Don't know what to do with NumberDigits ROSE component type 0x%x\n");
-+
-+ data = comp->data;
-+ if (comp->len == ASN1_LEN_INDEF) {
-+ len = strlen((char *)comp->data);
-+ res = len + 2 + 2;
-+ } else {
-+ len = comp->len;
-+ res = len + 2;
-+ }
-+ } else
-+ res = len;
-+
-+ if (len > sizeof(value->partyaddress)-1) {
-+ pri_message(pri, "!! Oversized NumberDigits component (%d)\n", len);
-+ return -1;
-+ }
-+
-+ memcpy(value->partyaddress, data, len);
-+ value->partyaddress[len] = '\0';
-+
-+ return res;
-+ }
-+ while(0);
-+
-+ return -1;
-+}
-+
-+static int rose_public_party_number_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct addressingdataelements_presentednumberunscreened *value)
-+{
-+ int i = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = data;
- int ton;
- int res = 0;
-
-@@ -450,13 +781,19 @@
- return -1;
-
- do {
-+ if (!implicit) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Don't know what to do if PublicPartyNumber is of type 0x%x\n");
-+ SUB_COMPONENT(comp, i);
-+ }
-+
- GET_COMPONENT(comp, i, vdata, len);
- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n");
- ASN1_GET_INTEGER(comp, ton);
- NEXT_COMPONENT(comp, i);
- ton = typeofnumber_for_q931(pri, ton);
-
-- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value);
-+ res = rose_number_digits_decode(pri, &vdata[i], len-i, 0, value);
- if (res < 0)
- return -1;
- value->ton = ton;
-@@ -467,8 +804,48 @@
- return -1;
- }
-
--static int rose_private_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
-+static int rose_public_party_number_encode(struct pri *pri, unsigned char *dst, int implicit, unsigned char ton, char *num)
- {
-+ int i = 0, compsp = 0;
-+ struct rose_component *comp, *compstk[10];
-+ int numsize;
-+
-+ numsize = strlen(num);
-+ if (numsize > 20 ) {
-+ pri_message(pri, "!! Encoding of oversized PublicPartyNumber component failed (%d)\n", numsize);
-+ return -1;
-+ }
-+
-+ if (!implicit) {
-+ /* constructor component (0x30,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), dst, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+ } else
-+ comp = (struct rose_component *)dst;
-+
-+ /* publicTypeOfNumber (0x0a,0x01,ton)*/
-+ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, dst, i, ton);
-+
-+ /* publicNumberDigits */
-+
-+ /* tag component NumericString (0x12,len) */
-+ ASN1_ADD_SIMPLE(comp, ASN1_NUMERICSTRING, dst, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* NumericString */
-+ memcpy(comp->data, num, numsize);
-+ i += numsize;
-+
-+ ASN1_FIXUP(compstk, compsp, dst, i);
-+
-+ if (!implicit)
-+ ASN1_FIXUP(compstk, compsp, dst, i);
-+
-+ return i;
-+}
-+
-+static int rose_private_party_number_decode(struct pri *pri, unsigned char *data, int len, int implicit, struct addressingdataelements_presentednumberunscreened *value)
-+{
- int i = 0;
- struct rose_component *comp = NULL;
- unsigned char *vdata = data;
-@@ -476,18 +853,24 @@
- int res = 0;
-
- if (len < 2)
-- return -1;
-+ return -1;
-
- do {
-+ if (!implicit) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Don't know what to do if PrivatePartyNumber is of type 0x%x\n");
-+ SUB_COMPONENT(comp, i);
-+ }
-+
- GET_COMPONENT(comp, i, vdata, len);
- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PrivatePartyNumber ROSE component type 0x%x\n");
- ASN1_GET_INTEGER(comp, ton);
- NEXT_COMPONENT(comp, i);
- ton = typeofnumber_for_q931(pri, ton);
-
-- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value);
-+ res = rose_number_digits_decode(pri, &vdata[i], len-i, 0, value);
- if (res < 0)
-- return -1;
-+ return -1;
- value->ton = ton;
-
- return res + 3;
-@@ -496,7 +879,7 @@
- return -1;
- }
-
--static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
-+static int rose_address_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
- {
- int i = 0;
- struct rose_component *comp = NULL;
-@@ -506,65 +889,59 @@
- do {
- GET_COMPONENT(comp, i, vdata, len);
-
-+ /* PartyNumber */
- switch(comp->type) {
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] unknownPartyNumber */
-- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] unknownPartyNumber, IMPLICIT NumberDigits */
-+ res = rose_number_digits_decode(pri, comp->data, comp->len, 1, value);
- if (res < 0)
- return -1;
- value->npi = PRI_NPI_UNKNOWN;
- value->ton = PRI_TON_UNKNOWN;
- break;
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] unknownPartyNumber */
-- res = asn1_copy_string(value->partyaddress, sizeof(value->partyaddress), comp);
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] publicPartyNumber, IMPLICIT PublicPartyNumber */
-+ res = rose_public_party_number_decode(pri, comp->data, comp->len, 1, value);
- if (res < 0)
- return -1;
-- value->npi = PRI_NPI_UNKNOWN;
-- value->ton = PRI_TON_UNKNOWN;
-+ value->npi = PRI_NPI_E163_E164;
- break;
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] publicPartyNumber */
-- res = rose_public_party_number_decode(pri, call, comp->data, comp->len, value);
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_3): /* [3] dataPartyNumber, IMPLICIT NumberDigits */
-+ res = rose_number_digits_decode(pri, comp->data, comp->len, 1, value);
- if (res < 0)
- return -1;
-- value->npi = PRI_NPI_E163_E164;
-- break;
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* [2] nsapEncodedNumber */
-- pri_message(pri, "!! NsapEncodedNumber isn't handled\n");
-- return -1;
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] dataPartyNumber */
-- if(rose_number_digits_decode(pri, call, comp->data, comp->len, value))
-- return -1;
- value->npi = PRI_NPI_X121 /* ??? */;
- value->ton = PRI_TON_UNKNOWN /* ??? */;
- pri_message(pri, "!! dataPartyNumber isn't handled\n");
- return -1;
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] telexPartyNumber */
-- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] telexPartyNumber, IMPLICIT NumberDigits */
-+ res = rose_number_digits_decode(pri, comp->data, comp->len, 1, value);
- if (res < 0)
- return -1;
- value->npi = PRI_NPI_F69 /* ??? */;
- value->ton = PRI_TON_UNKNOWN /* ??? */;
- pri_message(pri, "!! telexPartyNumber isn't handled\n");
- return -1;
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] priavePartyNumber */
-- res = rose_private_party_number_decode(pri, call, comp->data, comp->len, value);
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] privatePartyNumber, IMPLICIT PrivatePartyNumber */
-+ res = rose_private_party_number_decode(pri, comp->data, comp->len, 1, value);
- if (res < 0)
-- return -1;
-+ return -1;
- value->npi = PRI_NPI_PRIVATE;
- break;
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] nationalStandardPartyNumber */
-- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_8): /* [8] nationalStandardPartyNumber, IMPLICIT NumberDigits */
-+ res = rose_number_digits_decode(pri, comp->data, comp->len, 1, value);
- if (res < 0)
- return -1;
- value->npi = PRI_NPI_NATIONAL;
- value->ton = PRI_TON_NATIONAL;
- break;
- default:
-- pri_message(pri, "!! Unknown Party number component received 0x%X\n", comp->type);
-+ pri_message(pri, "!! Unknown PartyNumber component received 0x%X\n", comp->type);
- return -1;
- }
- ASN1_FIXUP_LEN(comp, res);
- NEXT_COMPONENT(comp, i);
-- if(i < len)
-+
-+ /* PartySubaddress OPTIONAL */
-+ if (i < len)
- pri_message(pri, "!! not all information is handled from Address component\n");
- return res + 2;
- }
-@@ -573,14 +950,176 @@
- return -1;
- }
-
--static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
-+static int rose_party_number_encode(struct pri *pri, unsigned char *dst, unsigned char ton, char *num)
- {
-+ int i = 0, compsp = 0;
-+ struct rose_component *comp, *compstk[10];
-+ int numsize, size;
-+
-+ numsize = strlen(num);
-+ if (numsize > 20 ) {
-+ pri_message(pri, "!! Encoding of oversized PartyNumber component failed (%d)\n", numsize);
-+ return -1;
-+ }
-+
-+#if 0
-+ /* tag component unknownPartyNumber (0x80,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), dst, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* unknownPartyNumber, implicid NumberDigits */
-+ memcpy(comp->data, num, numsize);
-+ i += numsize;
-+
-+ ASN1_FIXUP(compstk, compsp, dst, i);
-+#endif
-+
-+ /* tag component publicPartyNumber (0xa1,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), dst, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* publicPartyNumber, implicid PublicPartyNumber */
-+ size = rose_public_party_number_encode(pri, comp->data, 1, ton, num);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ ASN1_FIXUP(compstk, compsp, dst, i);
-+
-+ return i;
-+}
-+
-+static int rose_party_number_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
-+{
- int i = 0;
- int size = 0;
- struct rose_component *comp = NULL;
- unsigned char *vdata = data;
-
-+ do {
-+ GET_COMPONENT(comp, i, vdata, len);
-+
-+ switch(comp->type) {
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] IMPLICIT NumberDigits -- default: unknownPartyNumber */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PartyNumber: UnknownPartyNumber len=%d\n", len);
-+ size = rose_number_digits_decode(pri, comp->data, comp->len, 1, value);
-+ if (size < 0)
-+ return -1;
-+ value->npi = PRI_NPI_UNKNOWN;
-+ value->ton = PRI_TON_UNKNOWN;
-+ break;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT PublicPartyNumber */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PartyNumber: PublicPartyNumber len=%d\n", len);
-+ size = rose_public_party_number_decode(pri, comp->data, comp->len, 1, value);
-+ if (size < 0)
-+ return -1;
-+ value->npi = PRI_NPI_E163_E164;
-+ break;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_3): /* [3] IMPLICIT NumberDigits -- not used: dataPartyNumber */
-+ pri_message(pri, "!! PartyNumber: dataPartyNumber is reserved!\n");
-+ size = rose_number_digits_decode(pri, comp->data, comp->len, 1, value);
-+ if (size < 0)
-+ return -1;
-+ value->npi = PRI_NPI_X121 /* ??? */;
-+ value->ton = PRI_TON_UNKNOWN /* ??? */;
-+ break;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] IMPLICIT NumberDigits -- not used: telexPartyNumber */
-+ pri_message(pri, "!! PartyNumber: telexPartyNumber is reserved!\n");
-+ size = rose_number_digits_decode(pri, comp->data, comp->len, 1, value);
-+ if (size < 0)
-+ return -1;
-+ value->npi = PRI_NPI_F69 /* ??? */;
-+ value->ton = PRI_TON_UNKNOWN /* ??? */;
-+ break;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT PrivatePartyNumber */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PartyNumber: PrivatePartyNumber len=%d\n", len);
-+ size = rose_private_party_number_decode(pri, comp->data, comp->len, 1, value);
-+ if (size < 0)
-+ return -1;
-+ value->npi = PRI_NPI_PRIVATE;
-+ break;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_8): /* [8] IMPLICIT NumberDigits -- not used: nationalStandatdPartyNumber */
-+ pri_message(pri, "!! PartyNumber: nationalStandardPartyNumber is reserved!\n");
-+ size = rose_number_digits_decode(pri, comp->data, comp->len, 1, value);
-+ if (size < 0)
-+ return -1;
-+ value->npi = PRI_NPI_NATIONAL;
-+ value->ton = PRI_TON_NATIONAL;
-+ break;
-+
-+ default:
-+ pri_message(pri, "Invalid PartyNumber component 0x%X\n", comp->type);
-+ return -1;
-+ }
-+ ASN1_FIXUP_LEN(comp, size);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PartyNumber: '%s' size=%d len=%d\n", value->partyaddress, size, len);
-+ return size;
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+static int rose_presented_number_unscreened_encode(struct pri *pri, unsigned char *dst, unsigned char presentation, unsigned char ton, char *num)
-+{
-+ int i = 0, compsp = 0;
-+ struct rose_component *comp, *compstk[10];
-+ int numsize, size;
-+
-+ numsize = strlen(num);
-+ if (numsize > 20 ) {
-+ pri_message(pri, "!! Encoding of oversized PresentedNumberUnscreened component failed (%d)\n", numsize);
-+ return -1;
-+ }
-+
-+ switch (presentation & PRES_RESTRICTION) {
-+ case PRES_ALLOWED:
-+ /* tag component [0] presentationAllowedAddress (0xa0,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), dst, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* PartyNumber */
-+ size = rose_party_number_encode(pri, comp->data, ton, num);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+ ASN1_FIXUP(compstk, compsp, dst, i);
-+ break;
-+ case PRES_RESTRICTED:
-+ /* tag component [1] presentationRestricted (0x81,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), dst, i);
-+ break;
-+ case PRES_UNAVAILABLE:
-+ /* tag component [2] numberNotAvailableDueToInterworking (0x82,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), dst, i);
-+ /* ASN1_FIXUP(compstk, compsp, dst, i); */
-+ break;
-+ default:
-+ pri_message(pri, "!! Undefined presentation value for PresentedNumberUnscreened: 0x%x\n", presentation);
-+ return -1;
-+ }
-+
-+ return i;
-+}
-+
-+static int rose_presented_number_unscreened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
-+{
-+ int i = 0;
-+ int size = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = data;
-+
- /* Fill in default values */
-+ value->partyaddress[0] = '\0';
- value->ton = PRI_TON_UNKNOWN;
- value->npi = PRI_NPI_E163_E164;
- value->pres = -1; /* Data is not available */
-@@ -591,7 +1130,7 @@
- switch(comp->type) {
- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] presentationAllowedNumber */
- value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
-- size = rose_address_decode(pri, call, comp->data, comp->len, value);
-+ size = rose_address_decode(pri, comp->data, comp->len, value);
- ASN1_FIXUP_LEN(comp, size);
- return size + 2;
- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
-@@ -610,7 +1149,7 @@
- return 2;
- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] presentationRestrictedNumber */
- value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
-- size = rose_address_decode(pri, call, comp->data, comp->len, value) + 2;
-+ size = rose_address_decode(pri, comp->data, comp->len, value) + 2;
- ASN1_FIXUP_LEN(comp, size);
- return size + 2;
- default:
-@@ -623,17 +1162,482 @@
- return -1;
- }
-
-+static int rose_number_screened_encode(struct pri *pri, unsigned char *dst, int implicit, unsigned char ton, unsigned char screenind, char *num)
-+{
-+ int i = 0, compsp = 0;
-+ struct rose_component *comp, *compstk[10];
-+ int numsize, size;
-+
-+ numsize = strlen(num);
-+ if (numsize > 20 ) {
-+ pri_message(pri, "!! Encoding of oversized NumberScreened component failed (%d)\n", numsize);
-+ return -1;
-+ }
-+
-+ if (!implicit) {
-+ /* constructor component (0x30,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), dst, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+ } else
-+ comp = (struct rose_component *)dst;
-+
-+ /* PartyNumber */
-+ size = rose_party_number_encode(pri, (u_int8_t *)comp, ton, num);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ /* ScreeningIndicator (0x0a,0x01,screenind) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, dst, i, screenind);
-+
-+ if (!implicit)
-+ ASN1_FIXUP(compstk, compsp, dst, i);
-+
-+ return i;
-+}
-+
-+static int rose_number_screened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
-+{
-+ int i = 0;
-+ int size = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = data;
-+
-+ int scrind = -1;
-+
-+ do {
-+ /* Party Number */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ size = rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened*) value);
-+ if (size < 0)
-+ return -1;
-+ comp->len = size;
-+ NEXT_COMPONENT(comp, i);
-+
-+ /* Screening Indicator */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with NumberScreened ROSE component type 0x%x\n");
-+ ASN1_GET_INTEGER(comp, scrind);
-+ // Todo: scrind = screeningindicator_for_q931(pri, scrind);
-+ NEXT_COMPONENT(comp, i);
-+
-+ value->scrind = scrind;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " NumberScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len);
-+
-+ return i-2; // We do not have a sequence header here.
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+static int rose_presented_number_screened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
-+{
-+ int i = 0;
-+ int size = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = data;
-+
-+ /* Fill in default values */
-+ value->partyaddress[0] = '\0';
-+ value->ton = PRI_TON_UNKNOWN;
-+ value->npi = PRI_NPI_UNKNOWN;
-+ value->pres = -1; /* Data is not available */
-+ value->scrind = 0;
-+
-+ do {
-+ GET_COMPONENT(comp, i, vdata, len);
-+
-+ switch(comp->type) {
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedNumber */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedNumberScreened: presentationAllowedNumber comp->len=%d\n", comp->len);
-+ value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
-+ size = rose_number_screened_decode(pri, comp->data, comp->len, value);
-+ if (size < 0)
-+ return -1;
-+ ASN1_FIXUP_LEN(comp, size);
-+ return size + 2;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedNumberScreened: presentationRestricted comp->len=%d\n", comp->len);
-+ if (comp->len != 0) { /* must be NULL */
-+ pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
-+ return -1;
-+ }
-+ value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
-+ return 2;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedNumberScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len);
-+ if (comp->len != 0) { /* must be NULL */
-+ pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
-+ return -1;
-+ }
-+ value->pres = PRES_NUMBER_NOT_AVAILABLE;
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedNumberScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len);
-+ return 2;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedNumber */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedNumberScreened: presentationRestrictedNumber comp->len=%d\n", comp->len);
-+ value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
-+ size = rose_number_screened_decode(pri, comp->data, comp->len, value);
-+ if (size < 0)
-+ return -1;
-+ ASN1_FIXUP_LEN(comp, size);
-+ return size + 2;
-+
-+ default:
-+ pri_message(pri, "Invalid PresentedNumberScreened component 0x%X\n", comp->type);
-+ }
-+ return -1;
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+static int rose_partysubaddress_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_partysubaddress *value)
-+{
-+ int i = 0;
-+ int size = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = data;
-+
-+ int odd_count_indicator = -1;
-+ value->partysubaddress[0] = '\0';
-+
-+ do {
-+ GET_COMPONENT(comp, i, vdata, len);
-+
-+ switch(comp->type) {
-+ case (ASN1_CONSTRUCTOR | ASN1_SEQUENCE): /* UserSpecifiedSubaddress */
-+ /* SubaddressInformation */
-+ SUB_COMPONENT(comp, i);
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if SubaddressInformation is of type 0x%x\n");
-+ size = asn1_name_decode(comp->data, comp->len, value->partysubaddress, sizeof(value->partysubaddress));
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ /* oddCountIndicator BOOLEAN OPTIONAL */
-+ if (i < len) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_BOOLEAN, "Don't know what to do if SubaddressInformation is of type 0x%x\n");
-+
-+ ASN1_GET_INTEGER(comp, odd_count_indicator);
-+ NEXT_COMPONENT(comp, i);
-+ }
-+ case (ASN1_OCTETSTRING): /* NSAPSubaddress */
-+ size = asn1_name_decode((u_int8_t *)comp, comp->len + 2, value->partysubaddress, sizeof(value->partysubaddress));
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+ break;
-+ default:
-+ pri_message(pri, "Invalid PartySubaddress component 0x%X\n", comp->type);
-+ return -1;
-+ }
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PartySubaddress: '%s', oddCountIndicator=%d, i=%d len=%d\n", value->partysubaddress, odd_count_indicator, i, len);
-+
-+ return i;
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+static int rose_address_screened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_addressscreened *value)
-+{
-+ int i = 0;
-+ int size = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = data;
-+
-+ int scrind;
-+ value->partysubaddress[0] = '\0';
-+
-+ /* SEQUENCE AddressScreened */
-+ do {
-+ /* PartyNumber */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ size = rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened *)value);
-+ if (size < 0)
-+ return -1;
-+ comp->len = size;
-+ NEXT_COMPONENT(comp, i);
-+
-+ /* ScreeningIndicator */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with AddressScreened ROSE component type 0x%x\n");
-+ ASN1_GET_INTEGER(comp, scrind);
-+ NEXT_COMPONENT(comp, i);
-+
-+ if (i < len) {
-+ /* PartySubaddress OPTIONAL */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ size = rose_partysubaddress_decode(pri, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_partysubaddress *)value);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+ }
-+
-+ value->scrind = scrind;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " AddressScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len);
-+
-+ return i-2;
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+static int rose_presented_address_screened_decode(struct pri *pri, unsigned char *data, int len, struct addressingdataelements_presentedaddressscreened *value)
-+{
-+ int i = 0;
-+ int size = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = data;
-+
-+ /* Fill in default values */
-+ value->partyaddress[0] = '\0';
-+ value->partysubaddress[0] = '\0';
-+ value->npi = PRI_NPI_UNKNOWN;
-+ value->ton = PRI_TON_UNKNOWN;
-+ value->pres = -1; /* Data is not available */
-+ value->scrind = 0;
-+
-+ do {
-+ GET_COMPONENT(comp, i, vdata, len);
-+
-+ switch(comp->type) {
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedAddress */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedAddressScreened: presentationAllowedAddress comp->len=%d\n", comp->len);
-+ value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
-+ size = rose_address_screened_decode(pri, comp->data, comp->len, (struct addressingdataelements_addressscreened *)value);
-+ if (size < 0)
-+ return -1;
-+ ASN1_FIXUP_LEN(comp, size);
-+ return size + 2;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedAddressScreened: presentationRestricted comp->len=%d\n", comp->len);
-+ if (comp->len != 0) { /* must be NULL */
-+ pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
-+ return -1;
-+ }
-+ value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
-+ return 2;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedAddressScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len);
-+ if (comp->len != 0) { /* must be NULL */
-+ pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
-+ return -1;
-+ }
-+ value->pres = PRES_NUMBER_NOT_AVAILABLE;
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedAddressScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len);
-+ return 2;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedAddress */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " PresentedAddressScreened: presentationRestrictedAddress comp->len=%d\n", comp->len);
-+ value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
-+ size = rose_address_screened_decode(pri, comp->data, comp->len, (struct addressingdataelements_addressscreened *)value);
-+ if (size < 0)
-+ return -1;
-+ ASN1_FIXUP_LEN(comp, size);
-+ return size + 2;
-+
-+ default:
-+ pri_message(pri, "Invalid PresentedAddressScreened component 0x%X\n", comp->type);
-+ }
-+ return -1;
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+static int rose_diverting_leg_information1_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
-+{
-+ int i = 0;
-+ struct addressingdataelements_presentednumberunscreened nominatednr;
-+ int diversion_reason;
-+ int subscription_option;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = sequence->data;
-+ int size = 0;
-+ memset(&nominatednr, 0, sizeof(nominatednr));
-+
-+ /* Data checks */
-+ if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
-+ pri_message(pri, "Invalid DivertingLegInformation1Type argument\n");
-+ return -1;
-+ }
-+
-+ if (sequence->len == ASN1_LEN_INDEF) {
-+ len -= 4; /* For the 2 extra characters at the end
-+ and two characters of header */
-+ } else
-+ len -= 2;
-+
-+ do {
-+ /* diversionReason DiversionReason */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid diversionReason type 0x%X of ROSE divertingLegInformation1 component received\n");
-+ ASN1_GET_INTEGER(comp, diversion_reason);
-+ NEXT_COMPONENT(comp, i);
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Received diversionReason: %s(%d)\n", diversionreason_to_str(pri, diversion_reason), diversion_reason);
-+
-+ diversion_reason = redirectingreason_for_q931(pri, diversion_reason);
-+
-+ /* subscriptionOption SubscriptionOption */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid subscriptionOption type 0x%X of ROSE divertingLegInformation1 component received\n");
-+ ASN1_GET_INTEGER(comp, subscription_option);
-+ NEXT_COMPONENT(comp, i);
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Received subscriptionOption: %d\n", subscription_option);
-+
-+ /* nominatedNr PartyNumber */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ size = rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, &nominatednr);
-+ if (size < 0)
-+ return -1;
-+
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, " Received nominatedNr '%s'\n", nominatednr.partyaddress);
-+ pri_message(pri, " ton = %d, npi = %d\n\n", nominatednr.ton, nominatednr.npi);
-+ }
-+
-+ call->divleginfo1activeflag = 1;
-+ if (subscription_option == QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR) {
-+ libpri_copy_string(call->divertedtonum, nominatednr.partyaddress, sizeof(call->divertedtonum));
-+ } else {
-+ call->divertedtonum[0] = '\0';
-+ }
-+ call->divertedtopres = (subscription_option == QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR) ? PRES_ALLOWED_USER_NUMBER_NOT_SCREENED : PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
-+ call->divertedtoplan = ((nominatednr.ton & 0x07) << 4) | (nominatednr.npi & 0x0f);
-+ call->divertedtoreason = diversion_reason;
-+ call->divertedtocount++;
-+
-+ return 0;
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call)
-+{
-+ int i = 0, compsp = 0;
-+ struct rose_component *comp, *compstk[10];
-+ unsigned char buffer[256];
-+ int size;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Encode divertingLegInformation1\n");
-+
-+ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */
-+ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
-+
-+ /* Network Facility Extension */
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ /* tag component NetworkFacilityExtension (0xaa, len ) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* sourceEntity (0x80,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */
-+
-+ /* destinationEntity (0x82,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ }
-+
-+ /* Network Protocol Profile */
-+ /* - not included - */
-+
-+ /* Interpretation APDU (0x8b,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */
-+
-+ /* Service APDU(s): */
-+
-+ /* ROSE InvokePDU (0xa1,len) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* ROSE InvokeID (0x02,0x01,invokeid) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
-+
-+ /* ROSE operationId (0x02,0x01,0x14)*/
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION1);
-+
-+ /* constructor component (0x30,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* diversionReason (0x0a,0x01,diversionreason) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->divertedtoreason));
-+
-+ /* subscriptionOption (0x0a,0x01,subscriptionoption) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, presentation_to_subscription(pri, call->divertedtopres));
-+
-+ /* nominatedNr */
-+
-+ /* tag component publicPartyNumber (0xa1,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* publicPartyNumber, implicid PublicPartyNumber */
-+ size = rose_public_party_number_encode(pri, &buffer[i], 1, (call->divertedtoplan & 0x70) >> 4, call->divertedtonum);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, i, NULL, NULL))
-+ return -1;
-+
-+ return 0;
-+}
-+
- static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
- {
- int i = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = sequence->data;
-+ int size = 0;
-+
- int diversion_counter;
- int diversion_reason;
-- char origcalledname[50] = "", redirectingname[50] = "";
-+ int original_diversion_reason = QSIG_DIVERT_REASON_UNKNOWN;
-+ struct nameelements_name redirectingname = { "", CHARACTER_SET_UNKNOWN, 0 };
-+ struct nameelements_name origcalledname = { "", CHARACTER_SET_UNKNOWN, 0 };;
- struct addressingdataelements_presentednumberunscreened divertingnr;
-- struct addressingdataelements_presentednumberunscreened originalcallednr;
-- struct rose_component *comp = NULL;
-- unsigned char *vdata = sequence->data;
-- int res = 0;
-+ struct addressingdataelements_presentednumberunscreened originalcallednr;
- memset(&divertingnr, 0, sizeof(divertingnr));
- memset(&originalcallednr, 0, sizeof(originalcallednr));
-
-@@ -644,249 +1648,429 @@
- }
-
- if (sequence->len == ASN1_LEN_INDEF) {
-- len -= 4; /* For the 2 extra characters at the end
-- * and two characters of header */
-+ len -= 4; /* For the 2 extra characters at the end
-+ and two characters of header */
- } else
- len -= 2;
-
- do {
-- /* diversionCounter stuff */
-+ /* diversionCounter */
- GET_COMPONENT(comp, i, vdata, len);
-- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do it diversionCounter is of type 0x%x\n");
-+ CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if diversionCounter is of type 0x%x\n");
- ASN1_GET_INTEGER(comp, diversion_counter);
- NEXT_COMPONENT(comp, i);
-
-- /* diversionReason stuff */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Received diversionCounter: %d\n", diversion_counter);
-+
-+ /* diversionReason DiversionReason */
- GET_COMPONENT(comp, i, vdata, len);
- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid diversionReason type 0x%X of ROSE divertingLegInformation2 component received\n");
- ASN1_GET_INTEGER(comp, diversion_reason);
- NEXT_COMPONENT(comp, i);
-
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Received diversionReason: %s(%d)\n", diversionreason_to_str(pri, diversion_reason), diversion_reason);
-+
- diversion_reason = redirectingreason_for_q931(pri, diversion_reason);
--
-- if(pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter);
-- pri_message(NULL, "Length of message is %d\n", len);
-
-- for(; i < len; NEXT_COMPONENT(comp, i)) {
-+ /* Type SEQUENCE specifies an ordered list of component types. *
-+ * We decode all components but for simplicity we don't check the order. */
-+ while (i < len) {
- GET_COMPONENT(comp, i, vdata, len);
-+
- switch(comp->type) {
- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0):
-- call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]);
-+ /* originalDiversionReason */
-+ ASN1_GET_INTEGER(comp, original_diversion_reason);
-+ NEXT_COMPONENT(comp,i);
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " Received reason for original redirection %d\n", call->origredirectingreason);
-+ pri_message(pri, " Received originalDiversionReason: %s(%d)\n", diversionreason_to_str(pri, original_diversion_reason), original_diversion_reason);
-+ original_diversion_reason = redirectingreason_for_q931(pri, original_diversion_reason);
- break;
- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1):
-- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr);
-- /* TODO: Fix indefinite length form hacks */
-- ASN1_FIXUP_LEN(comp, res);
-- comp->len = res;
-- if (res < 0)
-+ /* divertingNr */
-+ size = rose_presented_number_unscreened_decode(pri, comp->data, comp->len, &divertingnr);
-+ if (size < 0)
- return -1;
-+ ASN1_FIXUP_LEN(comp, size);
-+ comp->len = size;
-+ NEXT_COMPONENT(comp,i);
- if (pri->debug & PRI_DEBUG_APDU) {
- pri_message(pri, " Received divertingNr '%s'\n", divertingnr.partyaddress);
- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi);
- }
- break;
- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2):
-- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr);
-- if (res < 0)
-+ /* originalCalledNr */
-+ size = rose_presented_number_unscreened_decode(pri, comp->data, comp->len, &originalcallednr);
-+ if (size < 0)
- return -1;
-- ASN1_FIXUP_LEN(comp, res);
-- comp->len = res;
-+ ASN1_FIXUP_LEN(comp, size);
-+ comp->len = size;
-+ NEXT_COMPONENT(comp,i);
- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, " Received originalcallednr '%s'\n", originalcallednr.partyaddress);
-+ pri_message(pri, " Received originalCalledNr '%s'\n", originalcallednr.partyaddress);
- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi);
- }
- break;
- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3):
-- res = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname));
-- if (res < 0)
-+ /* redirectingName */
-+ size = rose_name_decode(pri, comp->data, comp->len, &redirectingname);
-+ if (size < 0)
- return -1;
-- ASN1_FIXUP_LEN(comp, res);
-- comp->len = res;
-+ i += (size + 2);
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " Received RedirectingName '%s'\n", redirectingname);
-+ pri_message(pri, " Received RedirectingName '%s', namepres %s(%d), characterset %s(%d)\n",
-+ redirectingname.name, namepres_to_str(redirectingname.namepres), redirectingname.namepres,
-+ characterset_to_str(redirectingname.characterset), redirectingname.characterset);
- break;
- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4):
-- res = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname));
-- if (res < 0)
-+ /* originalCalledName */
-+ size = rose_name_decode(pri, comp->data, comp->len, &origcalledname);
-+ if (size < 0)
- return -1;
-- ASN1_FIXUP_LEN(comp, res);
-- comp->len = res;
-+ i += (size + 2);
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " Received Originally Called Name '%s'\n", origcalledname);
-+ pri_message(pri, " Received OriginalCalledName '%s', namepres %s(%d), characterset %s(%d)\n",
-+ origcalledname.name, namepres_to_str(origcalledname.namepres), origcalledname.namepres,
-+ characterset_to_str(origcalledname.characterset), origcalledname.characterset);
- break;
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5):
-- pri_message(pri, "!! Ignoring DivertingLegInformation2 component 0x%X\n", comp->type);
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT Extension */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_6): /* [6] IMPLICIT SEQUENCE OF Extension */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "!! Ignoring DivertingLegInformation2 component 0x%X\n", comp->type);
-+ NEXT_COMPONENT(comp, i);
- break;
- default:
-- if (comp->type == 0 && comp->len == 0) {
-- break; /* Found termination characters */
-- }
-- pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type);
-+ pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type);
- return -1;
- }
- }
-
- if (divertingnr.pres >= 0) {
-- call->redirectingplan = divertingnr.npi;
-+ call->redirectingplan = ((divertingnr.ton & 0x07) << 4) | (divertingnr.npi & 0x0f);
- call->redirectingpres = divertingnr.pres;
- call->redirectingreason = diversion_reason;
- libpri_copy_string(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum));
-- pri_message(pri, " Received redirectingnum '%s' (%d)\n", call->redirectingnum, (int)call->redirectingnum[0]);
- }
- if (originalcallednr.pres >= 0) {
-- call->origcalledplan = originalcallednr.npi;
-+ call->origcalledplan = ((originalcallednr.ton & 0x07) << 4) | (originalcallednr.npi & 0x0f);
- call->origcalledpres = originalcallednr.pres;
- libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum));
-- pri_message(pri, " Received origcallednum '%s' (%d)\n", call->origcallednum, (int)call->origcallednum[0]);
- }
-- libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname));
-- libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname));
-+
-+ if (redirectingname.namepres != 0) {
-+ libpri_copy_string(call->redirectingname, redirectingname.name, sizeof(call->redirectingname));
-+ } else {
-+ call->redirectingname[0] = '\0';
-+ }
-+
-+ if (origcalledname.namepres != 0) {
-+ libpri_copy_string(call->origcalledname, origcalledname.name, sizeof(call->origcalledname));
-+ } else {
-+ call->origcalledname[0] = '\0';
-+ }
-+
-+ call->origredirectingreason = original_diversion_reason;
-+ call->redirectingcount = diversion_counter;
-+
- return 0;
- }
- while (0);
-
- return -1;
- }
--
-+
- static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *call)
- {
-- int i = 0, j, compsp = 0;
-+ int i = 0, compsp = 0;
- struct rose_component *comp, *compstk[10];
- unsigned char buffer[256];
-- int len = 253;
--
--#if 0 /* This is not required by specifications */
-- if (!strlen(call->callername)) {
-- return -1;
-+ int size;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Encode divertingLegInformation2\n");
-+
-+ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */
-+ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
-+
-+ /* Network Facility Extension */
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ /* tag component NetworkFacilityExtension (0xaa, len ) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* sourceEntity (0x80,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */
-+
-+ /* destinationEntity (0x82,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
- }
--#endif
-
-- buffer[i] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
-- i++;
-- /* Interpretation component */
-- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0x00 /* Discard unrecognized invokes */);
--
-+ /* Network Protocol Profile */
-+ /* - not included - */
-+
-+ /* Interpretation APDU (0x8b,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */
-+
-+ /* Service APDU(s): */
-+
-+ /* ROSE InvokePDU (0xa1,len) */
- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
--
- ASN1_PUSH(compstk, compsp, comp);
-- /* Invoke component contents */
-- /* Invoke ID */
-+
-+ /* ROSE InvokeID (0x02,0x01,invokeid) */
- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
-- /* Operation Tag */
--
-- /* ROSE operationId component */
-+
-+ /* ROSE operationId (0x02,0x01,0x15)*/
- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION2);
-
-- /* ROSE ARGUMENT component */
-+ /* constructor component (0x30,len) */
- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
- ASN1_PUSH(compstk, compsp, comp);
-- /* ROSE DivertingLegInformation2.diversionCounter component */
-- /* Always is 1 because other isn't available in the current design */
-+
-+ /* diversionCounter always is 1 because other isn't available in the current design */
-+ /* diversionCounter (0x02,0x01,0x01) */
- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1);
--
-- /* ROSE DivertingLegInformation2.diversionReason component */
-+
-+ /* diversionReason (0x0a,0x01,redirectingreason) */
- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->redirectingreason));
--
-- /* ROSE DivertingLegInformation2.divertingNr component */
-+
-+ /* originalDiversionReason */
-+ /* - not included - */
-+
-+ /* divertingNr */
-+
-+ /* tag component divertingNr (0xa1,len) */
- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
--
- ASN1_PUSH(compstk, compsp, comp);
-- /* Redirecting information always not screened */
--
-- switch(call->redirectingpres) {
-- case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
-- case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
-- if (call->redirectingnum && strlen(call->redirectingnum)) {
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
-- ASN1_PUSH(compstk, compsp, comp);
-- /* NPI of redirected number is not supported in the current design */
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
-- ASN1_PUSH(compstk, compsp, comp);
-- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
-- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
-- if (j < 0)
-- return -1;
--
-- i += j;
-- ASN1_FIXUP(compstk, compsp, buffer, i);
-- ASN1_FIXUP(compstk, compsp, buffer, i);
-- break;
-- }
-- /* fall through */
-- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
-- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
-- break;
-- /* Don't know how to handle this */
-- case PRES_ALLOWED_NETWORK_NUMBER:
-- case PRES_PROHIB_NETWORK_NUMBER:
-- case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
-- case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
-- break;
-- default:
-- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
-- case PRES_NUMBER_NOT_AVAILABLE:
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i);
-- break;
-- }
-+
-+ size = rose_presented_number_unscreened_encode(pri, &buffer[i], call->redirectingpres, typeofnumber_from_q931(pri, (call->redirectingplan & 0x70) >> 4), call->redirectingnum);
-+ if (size < 0)
-+ return -1;
-+ i += size;
- ASN1_FIXUP(compstk, compsp, buffer, i);
-
-- /* ROSE DivertingLegInformation2.originalCalledNr component */
-- /* This information isn't supported by current design - duplicate divertingNr */
-+ /* originalCalledNr */
-+ /* - not included - */
-+
-+#if 0
-+ /* The originalCalledNr is unknown here. Its the same as divertingNr if the call *
-+ * is diverted only once but we don't know if its diverted one ore more times. */
-+
-+ /* originalCalledNr */
-+
-+ /* tag component originalCalledNr (0xa2,len) */
- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2), buffer, i);
- ASN1_PUSH(compstk, compsp, comp);
-- /* Redirecting information always not screened */
-- switch(call->redirectingpres) {
-- case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED:
-- case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN:
-- if (call->redirectingnum && strlen(call->redirectingnum)) {
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
-- ASN1_PUSH(compstk, compsp, comp);
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
-- ASN1_PUSH(compstk, compsp, comp);
-- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4));
--
-- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum));
-- if (j < 0)
-+
-+ size = rose_presented_number_unscreened_encode(pri, &buffer[i], call->redirectingpres, typeofnumber_from_q931(pri, (call->redirectingplan & 0x70) >> 4), call->redirectingnum);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+#endif
-+
-+ /* redirectingName */
-+ if (call->redirectingname[0]) {
-+ /* tag component redirectingName (0xa3,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* tag component namePresentationAllowedSimple (0x80,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* namePresentationAllowedSimple, implicid NameData */
-+ size = rose_namedata_encode(pri, &buffer[i], 1, call->redirectingname);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ }
-+
-+ /* originalCalledName */
-+ /* - not included - */
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ if (pri_call_apdu_queue(call, Q931_SETUP, buffer, i, NULL, NULL))
-+ return -1;
-+
-+ return 0;
-+}
-+
-+static int rose_diverting_leg_information3_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
-+{
-+ int i = 0;
-+ struct nameelements_name redirectionname = { "", CHARACTER_SET_UNKNOWN, 0 };
-+ int presentation_allowed_indicator;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = sequence->data;
-+ int size = 0;
-+
-+ /* Data checks */
-+ if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
-+ pri_message(pri, "Invalid DivertingLegInformation3Type argument\n");
-+ return -1;
-+ }
-+
-+ if (sequence->len == ASN1_LEN_INDEF) {
-+ len -= 4; /* For the 2 extra characters at the end
-+ and two characters of header */
-+ } else
-+ len -= 2;
-+
-+ do {
-+ /* presentationAllowedIndicator */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_BOOLEAN, "Don't know what to do if presentationAllowedIndicator is of type 0x%x\n");
-+ ASN1_GET_INTEGER(comp, presentation_allowed_indicator);
-+ NEXT_COMPONENT(comp, i);
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Received presentationAllowedIndicator: %d\n", presentation_allowed_indicator);
-+
-+ /* Type SEQUENCE specifies an ordered list of component types. *
-+ * We decode all components but for simplicity we don't check the order. */
-+ while (i < len) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+
-+ switch(comp->type) {
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0):
-+ /* redirectionName */
-+ size = rose_name_decode(pri, comp->data, comp->len, &redirectionname);
-+ if (size < 0)
- return -1;
--
-- i += j;
-- ASN1_FIXUP(compstk, compsp, buffer, i);
-- ASN1_FIXUP(compstk, compsp, buffer, i);
-+ i += (size + 2);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Received RedirectionName '%s', namepres %s(%d), characterset %s(%d)\n",
-+ redirectionname.name, namepres_to_str(redirectionname.namepres), redirectionname.namepres,
-+ characterset_to_str(redirectionname.characterset), redirectionname.characterset);
- break;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT Extension */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* [2] IMPLICIT SEQUENCE OF Extension */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "!! Ignoring DivertingLegInformation3 component 0x%X\n", comp->type);
-+ NEXT_COMPONENT(comp, i);
-+ break;
-+ default:
-+ pri_message(pri, "!! Invalid DivertingLegInformation3 component received 0x%X\n", comp->type);
-+ return -1;
- }
-- /* fall through */
-- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN:
-- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED:
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
-- break;
-- /* Don't know how to handle this */
-- case PRES_ALLOWED_NETWORK_NUMBER:
-- case PRES_PROHIB_NETWORK_NUMBER:
-- case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN:
-- case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN:
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i);
-- break;
-- default:
-- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres);
-- case PRES_NUMBER_NOT_AVAILABLE:
-- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i);
-- break;
-+ }
-+
-+ call->divleginfo3activeflag = 1;
-+ if ((redirectionname.namepres != 0) && (presentation_allowed_indicator != 0)) {
-+ libpri_copy_string(call->divertedtoname, redirectionname.name, sizeof(call->divertedtoname));
-+ } else {
-+ call->divertedtoname[0] = '\0';
-+ }
-+
-+ return 0;
- }
-- ASN1_FIXUP(compstk, compsp, buffer, i);
--
-- /* Fix length of stacked components */
-- while(compsp > 0) {
-+ while (0);
-+
-+ return -1;
-+}
-+
-+int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype)
-+{
-+ int i = 0, compsp = 0;
-+ struct rose_component *comp, *compstk[10];
-+ unsigned char buffer[256];
-+ int size;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Encode divertingLegInformation3\n");
-+
-+ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */
-+ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
-+
-+ /* Network Facility Extension */
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ /* tag component NetworkFacilityExtension (0xaa, len ) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* sourceEntity (0x80,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */
-+
-+ /* destinationEntity (0x82,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */
- ASN1_FIXUP(compstk, compsp, buffer, i);
- }
--
-- if (pri_call_apdu_queue(call, Q931_SETUP, buffer, i, NULL, NULL))
-+
-+ /* Network Protocol Profile */
-+ /* - not included - */
-+
-+ /* Interpretation APDU (0x8b,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */
-+
-+ /* Service APDU(s): */
-+
-+ /* ROSE InvokePDU (0xa1,len) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* ROSE InvokeID (0x02,0x01,invokeid) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
-+
-+ /* ROSE operationId (0x02,0x01,0x16)*/
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION3);
-+
-+ /* constructor component (0x30,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* 'connectedpres' also indicates if name presentation is allowed */
-+ if (((call->divertedtopres & 0x60) >> 5) == 0) {
-+ /* presentation allowed */
-+
-+ /* presentationAllowedIndicator (0x01,0x01,0xff) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_BOOLEAN, buffer, i, 0xff); /* true(255) */
-+
-+ /* redirectionName */
-+
-+ /* tag component redirectionName (0xa0,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ if (call->divertedtoname[0]) {
-+ /* tag component namePresentationAllowedSimple (0x80,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* namePresentationAllowedSimple, implicid NameData */
-+ size = rose_namedata_encode(pri, &buffer[i], 1, call->divertedtoname);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ }
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ } else {
-+ /* presentation restricted */
-+
-+ /* presentationAllowedIndicator (0x01,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_BOOLEAN, buffer, i, 0); /* false(0) */
-+
-+ /* - don't include redirectionName, component is optional - */
-+ }
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ if (pri_call_apdu_queue(call, messagetype, buffer, i, NULL, NULL))
- return -1;
--
-+
- return 0;
- }
-
-@@ -1644,7 +2828,7 @@
- switch (comp1->type) {
- /* TODO: charged number is untested - please report! */
- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* chargedNumber (0xA0) */
-- if(rose_presented_number_unscreened_decode(pri, call, comp1->data, comp1->len, &chargednr) != 0)
-+ if(rose_presented_number_unscreened_decode(pri, comp1->data, comp1->len, &chargednr) != 0)
- return -1;
- pri_message(pri, "!! not handled: Received ChargedNr '%s' \n", chargednr.partyaddress);
- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", chargednr.ton, chargednr.pres, chargednr.npi);
-@@ -1740,302 +2924,407 @@
- }
- /* End AOC */
-
--static int rose_calling_name_decode(struct pri *pri, q931_call *call, struct rose_component *choice, int len)
-+/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */
-+
-+static int rose_call_transfer_complete_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
- {
- int i = 0;
- struct rose_component *comp = NULL;
-- unsigned char *vdata = choice->data;
-- int characterSet = 1;
-- switch (choice->type) {
-- case ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE:
-- memcpy(call->callername, choice->data, choice->len);
-- call->callername[choice->len] = 0;
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " Received simple calling name '%s'\n", call->callername);
-- return 0;
-+ unsigned char *vdata = sequence->data;
-+ int size = 0;
-
-- case ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED:
-- do {
-- GET_COMPONENT(comp, i, vdata, len);
-- CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if nameData is of type 0x%x\n");
-- memcpy(call->callername, comp->data, comp->len);
-- call->callername[comp->len] = 0;
-- NEXT_COMPONENT(comp, i);
-+ struct addressingdataelements_presentednumberscreened redirection_number;
-+ struct nameelements_name redirectionname = { "", CHARACTER_SET_UNKNOWN, 0 };
-+ char basiccallinfoelements[257] = "";
-+ int call_status = 0; /* answered(0) */
-+ int end_designation;
-
-- GET_COMPONENT(comp, i, vdata, len);
-- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if CharacterSet is of type 0x%x\n");
-- ASN1_GET_INTEGER(comp, characterSet);
-- }
-- while (0);
--
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " Received extended calling name '%s', characterset %d\n", call->callername, characterSet);
-- return 0;
-- case ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE:
-- case ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED:
-- case ROSE_NAME_PRESENTATION_RESTRICTED_NULL:
-- case ROSE_NAME_NOT_AVAIL:
-- default:
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, "Do not handle argument of type 0x%X\n", choice->type);
-- return -1;
-+ /* Data checks */
-+ if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
-+ pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n");
-+ return -1;
- }
--}
--/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */
-
--static int rose_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value)
--{
-- int i = 0;
-- int size = 0;
-- struct rose_component *comp = NULL;
-- unsigned char *vdata = data;
-+ if (sequence->len == ASN1_LEN_INDEF) {
-+ len -= 4; /* For the 2 extra characters at the end
-+ and two characters of header */
-+ } else
-+ len -= 2;
-
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " CT-Complete: len=%d\n", len);
-
-+ /* CTCompleteArg SEQUENCE */
- do {
-+ /* endDesignation EndDesignation */
- GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid endDesignation type 0x%X of ROSE callTransferComplete component received\n");
-+ ASN1_GET_INTEGER(comp, end_designation);
-+ NEXT_COMPONENT(comp, i);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " CT-Complete: Received endDesignation=%s(%d)\n", enddesignation_to_str(end_designation), end_designation);
-
-- switch(comp->type) {
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT NumberDigits -- default: unknownPartyNumber */
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " PartyNumber: UnknownPartyNumber len=%d\n", len);
-- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
-- if (size < 0)
-- return -1;
-- value->npi = PRI_NPI_UNKNOWN;
-- value->ton = PRI_TON_UNKNOWN;
-- break;
-+ /* redirectionNumber PresentedNumberScreened */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ size = rose_presented_number_screened_decode(pri, (u_int8_t *)comp, comp->len + 2, &redirection_number);
-+ if (size < 0)
-+ return -1;
-+ comp->len = size;
-+ NEXT_COMPONENT(comp, i);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress);
-
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT PublicPartyNumber */
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " PartyNumber: PublicPartyNumber len=%d\n", len);
-- size = rose_public_party_number_decode(pri, call, comp->data, comp->len, value);
-- if (size < 0)
-- return -1;
-- value->npi = PRI_NPI_E163_E164;
-- break;
-+ /* Type SEQUENCE specifies an ordered list of component types. *
-+ * We decode all components but for simplicity we don't check the order. */
-+ while (i < len) {
-+ GET_COMPONENT(comp, i, vdata, len);
-
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT NumberDigits -- not used: dataPartyNumber */
-- pri_message(pri, "!! PartyNumber: dataPartyNumber is reserved!\n");
-- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
-+ switch(comp->type) {
-+ case (ASN1_APPLICATION):
-+ /* basicCallInfoElements PSS1InformationElement OPTIONAL */
-+ size = asn1_name_decode((u_int8_t *)comp, comp->len + 2, basiccallinfoelements, sizeof(basiccallinfoelements));
- if (size < 0)
- return -1;
-- value->npi = PRI_NPI_X121 /* ??? */;
-- value->ton = PRI_TON_UNKNOWN /* ??? */;
-+ i += size;
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ int j;
-+ pri_message(pri, " CT-Complete: Received basicCallInfoElements\n");
-+ pri_message(pri, " ");
-+ for (j = 0; basiccallinfoelements[j] != '\0'; j++)
-+ pri_message(pri, "%02x ", (u_int8_t)basiccallinfoelements[j]);
-+ pri_message(pri, "\n");
-+ }
- break;
--
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] IMPLICIT NumberDigits -- not used: telexPartyNumber */
-- pri_message(pri, "!! PartyNumber: telexPartyNumber is reserved!\n");
-- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] namePresentationAllowedSimple */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] namePresentationAllowedExtended */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] namePresentationRestrictedSimple */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] namePresentationRestrictedExtended */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] nameNotAvailable */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_7): /* [7] namePresentationRestrictedNull */
-+ /* redirectionName Name OPTIONAL */
-+ size = rose_name_decode(pri, (u_int8_t *)comp, comp->len + 2, &redirectionname);
- if (size < 0)
- return -1;
-- value->npi = PRI_NPI_F69 /* ??? */;
-- value->ton = PRI_TON_UNKNOWN /* ??? */;
-+ i += size;
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " CT-Complete: Received RedirectionName '%s', namepres %s(%d), characterset %s(%d)\n",
-+ redirectionname.name, namepres_to_str(redirectionname.namepres), redirectionname.namepres,
-+ characterset_to_str(redirectionname.characterset), redirectionname.characterset);
- break;
--
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT PrivatePartyNumber */
-+ case (ASN1_ENUMERATED):
-+ /* callStatus CallStatus DEFAULT answered */
-+ ASN1_GET_INTEGER(comp, call_status);
-+ NEXT_COMPONENT(comp,i);
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " PartyNumber: PrivatePartyNumber len=%d\n", len);
-- size = rose_private_party_number_decode(pri, call, comp->data, comp->len, value);
-- if (size < 0)
-- return -1;
-- value->npi = PRI_NPI_PRIVATE;
-+ pri_message(pri, " CT-Complete: Received callStatus=%s(%d)\n", callstatus_to_str(call_status), call_status);
- break;
--
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] IMPLICIT NumberDigits -- not used: nationalStandatdPartyNumber */
-- pri_message(pri, "!! PartyNumber: nationalStandardPartyNumber is reserved!\n");
-- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value);
-- if (size < 0)
-- return -1;
-- value->npi = PRI_NPI_NATIONAL;
-- value->ton = PRI_TON_NATIONAL;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_9): /* [9] IMPLICIT Extension */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "!! CT-Complete: Ignoring CallTransferComplete component 0x%X\n", comp->type);
-+ NEXT_COMPONENT(comp, i);
- break;
--
- default:
-- pri_message(pri, "Invalid PartyNumber component 0x%X\n", comp->type);
-+ pri_message(pri, "!! CT-Complete: Invalid CallTransferComplete component received 0x%X\n", comp->type);
- return -1;
-+ }
- }
-- ASN1_FIXUP_LEN(comp, size);
-+
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " PartyNumber: '%s' size=%d len=%d\n", value->partyaddress, size, len);
-- return size;
-+ pri_message(pri, " CT-Complete: callStatus=%s(%d)\n", callstatus_to_str(call_status), call_status);
-+
-+ call->ctcompleteflag = 1;
-+ if ((redirection_number.pres & PRES_RESTRICTION) == PRES_ALLOWED) {
-+ libpri_copy_string(call->ctcompletenum, redirection_number.partyaddress, sizeof(call->ctcompletenum));
-+ } else {
-+ call->ctcompletenum[0] = '\0';
-+ }
-+ call->ctcompletepres = redirection_number.pres;
-+ call->ctcompleteplan = ((redirection_number.ton & 0x07) << 4) | (redirection_number.npi & 0x0f);
-+ call->ctcompletecallstatus = call_status;
-+
-+ if (redirectionname.namepres != 0) {
-+ libpri_copy_string(call->ctcompletename, redirectionname.name, sizeof(call->ctcompletename));
-+ } else {
-+ call->ctcompletename[0] = '\0';
-+ }
-+
-+ return 0;
- }
- while (0);
-
- return -1;
- }
-
--
--static int rose_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
-+static int rose_call_transfer_complete_encode(struct pri *pri, q931_call *call, int call_status)
- {
-- int i = 0;
-- int size = 0;
-- struct rose_component *comp = NULL;
-- unsigned char *vdata = data;
-+ int i = 0, compsp = 0;
-+ struct rose_component *comp, *compstk[10];
-+ unsigned char buffer[256];
-+ int size;
-
-- int scrind = -1;
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Encode CallTransferComplete\n");
-
-- do {
-- /* Party Number */
-- GET_COMPONENT(comp, i, vdata, len);
-- size = rose_party_number_decode(pri, call, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened*) value);
-+ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */
-+ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
-+
-+ /* Network Facility Extension */
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ /* tag component NetworkFacilityExtension (0xaa, len ) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* sourceEntity (0x80,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */
-+
-+ /* destinationEntity (0x82,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ }
-+
-+ /* Network Protocol Profile */
-+ /* - not included - */
-+
-+ /* Interpretation APDU (0x8b,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */
-+
-+ /* Service APDU(s): */
-+
-+ /* ROSE InvokePDU (0xa1,len) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* ROSE InvokeID (0x02,0x01,invokeid) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
-+
-+ /* ROSE operationId (0x02,0x01,0x0c)*/
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_CALL_TRANSFER_COMPLETE);
-+
-+
-+ /* CTCompleteArg */
-+
-+ /* constructor component (0x30,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+
-+ /* endDesignation (0x0a,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); /* primaryEnd(0) */
-+
-+
-+ /* redirectionNumber PresentedNumberScreened */
-+
-+ /* tag component presentationAllowedAddress (0xa0,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* presentationAllowedAddress, implicit NumberScreened */
-+ size = rose_number_screened_encode(pri, &buffer[i], 1, typeofnumber_from_q931(pri, (call->connectedplan & 0x70) >> 4), call->connectedpres & 0x03, call->connectednum);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ /* basicCallInfoElements */
-+ /* - not included - */
-+
-+#if 0
-+ /* basicCallInfoElements (0x40,0x00) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_APPLICATION| ASN1_TAG_0), buffer, i);
-+#endif
-+
-+ /* redirectionName */
-+ if (call->connectedname[0]) {
-+ /* tag component namePresentationAllowedSimple (0x80,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* namePresentationAllowedSimple, implicid NameData */
-+ size = rose_namedata_encode(pri, &buffer[i], 1, call->connectedname);
- if (size < 0)
- return -1;
-- comp->len = size;
-- NEXT_COMPONENT(comp, i);
-+ i += size;
-
-- /* Screening Indicator */
-- GET_COMPONENT(comp, i, vdata, len);
-- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with NumberScreened ROSE component type 0x%x\n");
-- ASN1_GET_INTEGER(comp, scrind);
-- // Todo: scrind = screeningindicator_for_q931(pri, scrind);
-- NEXT_COMPONENT(comp, i);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ }
-
-- value->scrind = scrind;
-+ if (call_status) {
-+ /* callStatus (0x0a,0x01,0x01) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1); /* alerting(1) */
-+ } else {
-+ /* callStatus */
-+ /* - not included, default: answered(0) - */
-+#if 0
-+ /* callStatus (0x0a,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); /* answered(0) */
-+#endif
-+ }
-
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " NumberScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-
-- return i-2; // We do not have a sequence header here.
-- }
-- while (0);
-+ if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, i, NULL, NULL))
-+ return -1;
-
-- return -1;
-+ return 0;
- }
-
--
--static int rose_presented_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value)
-+static int rose_call_transfer_active_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
- {
- int i = 0;
-+ struct rose_component *comp = NULL;
-+ unsigned char *vdata = sequence->data;
- int size = 0;
-- struct rose_component *comp = NULL;
-- unsigned char *vdata = data;
-
-- /* Fill in default values */
-- value->ton = PRI_TON_UNKNOWN;
-- value->npi = PRI_NPI_UNKNOWN;
-- value->pres = -1; /* Data is not available */
-+ struct addressingdataelements_presentedaddressscreened connectedaddress;
-+ struct nameelements_name connectedname = { "", CHARACTER_SET_UNKNOWN, 0 };
-+ char basiccallinfoelements[257] = "";
-
-+ /* Data checks */
-+ if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
-+ pri_message(pri, "Invalid callTransferActive argument. (Not a sequence)\n");
-+ return -1;
-+ }
-+
-+ if (sequence->len == ASN1_LEN_INDEF) {
-+ len -= 4; /* For the 2 extra characters at the end
-+ and two characters of header */
-+ } else
-+ len -= 2;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " CT-Active: len=%d\n", len);
-+
-+ /* CTActiveArg SEQUENCE */
- do {
-+ /* connectedAddress PresentedAddressScreened */
- GET_COMPONENT(comp, i, vdata, len);
-+ size = rose_presented_address_screened_decode(pri, (u_int8_t *)comp, comp->len + 2, &connectedaddress);
-+ if (size < 0)
-+ return -1;
-+ comp->len = size;
-+ NEXT_COMPONENT(comp, i);
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, " CT-Active: Received connectedAddress=%s\n", connectedaddress.partyaddress);
-+ }
-
-- switch(comp->type) {
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedNumber */
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " PresentedNumberScreened: presentationAllowedNumber comp->len=%d\n", comp->len);
-- value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
-- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value);
-+ /* Type SEQUENCE specifies an ordered list of component types. *
-+ * We decode all components but for simplicity we don't check the order. */
-+ while (i < len) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+
-+ switch(comp->type) {
-+ case (ASN1_APPLICATION):
-+ /* basiccallinfoelements PSS1InformationElement OPTIONAL */
-+ size = asn1_name_decode((u_int8_t *)comp, comp->len + 2, basiccallinfoelements, sizeof(basiccallinfoelements));
- if (size < 0)
- return -1;
-- ASN1_FIXUP_LEN(comp, size);
-- return size + 2;
--
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " PresentedNumberScreened: presentationRestricted comp->len=%d\n", comp->len);
-- if (comp->len != 0) { /* must be NULL */
-- pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n");
-- return -1;
-+ i += size;
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ int j;
-+ pri_message(pri, " CT-Active: Received basicCallInfoElements\n");
-+ pri_message(pri, " ");
-+ for (j = 0; basiccallinfoelements[j] != '\0'; j++)
-+ pri_message(pri, "%02x ", (u_int8_t)basiccallinfoelements[j]);
-+ pri_message(pri, "\n");
- }
-- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
-- return 2;
--
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " PresentedNumberScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len);
-- if (comp->len != 0) { /* must be NULL */
-- pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n");
-+ break;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] namePresentationAllowedSimple */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] namePresentationAllowedExtended */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] namePresentationRestrictedSimple */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] namePresentationRestrictedExtended */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_4): /* [4] nameNotAvailable */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_7): /* [7] namePresentationRestrictedNull */
-+ /* connectedName Name OPTIONAL */
-+ size = rose_name_decode(pri, (u_int8_t *)comp, comp->len + 2, &connectedname);
-+ if (size < 0)
- return -1;
-- }
-- value->pres = PRES_NUMBER_NOT_AVAILABLE;
-+ i += size;
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " PresentedNumberScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len);
-- return 2;
--
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedNumber */
-+ pri_message(pri, " CT-Active: Received ConnectedName '%s', namepres %s(%d), characterset %s(%d)\n",
-+ connectedname.name, namepres_to_str(connectedname.namepres), connectedname.namepres,
-+ characterset_to_str(connectedname.characterset), connectedname.characterset);
-+ break;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_9): /* [9] IMPLICIT Extension */
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " PresentedNumberScreened: presentationRestrictedNumber comp->len=%d\n", comp->len);
-- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN;
-- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value);
-- if (size < 0)
-- return -1;
-- ASN1_FIXUP_LEN(comp, size);
-- return size + 2;
-+ pri_message(pri, "!! CT-Active: Ignoring CallTransferActive component 0x%X\n", comp->type);
-+ NEXT_COMPONENT(comp, i);
-+ break;
-+ default:
-+ pri_message(pri, "!! CT-Active: Invalid CallTransferActive component received 0x%X\n", comp->type);
-+ return -1;
-+ }
-+ }
-
-- default:
-- pri_message(pri, "Invalid PresentedNumberScreened component 0x%X\n", comp->type);
-+ call->ctactiveflag = 1;
-+ if ((connectedaddress.pres & PRES_RESTRICTION) == PRES_ALLOWED) {
-+ libpri_copy_string(call->ctactivenum, connectedaddress.partyaddress, sizeof(call->ctactivenum));
-+ } else {
-+ call->ctactivenum[0] = '\0';
- }
-- return -1;
-+ call->ctactivepres = connectedaddress.pres;
-+ call->ctactiveplan = ((connectedaddress.ton & 0x07) << 4) | (connectedaddress.npi & 0x0f);
-+
-+ if (connectedname.namepres != 0) {
-+ libpri_copy_string(call->ctactivename, connectedname.name, sizeof(call->ctactivename));
-+ } else {
-+ call->ctactivename[0] = '\0';
-+ }
-+
-+ return 0;
- }
- while (0);
-
- return -1;
- }
-
--
--static int rose_call_transfer_complete_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
-+#if 0
-+static int rose_call_transfer_update_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
- {
- int i = 0;
- struct rose_component *comp = NULL;
- unsigned char *vdata = sequence->data;
- int res = 0;
-
-- int end_designation = 0;
- struct addressingdataelements_presentednumberscreened redirection_number;
-- char redirection_name[50] = "";
-- int call_status = 0;
- redirection_number.partyaddress[0] = 0;
-- redirection_number.partysubaddress[0] = 0;
-+ char redirection_name[51] = "";
- call->callername[0] = 0;
- call->callernum[0] = 0;
-
--
- /* Data checks */
- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
-- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n");
-+ pri_message(pri, "Invalid callTransferUpdate argument. (Not a sequence)\n");
- return -1;
- }
-
- if (sequence->len == ASN1_LEN_INDEF) {
-- len -= 4; /* For the 2 extra characters at the end
-- * and two characters of header */
-+ len -= 4; /* For the 2 extra characters at the end
-+ and two characters of header */
- } else
- len -= 2;
-
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " CT-Complete: len=%d\n", len);
-+ pri_message(pri, " CT-Update: len=%d\n", len);
-
- do {
-- /* End Designation */
-- GET_COMPONENT(comp, i, vdata, len);
-- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid endDesignation type 0x%X of ROSE callTransferComplete component received\n");
-- ASN1_GET_INTEGER(comp, end_designation);
-- NEXT_COMPONENT(comp, i);
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " CT-Complete: Received endDesignation=%d\n", end_designation);
--
--
- /* Redirection Number */
- GET_COMPONENT(comp, i, vdata, len);
-- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number);
-+ res = rose_presented_number_screened_decode(pri, (u_int8_t *)comp, comp->len + 2, &redirection_number);
- if (res < 0)
- return -1;
- comp->len = res;
- if (res > 2) {
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress);
-+ pri_message(pri, " CT-Update: Received redirectionNumber=%s\n", redirection_number.partyaddress);
- strncpy(call->callernum, redirection_number.partyaddress, 20);
- call->callernum[20] = 0;
- }
- NEXT_COMPONENT(comp, i);
-
--
--#if 0 /* This one is optional. How do we check if it is there? */
-- /* Basic Call Info Elements */
-- GET_COMPONENT(comp, i, vdata, len);
-- NEXT_COMPONENT(comp, i);
--#endif
--
--
- /* Redirection Name */
- GET_COMPONENT(comp, i, vdata, len);
- res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name));
-@@ -2047,16 +3336,14 @@
- comp->len = res;
- NEXT_COMPONENT(comp, i);
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name);
-+ pri_message(pri, " CT-Update: Received redirectionName '%s'\n", redirection_name);
-
-
-- /* Call Status */
-+#if 0 /* This one is optional. How do we check if it is there? */
-+ /* Basic Call Info Elements */
- GET_COMPONENT(comp, i, vdata, len);
-- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid callStatus type 0x%X of ROSE callTransferComplete component received\n");
-- ASN1_GET_INTEGER(comp, call_status);
- NEXT_COMPONENT(comp, i);
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " CT-Complete: Received callStatus=%d\n", call_status);
-+#endif
-
-
- /* Argument Extension */
-@@ -2078,8 +3365,8 @@
- comp->len = res;
-
- default:
-- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type);
-- return -1;
-+ pri_message(pri, " CT-Update: !! Unknown argumentExtension received 0x%X\n", comp->type);
-+ return -1;
- }
- #else
- GET_COMPONENT(comp, i, vdata, len);
-@@ -2088,7 +3375,7 @@
- #endif
-
- if(i < len)
-- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len);
-+ pri_message(pri, " CT-Update: !! not all information is handled !! i=%d / len=%d\n", i, len);
-
- return 0;
- }
-@@ -2096,26 +3383,422 @@
-
- return -1;
- }
-+#endif
-
-+/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */
-
--static int rose_call_transfer_update_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
-+
-+
-+static int rose_calling_name_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
- {
-+ struct nameelements_name callingname;
-+ int res;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Handle callingName\n");
-+
-+ res = rose_name_decode(pri, (u_int8_t *)sequence, sequence->len + 2, &callingname);
-+ if (res < 0)
-+ return -1;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Received CallingName '%s', namepres: %s(%d), characterset %s(%d)\n",
-+ callingname.name, namepres_to_str(callingname.namepres), callingname.namepres,
-+ characterset_to_str(callingname.characterset), callingname.characterset);
-+
-+ if (callingname.namepres >= 0) {
-+ libpri_copy_string(call->callername, callingname.name, sizeof(call->callername));
-+ }
-+
-+ return 0;
-+}
-+
-+static int rose_called_name_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
-+{
-+ struct nameelements_name calledname;
-+ int res;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Handle calledName\n");
-+
-+ res = rose_name_decode(pri, (u_int8_t *)sequence, sequence->len + 2, &calledname);
-+ if (res < 0)
-+ return -1;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Received CalledName '%s', namepres %s(%d), characterset %s(%d)\n",
-+ calledname.name, namepres_to_str(calledname.namepres), calledname.namepres,
-+ characterset_to_str(calledname.characterset), calledname.characterset);
-+
-+ if (calledname.namepres != 0) {
-+ libpri_copy_string(call->calledname, calledname.name, sizeof(call->calledname));
-+ } else {
-+ call->calledname[0] = '\0';
-+ }
-+
-+ return 0;
-+}
-+
-+int rose_called_name_encode(struct pri *pri, q931_call *call, int messagetype)
-+{
-+ int i = 0, compsp = 0;
-+ struct rose_component *comp, *compstk[10];
-+ unsigned char buffer[256];
-+ int size;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Encode calledName\n");
-+
-+ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */
-+ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
-+
-+ /* Network Facility Extension */
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ /* tag component NetworkFacilityExtension (0xaa, len ) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* sourceEntity (0x80,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */
-+
-+ /* destinationEntity (0x82,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ }
-+
-+ /* Network Protocol Profile */
-+ /* - not included - */
-+
-+ /* Interpretation APDU (0x8b,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */
-+
-+ /* Service APDU(s): */
-+
-+ /* ROSE InvokePDU (0xa1,len) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* ROSE InvokeID (0x02,0x01,invokeid) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
-+
-+ /* ROSE operationId (0x02,0x01,0x02)*/
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, SS_CNOP_CALLEDNAME);
-+
-+ /* tag component namePresentationAllowedSimple (0x80,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* namePresentationAllowedSimple, implicid NameData */
-+ size = rose_namedata_encode(pri, &buffer[i], 1, call->connectedname);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ if (pri_call_apdu_queue(call, messagetype, buffer, i, NULL, NULL))
-+ return -1;
-+
-+ return 0;
-+}
-+
-+static int rose_connected_name_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len)
-+{
-+ struct nameelements_name connectedname;
-+ int res;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Handle connectedName\n");
-+
-+ res = rose_name_decode(pri, (u_int8_t *)sequence, sequence->len + 2, &connectedname);
-+ if (res < 0)
-+ return -1;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Received ConnectedName '%s', namepres %s(%d), characterset %s(%d)\n",
-+ connectedname.name, namepres_to_str(connectedname.namepres), connectedname.namepres,
-+ characterset_to_str(connectedname.characterset), connectedname.characterset);
-+
-+ if (connectedname.namepres != 0) {
-+ libpri_copy_string(call->connectedname, connectedname.name, sizeof(call->connectedname));
-+ } else {
-+ call->connectedname[0] = '\0';
-+ }
-+
-+ return 0;
-+}
-+
-+int rose_connected_name_encode(struct pri *pri, q931_call *call, int messagetype)
-+{
-+ int i = 0, compsp = 0;
-+ struct rose_component *comp, *compstk[10];
-+ unsigned char buffer[256];
-+ int size;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Encode connectedName\n");
-+
-+ /* Protocol Profile = 0x1f (Networking Extensions) (0x9f) */
-+ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
-+
-+ /* Network Facility Extension */
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ /* tag component NetworkFacilityExtension (0xaa, len ) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* sourceEntity (0x80,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* endPINX(0) */
-+
-+ /* destinationEntity (0x82,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* endPINX(0) */
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ }
-+
-+ /* Network Protocol Profile */
-+ /* - not included - */
-+
-+ /* Interpretation APDU (0x8b,0x01,0x00) */
-+ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* discardAnyUnrecognisedInvokePdu(0) */
-+
-+ /* Service APDU(s): */
-+
-+ /* ROSE InvokePDU (0xa1,len) */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* ROSE InvokeID (0x02,0x01,invokeid) */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri));
-+
-+ /* ROSE operationId (0x02,0x01,0x02)*/
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, SS_CNOP_CONNECTEDNAME);
-+
-+ /* tag component namePresentationAllowedSimple (0x80,len) */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* namePresentationAllowedSimple, implicid NameData */
-+ size = rose_namedata_encode(pri, &buffer[i], 1, call->connectedname);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ if (pri_call_apdu_queue(call, messagetype, buffer, i, NULL, NULL))
-+ return -1;
-+
-+ return 0;
-+}
-+
-+/* ===== Begin Call Completion Supplementary Service (ETS 300 366/ECMA 186) ===== */
-+/* operationId e.g. QSIG_CCBSRINGOUT, QSIG_CC_CANCEL */
-+int add_qsigCcInv_facility_ie (struct pri *pri, q931_call *c, int messagetype)
-+{
- int i = 0;
-+ unsigned char buffer[256];
-+ struct rose_component *comp = NULL, *compstk[10];
-+ int compsp = 0;
-+ u_int8_t operationId = c->ccoperation;
-+
-+ /* 1 Byte 0x80 | 0x1F = 9F Protocol Profile */
-+ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
-+
-+ /* Interpretation component */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); /* 2. Byte NEtwork Facility Extension 0xAA = ASN1_CONTEXT_SPECIFIC(0x80) | (ASN1_CONSTRUCTOR 0x20) 0x0A (Tag laut Standard) */
-+ ASN1_PUSH(compstk, compsp, comp);
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* (0x80, 0x01(len), 0x00) endPTNX */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* (0x82, 0x01(len), 0x00) endPTNX */
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* 0x8B, 0x01(len), 0x00 discard */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); /* 0xA1, 0xXX (len of Invoke Sequenz) invoke APDU */
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* Invoke ID */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); /* 0x02 0x01 0xXX */
-+
-+ /* Operation ID: QSIG_CCBSRINGOUT, QSIG_CC_CANCEL */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, operationId); /* 0x02 0x01 0x1f/0x1c */
-+
-+ /* CcExtension */
-+ ASN1_ADD_SIMPLE(comp, ASN1_NULL, buffer, i); /* 0x05 0x00 */
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ if (pri_call_apdu_queue(c, messagetype, buffer, i, NULL, NULL))
-+ return -1;
-+
-+ return 0;
-+}
-+
-+static int rose_cc_ringout_inv_decode(struct pri *pri, struct qsig_cc_extension *cc_extension, struct rose_component *choice, int len) {
-+ int i = 0;
-+ cc_extension->cc_extension_tag = 0;
-+
-+ do {
-+ switch(choice->type) {
-+ case (ASN1_NULL): /* none NULL */
-+ cc_extension->cc_extension_tag = ASN1_NULL;
-+ return 0;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_14): /* single [14] IMPLICIT Extension */
-+ cc_extension->cc_extension_tag = ASN1_TAG_14;
-+ return 0;
-+
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_15): /* multiple [15] IMPLICIT SEQUENCE OF Extension */
-+ cc_extension->cc_extension_tag = ASN1_TAG_15;
-+ return 0;
-+
-+ default:
-+ if (choice->type == 0 && choice->len == 0) {
-+ return 0;
-+ }
-+ pri_message(pri, "!! Invalid ss-cc-optional-Arg component received 0x%X\n", choice->type);
-+ return -1;
-+ }
-+
-+ if (i < len)
-+ pri_message(pri, " ss-cc-extension: !! not all information is handled !! i=%d / len=%d\n", i, len);
-+
-+ return 0;
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+static int rose_cc_optional_arg_decode(struct pri *pri, q931_call *call, struct qsig_cc_optional_arg *cc_optional_arg , struct rose_component *choice, int len) {
-+ int i = 0;
-+ int res = 0;
- struct rose_component *comp = NULL;
-+ unsigned char *vdata = choice->data;
-+ struct addressingdataelements_presentednumberunscreened numberA;
-+ struct addressingdataelements_presentednumberunscreened numberB;
-+
-+ cc_optional_arg->cc_extension.cc_extension_tag = 0;
-+ cc_optional_arg->number_A[0] = '\0';
-+ cc_optional_arg->number_B[0] = '\0';
-+
-+ do {
-+ switch(choice->type) {
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* fullArg [0] IMPLICIT SEQUENCE */
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " ss-cc-optional-Arg: len=%d\n", len);
-+
-+ numberA.partyaddress[0] = '\0';
-+
-+ /* numberA */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ res += rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, &numberA);
-+ if (res < 0)
-+ return -1;
-+ comp->len = res;
-+ if (res > 2) {
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " ss-cc-optional-Arg: Received numberA=%s\n", numberA.partyaddress);
-+ strncpy(cc_optional_arg->number_A, numberA.partyaddress, 20);
-+ cc_optional_arg->number_A[20] = '\0';
-+ }
-+ NEXT_COMPONENT(comp, i);
-+
-+ numberB.partyaddress[0] = '\0';
-+
-+ /* numberB */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ res = rose_party_number_decode(pri, (u_int8_t *)comp, comp->len + 2, &numberB);
-+ if (res < 0)
-+ return -1;
-+ comp->len = res;
-+ if (res > 2) {
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " ss-cc-optional-Arg: Received numberB=%s\n", numberB.partyaddress);
-+ strncpy(cc_optional_arg->number_B, numberB.partyaddress, 20);
-+ cc_optional_arg->number_B[20] = '\0';
-+ }
-+ NEXT_COMPONENT(comp, i);
-+
-+ /* service */ /* PSS1InformationElement */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ NEXT_COMPONENT(comp, i);
-+
-+ /* optional */
-+ for (; i < len; NEXT_COMPONENT(comp, i)) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+ switch(comp->type) {
-+ case (ASN1_NULL): /* */
-+ cc_optional_arg->cc_extension.cc_extension_tag = ASN1_NULL;
-+ NEXT_COMPONENT(comp, i);
-+ break;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_14): /* */
-+ NEXT_COMPONENT(comp, i);
-+ break;
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_15): /* */
-+ NEXT_COMPONENT(comp, i);
-+ break;
-+ default:
-+ if (comp->type == 0 && comp->len == 0) {
-+ return 0;
-+ break; /* Found termination characters */
-+ }
-+ pri_message(pri, "!! Invalid ss-cc-optional-Arg component received 0x%X\n", comp->type);
-+ return -1;
-+ }
-+ }
-+
-+ if (i < len)
-+ pri_message(pri, " ss-cc-optional-Arg: !! not all information is handled !! i=%d / len=%d\n", i, len);
-+
-+ return 0;
-+
-+ /* extArg CcExtension */
-+ case (ASN1_NULL): /* none NULL */
-+ cc_optional_arg->cc_extension.cc_extension_tag = ASN1_NULL;
-+ return 0;
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_14): /* single [14] IMPLICIT Extension */
-+ cc_optional_arg->cc_extension.cc_extension_tag = ASN1_TAG_14;
-+ return 0;
-+
-+
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_15): /* multiple [15] IMPLICIT SEQUENCE OF Extension */
-+ cc_optional_arg->cc_extension.cc_extension_tag = ASN1_TAG_15;
-+ return 0;
-+
-+ default:
-+ if (choice->type == 0 && choice->len == 0) {
-+ return 0;
-+ }
-+ pri_message(pri, "!! Invalid ss-cc-optional-Arg component received 0x%X\n", choice->type);
-+ return -1;
-+ }
-+
-+ if (i < len)
-+ pri_message(pri, " ss-cc-optional-Arg: !! not all information is handled !! i=%d / len=%d\n", i, len);
-+
-+ return 0;
-+ }
-+ while (0);
-+
-+ return -1;
-+}
-+
-+static int rose_cc_request_result_decode(struct pri *pri, struct qsig_cc_request_res *cc_request_res , struct rose_component *sequence, int len)
-+{
-+ int i = 0;
-+ struct rose_component *comp = NULL;
- unsigned char *vdata = sequence->data;
-- int res = 0;
-
-- struct addressingdataelements_presentednumberscreened redirection_number;
-- redirection_number.partyaddress[0] = 0;
-- redirection_number.partysubaddress[0] = 0;
-- char redirection_name[50] = "";
-- call->callername[0] = 0;
-- call->callernum[0] = 0;
-+ cc_request_res->no_path_reservation = 0; /* Default FALSE */
-+ cc_request_res->retain_service = 0; /* Default FALSE */
-+ cc_request_res->cc_extension.cc_extension_tag = 0;
-
--
- /* Data checks */
- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
-- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n");
-+ pri_message(pri, "Invalid cc request result argument. (Not a sequence)\n");
- return -1;
- }
-
-@@ -2126,75 +3809,55 @@
- len -= 2;
-
- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " CT-Complete: len=%d\n", len);
-+ pri_message(pri, " CC-request-Return-Result: len=%d\n", len);
-
- do {
-- /* Redirection Number */
-- GET_COMPONENT(comp, i, vdata, len);
-- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number);
-- if (res < 0)
-- return -1;
-- comp->len = res;
-- if (res > 2) {
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress);
-- strncpy(call->callernum, redirection_number.partyaddress, 20);
-- call->callernum[20] = 0;
-- }
-- NEXT_COMPONENT(comp, i);
-+ /* defaults and optional */
-+ for (; i < len; NEXT_COMPONENT(comp, i)) {
-+ GET_COMPONENT(comp, i, vdata, len);
-+ switch(comp->type) {
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0):
-+ /* no-path-reservation */
-+ ASN1_GET_INTEGER(comp, cc_request_res->no_path_reservation);
-+ NEXT_COMPONENT(comp, i);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " cc request result: Received noPathReservation=%d\n", cc_request_res->no_path_reservation);
-+ break;
-
-- /* Redirection Name */
-- GET_COMPONENT(comp, i, vdata, len);
-- res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name));
-- if (res < 0)
-- return -1;
-- memcpy(call->callername, comp->data, comp->len);
-- call->callername[comp->len] = 0;
-- ASN1_FIXUP_LEN(comp, res);
-- comp->len = res;
-- NEXT_COMPONENT(comp, i);
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name);
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1):
-+ /* retain_service */
-+ ASN1_GET_INTEGER(comp, cc_request_res->retain_service);
-+ NEXT_COMPONENT(comp, i);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " cc request result: Received retainService=%d\n", cc_request_res->retain_service);
-+ break;
-
-+ case (ASN1_NULL): /* */
-+ cc_request_res->cc_extension.cc_extension_tag = ASN1_NULL;
-+ NEXT_COMPONENT(comp, i);
-+ break;
-
--#if 0 /* This one is optional. How do we check if it is there? */
-- /* Basic Call Info Elements */
-- GET_COMPONENT(comp, i, vdata, len);
-- NEXT_COMPONENT(comp, i);
--#endif
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_14):
-+ cc_request_res->cc_extension.cc_extension_tag = ASN1_TAG_14;
-+ NEXT_COMPONENT(comp, i);
-+ break;
-
-+ case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_15):
-+ cc_request_res->cc_extension.cc_extension_tag = ASN1_TAG_15;
-+ NEXT_COMPONENT(comp, i);
-+ break;
-
-- /* Argument Extension */
--#if 0 /* Not supported */
-- GET_COMPONENT(comp, i, vdata, len);
-- switch (comp->type) {
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */
-- res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
-- if (res < 0)
-- return -1;
-- ASN1_FIXUP_LEN(comp, res);
-- comp->len = res;
--
-- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */
-- res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number);
-- if (res < 0)
-- return -1;
-- ASN1_FIXUP_LEN(comp, res);
-- comp->len = res;
--
- default:
-- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type);
-+ if (comp->type == 0 && comp->len == 0) {
-+ break; /* Found termination characters */
-+ }
-+ pri_message(pri, "!! Invalid ss-cc-optional-Arg component received 0x%X\n", comp->type);
- return -1;
-+ }
- }
--#else
-- GET_COMPONENT(comp, i, vdata, len);
-- ASN1_FIXUP_LEN(comp, res);
-- NEXT_COMPONENT(comp, i);
--#endif
-
-- if(i < len)
-- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len);
--
-+ if (i < len)
-+ pri_message(pri, " ss-cc-optional-Arg: !! not all information is handled !! i=%d / len=%d\n", i, len);
- return 0;
- }
- while (0);
-@@ -2202,11 +3865,18 @@
- return -1;
- }
-
-+static int rose_ccbs_request_result_decode(struct pri *pri, struct qsig_cc_request_res *cc_request_res , struct rose_component *sequence, int len)
-+{
-+ return rose_cc_request_result_decode(pri, cc_request_res , sequence, len);
-+}
-
--/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */
-+static int rose_ccnr_request_result_decode(struct pri *pri, struct qsig_cc_request_res *cc_request_res , struct rose_component *sequence, int len)
-+{
-+ return rose_cc_request_result_decode(pri, cc_request_res , sequence, len);
-+}
-+/* ===== End Call Completion Supplementary Service (ETS 300 366/ECMA 186) ===== */
-
-
--
- int rose_reject_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
- {
- int i = 0;
-@@ -2267,7 +3937,7 @@
-
- return 0;
- } else {
-- pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype);
-+ pri_message(pri, "Unable to handle reject on switchtype %d!\n", pri->switchtype);
- return -1;
- }
-
-@@ -2275,6 +3945,20 @@
-
- return -1;
- }
-+
-+
-+static struct subcommand *get_ptr_subcommand(struct subcommands *sub)
-+{
-+ if (sub->counter_subcmd < MAX_SUBCOMMANDS) {
-+ int count = sub->counter_subcmd;
-+ sub->counter_subcmd++;
-+ return &sub->subcmd[count];
-+ }
-+
-+ return NULL;
-+}
-+
-+
- int rose_return_error_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len)
- {
- int i = 0;
-@@ -2283,6 +3967,7 @@
- unsigned char *vdata = data;
- struct rose_component *comp = NULL;
- char *invokeidstr, *errorstr;
-+ struct subcommand *c_subcmd;
-
- do {
- /* Invoke ID stuff */
-@@ -2329,9 +4014,39 @@
- pri_error(pri, "\tERROR: %s\n", errorstr);
-
- return 0;
-+ } else if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ switch (errorvalue) {
-+ case 1008:
-+ errorstr = "Unspecified";
-+ break;
-+ case 1012:
-+ errorstr = "Remote user busy again";
-+ break;
-+ case 1013:
-+ errorstr = "Failure to match";
-+ break;
-+ default:
-+ errorstr = "Unknown";
-+ }
-+
-+ c_subcmd = get_ptr_subcommand(&call->subcmds);
-+ if (!c_subcmd) {
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE RETURN ERROR %i - more than %d facilities !\n", errorvalue, MAX_SUBCOMMANDS);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ }
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ {
-+ pri_message(pri, "ROSE RETURN RESULT %i: %s\n", errorvalue, errorstr);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ c_subcmd->cmd = CMD_CC_ERROR;
-+ c_subcmd->cc_error.error_value = errorvalue;
-+ return 0;
- } else {
-- pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype);
-- return -1;
-+ pri_message(pri, "Unable to handle return error on switchtype %d!\n", pri->switchtype);
- }
-
- } while(0);
-@@ -2346,6 +4061,8 @@
- int invokeidvalue = -1;
- unsigned char *vdata = data;
- struct rose_component *comp = NULL;
-+ int res;
-+ struct subcommand *c_subcmd;
-
- do {
- /* Invoke ID stuff */
-@@ -2392,11 +4109,90 @@
- return -1;
- }
- } else if (pri->switchtype == PRI_SWITCH_QSIG) {
-- switch (invokeidvalue) {
-- case 0x13:
-- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed QSIG CF callRerouting!\n");
-+ int operation_tag;
-+
-+ /* sequence is optional */
-+ if (i >= len)
- return 0;
-+
-+ /* Data checks, sequence is optional */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ if (comp->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */
-+ pri_message(pri, "No arguments on cc-return result\n");
-+ return 0;
- }
-+
-+ if (comp->len == ASN1_LEN_INDEF) {
-+ len -= 2; /* For the 2 extra characters at the end*/
-+ }
-+
-+ /* Traverse the contents of this sequence */
-+ SUB_COMPONENT(comp, i);
-+
-+ /* Operation Tag */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if second ROSE component is of type 0x%x\n");
-+ ASN1_GET_INTEGER(comp, operation_tag);
-+ NEXT_COMPONENT(comp, i);
-+
-+ /* No argument - return with error */
-+ if (i >= len)
-+ return -1;
-+
-+ /* Arguement Tag */
-+ GET_COMPONENT(comp, i, vdata, len);
-+ if (!comp->type)
-+ return -1;
-+
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " [ Handling operation %d ]\n", operation_tag);
-+ switch (operation_tag) {
-+ case QSIG_CF_CALLREROUTING:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "Successfully completed QSIG CF callRerouting!\n");
-+ return 0;
-+
-+ case QSIG_CC_CCBSREQUEST:
-+ c_subcmd = get_ptr_subcommand(&call->subcmds);
-+ if (!c_subcmd) {
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: return_result CcCcbsRequest - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ }
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ {
-+ pri_message(pri, "ROSE %i: Handle CcCcbsRequest\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ c_subcmd->cmd = CMD_CC_CCBSREQUEST_RR;
-+ res = rose_ccbs_request_result_decode(pri, &c_subcmd->cc_ccbs_rr.cc_request_res, comp, len-i);
-+ return res;
-+
-+ case QSIG_CC_CCNRREQUEST:
-+ c_subcmd = get_ptr_subcommand(&call->subcmds);
-+ if (!c_subcmd) {
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: return_result CcCcnrRequest - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ }
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ {
-+ pri_message(pri, "ROSE %i: Handle CcCcnrRequest\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ c_subcmd->cmd = CMD_CC_CCNRREQUEST_RR;
-+ res = rose_ccnr_request_result_decode(pri, &c_subcmd->cc_ccnr_rr.cc_request_res, comp, len-i);
-+ return res;
-+
-+ default:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return -1;
-+ }
- } else {
- pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype);
- return -1;
-@@ -2414,6 +4210,7 @@
- int operation_tag;
- unsigned char *vdata = data;
- struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL;
-+ struct subcommand *c_subcmd;
-
- do {
- /* Invoke ID stuff */
-@@ -2444,126 +4241,294 @@
-
- if (pri->debug & PRI_DEBUG_APDU)
- pri_message(pri, " [ Handling operation %d ]\n", operation_tag);
-- switch (operation_tag) {
-- case SS_CNID_CALLINGNAME:
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, " Handle Name display operation\n");
-- return rose_calling_name_decode(pri, call, comp, len-i);
-- case ROSE_CALL_TRANSFER_IDENTIFY:
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag);
-- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- return -1;
-- case ROSE_CALL_TRANSFER_ABANDON:
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag);
-- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- return -1;
-- case ROSE_CALL_TRANSFER_INITIATE:
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag);
-- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- return -1;
-- case ROSE_CALL_TRANSFER_SETUP:
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag);
-- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- return -1;
-- case ROSE_CALL_TRANSFER_ACTIVE:
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, "ROSE %i: CallTransferActive - not handled!\n", operation_tag);
-- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- return -1;
-- case ROSE_CALL_TRANSFER_COMPLETE:
-- if (pri->debug & PRI_DEBUG_APDU)
-- {
-- pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag);
-+
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+
-+ switch (operation_tag) {
-+ case SS_CNID_CALLINGNAME:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return rose_calling_name_decode(pri, call, comp, len-i);
-+ case SS_CNOP_CALLEDNAME:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: Handle CalledName\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return rose_called_name_decode(pri, call, comp, len-i);
-+ case SS_CNOP_CONNECTEDNAME:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: Handle ConnectedName\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return rose_connected_name_decode(pri, call, comp, len-i);
-+ case ROSE_CALL_TRANSFER_IDENTIFY:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag);
- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- }
-- return rose_call_transfer_complete_decode(pri, call, comp, len-i);
-- case ROSE_CALL_TRANSFER_UPDATE:
-- if (pri->debug & PRI_DEBUG_APDU)
-- {
-- pri_message(pri, "ROSE %i: Handle CallTransferUpdate\n", operation_tag);
-+ return -1;
-+ case ROSE_CALL_TRANSFER_ABANDON:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag);
- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- }
-- return rose_call_transfer_update_decode(pri, call, comp, len-i);
-- case ROSE_SUBADDRESS_TRANSFER:
-- if (pri->debug & PRI_DEBUG_APDU)
-- pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag);
-- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- return -1;
-- case ROSE_DIVERTING_LEG_INFORMATION2:
-- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag);
-- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- }
-- return rose_diverting_leg_information2_decode(pri, call, comp, len-i);
-- case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE:
-- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag);
-- dump_apdu (pri, comp->data, comp->len);
-- }
-- return -1;
-- case ROSE_AOC_CHARGING_REQUEST:
-- return aoc_aoce_charging_request_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
-- case ROSE_AOC_AOCS_CURRENCY:
-- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, "ROSE %i: AOC-S Currency - not handled!", operation_tag);
-+ return -1;
-+ case ROSE_CALL_TRANSFER_INITIATE:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag);
- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- }
-- return -1;
-- case ROSE_AOC_AOCS_SPECIAL_ARR:
-- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, "ROSE %i: AOC-S Special Array - not handled!", operation_tag);
-+ return -1;
-+ case ROSE_CALL_TRANSFER_SETUP:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag);
- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- }
-- return -1;
-- case ROSE_AOC_AOCD_CURRENCY:
-- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, "ROSE %i: AOC-D Currency - not handled!", operation_tag);
-+ return -1;
-+ case ROSE_CALL_TRANSFER_ACTIVE:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: Handle CallTransferActive\n", operation_tag);
- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- }
-- return -1;
-- case ROSE_AOC_AOCD_CHARGING_UNIT:
-- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, "ROSE %i: AOC-D Charging Unit - not handled!", operation_tag);
-+ return rose_call_transfer_active_decode(pri, call, comp, len-i);
-+ case ROSE_CALL_TRANSFER_COMPLETE:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ {
-+ pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return rose_call_transfer_complete_decode(pri, call, comp, len-i);
-+ case ROSE_CALL_TRANSFER_UPDATE:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferUpdate - not handled!\n", operation_tag);
- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- }
-- return -1;
-- case ROSE_AOC_AOCE_CURRENCY:
-- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, "ROSE %i: AOC-E Currency - not handled!", operation_tag);
-+ return -1;
-+ case ROSE_SUBADDRESS_TRANSFER:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag);
- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-- }
-- return -1;
-- case ROSE_AOC_AOCE_CHARGING_UNIT:
-- return aoc_aoce_charging_unit_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
-- if (0) { /* the following function is currently not used - just to make the compiler happy */
-- aoc_aoce_charging_unit_encode(pri, call, call->aoc_units); /* use this function to forward the aoc-e on a bridged channel */
-+ return -1;
-+ case ROSE_DIVERTING_LEG_INFORMATION1:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Handle DivertingLegInformation1\n");
-+ return rose_diverting_leg_information1_decode(pri, call, comp, len-i);
-+ case ROSE_DIVERTING_LEG_INFORMATION2:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Handle DivertingLegInformation2\n");
-+ return rose_diverting_leg_information2_decode(pri, call, comp, len-i);
-+ case ROSE_DIVERTING_LEG_INFORMATION3:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Handle DivertingLegInformation3\n");
-+ return rose_diverting_leg_information3_decode(pri, call, comp, len-i);
-+ case SS_ANFPR_PATHREPLACEMENT:
-+ /* Clear Queue */
-+ res = pri_call_apdu_queue_cleanup(call->bridged_call);
-+ if (res) {
-+ pri_message(pri, "Could not Clear queue ADPU\n");
-+ return -1;
-+ }
-+ anfpr_pathreplacement_respond(pri, call, ie);
-+ break;
-+ case QSIG_CC_CCBSREQUEST:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: invoke CcbsRequest - not handled!\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ case QSIG_CC_CCNRREQUEST:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: invoke CcnrRequest - not handled!\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ case QSIG_CC_CANCEL:
-+ c_subcmd = get_ptr_subcommand(&call->subcmds);
-+ if (!c_subcmd) {
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: invoke CcCancel - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ }
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ {
-+ pri_message(pri, "ROSE %i: Handle CcCancel\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ c_subcmd->cmd = CMD_CC_CANCEL_INV;
-+ res = rose_cc_optional_arg_decode(pri, call, &c_subcmd->cc_cancel_inv.cc_optional_arg, comp, len-i);
-+ return res;
-+ case QSIG_CC_EXECPOSIBLE:
-+ c_subcmd = get_ptr_subcommand(&call->subcmds);
-+ if (!c_subcmd) {
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: invoke CcExecposible - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ }
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ {
-+ pri_message(pri, "ROSE %i: Handle CcExecposible\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ c_subcmd->cmd = CMD_CC_EXECPOSIBLE_INV;
-+ res = rose_cc_optional_arg_decode(pri, call, &c_subcmd->cc_execposible_inv.cc_optional_arg, comp, len-i);
-+ return res;
-+ case QSIG_CC_PATHRESERVE:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: invoke CcPathreserve - not handled!\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ case QSIG_CC_RINGOUT:
-+ c_subcmd = get_ptr_subcommand(&call->subcmds);
-+ if (!c_subcmd) {
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: invoke CcRingout - more than %d facilities !\n", operation_tag, MAX_SUBCOMMANDS);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ }
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ {
-+ pri_message(pri, "ROSE %i: Handle CcRingout\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ c_subcmd->cmd = CMD_CC_RINGOUT_INV;
-+ res = rose_cc_ringout_inv_decode(pri, &c_subcmd->cc_ringout_inv.cc_extension, comp, len-i);
-+ return res;
-+ case QSIG_CC_SUSPEND:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ {
-+ pri_message(pri, "ROSE %i: Handle CcSuspend\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
- return 0;
-- }
-- case ROSE_AOC_IDENTIFICATION_OF_CHARGE:
-- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, "ROSE %i: AOC Identification Of Charge - not handled!", operation_tag);
-+ case QSIG_CC_RESUME:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: invoke CcResume - not handled!\n", operation_tag);
- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ default:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return -1;
- }
-- return -1;
-- case SS_ANFPR_PATHREPLACEMENT:
-- /* Clear Queue */
-- res = pri_call_apdu_queue_cleanup(call->bridged_call);
-- if (res) {
-- pri_message(pri, "Could not Clear queue ADPU\n");
-- return -1;
-- }
-- anfpr_pathreplacement_respond(pri, call, ie);
-- break;
-- default:
-- if (pri->debug & PRI_DEBUG_APDU) {
-- pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag);
-+ } else { /* pri->switchtype == PRI_SWITCH_QSIG */
-+
-+ switch (operation_tag) {
-+ case SS_CNID_CALLINGNAME:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return rose_calling_name_decode(pri, call, comp, len-i);
-+ case ROSE_CALL_TRANSFER_IDENTIFY:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag);
- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ case ROSE_CALL_TRANSFER_ABANDON:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ case ROSE_CALL_TRANSFER_INITIATE:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ case ROSE_CALL_TRANSFER_SETUP:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ case ROSE_CALL_TRANSFER_ACTIVE:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: Handle CallTransferActive\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return rose_call_transfer_active_decode(pri, call, comp, len-i);
-+ case ROSE_CALL_TRANSFER_COMPLETE:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ {
-+ pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return rose_call_transfer_complete_decode(pri, call, comp, len-i);
-+ case ROSE_CALL_TRANSFER_UPDATE:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: CallTransferUpdate - not handled!\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ case ROSE_SUBADDRESS_TRANSFER:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ return -1;
-+ case ROSE_DIVERTING_LEG_INFORMATION2:
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, " Handle DivertingLegInformation2\n");
-+ return rose_diverting_leg_information2_decode(pri, call, comp, len-i);
-+ case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag);
-+ dump_apdu (pri, comp->data, comp->len);
-+ }
-+ return -1;
-+ case ROSE_AOC_CHARGING_REQUEST:
-+ return aoc_aoce_charging_request_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
-+ case ROSE_AOC_AOCS_CURRENCY:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: AOC-S Currency - not handled!", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return -1;
-+ case ROSE_AOC_AOCS_SPECIAL_ARR:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: AOC-S Special Array - not handled!", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return -1;
-+ case ROSE_AOC_AOCD_CURRENCY:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: AOC-D Currency - not handled!", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return -1;
-+ case ROSE_AOC_AOCD_CHARGING_UNIT:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: AOC-D Charging Unit - not handled!", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return -1;
-+ case ROSE_AOC_AOCE_CURRENCY:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: AOC-E Currency - not handled!", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return -1;
-+ case ROSE_AOC_AOCE_CHARGING_UNIT:
-+ return aoc_aoce_charging_unit_decode(pri, call, (u_int8_t *)comp, comp->len + 2);
-+ if (0) { /* the following function is currently not used - just to make the compiler happy */
-+ aoc_aoce_charging_unit_encode(pri, call, call->aoc_units); /* use this function to forward the aoc-e on a bridged channel */
-+ return 0;
-+ }
-+ case ROSE_AOC_IDENTIFICATION_OF_CHARGE:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "ROSE %i: AOC Identification Of Charge - not handled!", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return -1;
-+ case SS_ANFPR_PATHREPLACEMENT:
-+ /* Clear Queue */
-+ res = pri_call_apdu_queue_cleanup(call->bridged_call);
-+ if (res) {
-+ pri_message(pri, "Could not Clear queue ADPU\n");
-+ return -1;
-+ }
-+ anfpr_pathreplacement_respond(pri, call, ie);
-+ break;
-+ default:
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag);
-+ dump_apdu (pri, (u_int8_t *)comp, comp->len + 2);
-+ }
-+ return -1;
- }
-- return -1;
- }
- } while(0);
-
-@@ -2619,15 +4584,119 @@
- return 0;
- }
-
-+/* ===== Begin Call Completion Supplementary Service (ETS 300 366/ECMA 186) ===== */
-+/* operationId e.g. QSIG_CC_CCBS_REQUEST and QSIG_CC_CCNR_REQUEST */
-+static int add_qsigCcRequestArg_facility_ie (struct pri *pri, q931_call *c)
-+{
-+ int size = 0;
-+ int i = 0;
-+ unsigned char buffer[256];
-+ struct rose_component *comp = NULL, *compstk[10];
-+ int compsp = 0;
-+ u_int8_t operationId = c->ccoperation;
-+ char *numberA = c->callernum;
-+ char *numberB = c->callednum;
-+
-+ /* 1 Byte 0x80 | 0x1F = 9F Protocol Profile (0x93 wäre altes QSIG oder DDS1) */
-+ buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS);
-+
-+ /* Interpretation component */
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); /* 2. Byte NEtwork Facility Extension 0xAA = ASN1_CONTEXT_SPECIFIC(0x80) | (ASN1_CONSTRUCTOR 0x20) 0x0A (Tag laut Standard) */
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); /* (0x80, 0x01(len), 0x00) endPTNX */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* (0x82, 0x01(len), 0x00) endPTNX */
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+#if 0
-+ ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); /* 0x8B, 0x01(len), 0x00 discard */
-+#endif
-+ ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); /* 0xA1, 0xXX (len of Invoke Sequenz) invoke APDU */
-+ ASN1_PUSH(compstk, compsp, comp);
-+
-+ /* Invoke ID */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); /* InvokeID 0x02 0x01 0xXX */
-+
-+ /*CcbsRequest ::= 40 or CcnrRequest ::= 27 */
-+ /* Operation ID: CCBS/CCNR */
-+ ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, operationId); /* 0x02 0x01 0x28/0x1b */
-+
-+ /* ccbs/ccnr request argument */
-+ /* PresentedNumberUnscreened */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); /*0x30 0xXX (len)*/
-+ ASN1_PUSH(compstk, compsp, comp);
-+ /* (0xA0, 0x01(len)) presentationAlloweAddress [0] PartyNumber */
-+ /* (0xA1, 0xXX (len) publicPartyNumber [1] IMPLICIT PublicPartyNumber */
-+ /* (0x0A, 0x01, 0x00 ) type of public party number = subscriber number */
-+ /* (0x12, 0xXX (len), 0xXX .. 0xXX) numeric string */
-+ size = rose_presented_number_unscreened_encode(pri, &buffer[i], PRES_ALLOWED, Q932_TON_UNKNOWN, numberA);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+
-+ /* (0xA1, 0xXX (len) [1] IMPLICIT PublicPartyNumber */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+ /* (0x0A, 0x01, 0x00 ) type of public party number = subscriber number */
-+ /* (0x12, 0xXX (len), 0xXX .. 0xXX) numeric string */
-+ size = rose_public_party_number_encode(pri, comp->data, 1, Q932_TON_UNKNOWN, numberB);
-+ if (size < 0)
-+ return -1;
-+ i += size;
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ /* (0x40, 0xXX (len), 0xXX .. 0xXX) pSS1InfoElement */
-+ ASN1_ADD_SIMPLE(comp, (ASN1_APPLICATION | ASN1_TAG_0 ), buffer, i);
-+ ASN1_PUSH(compstk, compsp, comp);
-+ buffer[i++] = (0x04); /* add Bearer Capability IE */
-+ buffer[i++] = (0x03); /* len*/
-+ buffer[i++] = (0x80); /* ETSI Standard, Speech */
-+ buffer[i++] = (0x90); /* circuit mode, 64kbit/s */
-+ buffer[i++] = (0xa3); /* level1 protocol, a-law */
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+#if 0
-+ /* can-retain-service [12] IMPLICIT BOOLEAN DEFAULT FALSE,*/
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_12), buffer, i, 0); /* 0x1C, 0x01(len), 0x00 false */
-+#endif
-+ /* retain-sig-connection [13] IMPLICIT BOOLEAN OPTIONAL, --TRUE: sign. connection to be retained */
-+ ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_13), buffer, i, 1); /* 0x1D, 0x01(len), 0x01 true */
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ ASN1_FIXUP(compstk, compsp, buffer, i);
-+
-+ if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL))
-+ return -1;
-+
-+ return 0;
-+}
-+/* ===== End Call Completion Supplementary Service (ETS 300 366/ECMA 186) ===== */
-+
- int pri_call_add_standard_apdus(struct pri *pri, q931_call *call)
- {
- if (!pri->sendfacility)
- return 0;
-
- if (pri->switchtype == PRI_SWITCH_QSIG) { /* For Q.SIG it does network and cpe operations */
-- if (call->redirectingnum[0])
-+ if (call->redirectingnum[0])
- rose_diverting_leg_information2_encode(pri, call);
- add_callername_facility_ies(pri, call, 1);
-+ if (call->ccoperation) {
-+ switch(call->ccoperation) {
-+ case 0:
-+ break;
-+ case QSIG_CC_CCBSREQUEST:
-+ case QSIG_CC_CCNRREQUEST:
-+ add_qsigCcRequestArg_facility_ie(pri, call);
-+ break;
-+ case QSIG_CC_RINGOUT:
-+ add_qsigCcInv_facility_ie(pri, call, Q931_SETUP);
-+ break;
-+ default:
-+ break;
-+ }
-+ }
- return 0;
- }
-
-@@ -2665,3 +4734,26 @@
- return 0;
- }
-
-+int qsig_initiate_diverting_leg_information1(struct pri *pri, q931_call *call)
-+{
-+ rose_diverting_leg_information1_encode(pri, call);
-+
-+ if (q931_facility(pri, call)) {
-+ pri_message(pri, "Could not schedule facility message for divertingLegInfo1\n");
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+int qsig_initiate_call_transfer_complete(struct pri *pri, q931_call *call, int call_status)
-+{
-+ rose_call_transfer_complete_encode(pri, call, call_status);
-+
-+ if (q931_facility(pri, call)) {
-+ pri_message(pri, "Could not schedule facility message for callTransferComplete\n");
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-Index: pri_timers.h
-===================================================================
---- a/pri_timers.h (.../tags/1.4.9) (revision 700)
-+++ b/pri_timers.h (.../team/group/issue14292) (revision 700)
-@@ -62,6 +62,7 @@
- -1, /* T322 */ \
- 2500, /* TM20 - Q.921 Appendix IV */ \
- 3, /* NM20 - Q.921 Appendix IV */ \
-+ 45*60*1000 /* CC-Timer2 45 min */\
- }
-
- /* XXX Only our default timers are setup now XXX */
-Index: pri_facility.h
-===================================================================
---- a/pri_facility.h (.../tags/1.4.9) (revision 700)
-+++ b/pri_facility.h (.../team/group/issue14292) (revision 700)
-@@ -38,14 +38,6 @@
- #define Q932_PROTOCOL_GAT 0x16
- #define Q932_PROTOCOL_EXTENSIONS 0x1F
-
--/* Argument values */
--#define ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE 0x80
--#define ROSE_NAME_PRESENTATION_RESTRICTED_NULL 0x87
--#define ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED 0xA1
--#define ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE 0xA2
--#define ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED 0xA3
--#define ROSE_NAME_NOT_AVAIL 0x84
--
- /* Component types */
- #define COMP_TYPE_INTERPRETATION 0x8B
- #define COMP_TYPE_NETWORK_PROTOCOL_PROFILE 0x92
-@@ -65,10 +57,11 @@
- #define ROSE_CALL_TRANSFER_COMPLETE 12
- #define ROSE_CALL_TRANSFER_UPDATE 13
- #define ROSE_SUBADDRESS_TRANSFER 14
-+#define QSIG_CF_CALLREROUTING 19
- /* Q.952 ROSE operations (Diverting) */
--#define ROSE_DIVERTING_LEG_INFORMATION1 18
--#define ROSE_DIVERTING_LEG_INFORMATION2 0x15
--#define ROSE_DIVERTING_LEG_INFORMATION3 19
-+#define ROSE_DIVERTING_LEG_INFORMATION1 20
-+#define ROSE_DIVERTING_LEG_INFORMATION2 21
-+#define ROSE_DIVERTING_LEG_INFORMATION3 22
- /* Q.956 ROSE operations (Advice Of Charge) */
- #define ROSE_AOC_NO_CHARGING_INFO_AVAILABLE 26
- #define ROSE_AOC_CHARGING_REQUEST 30
-@@ -81,12 +74,27 @@
- #define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37
- /* Q.SIG operations */
- #define SS_CNID_CALLINGNAME 0
-+#define SS_CNOP_CALLEDNAME 1
-+#define SS_CNOP_CONNECTEDNAME 2
- #define SS_ANFPR_PATHREPLACEMENT 4
--#define SS_DIVERTING_LEG_INFORMATION2 21
- #define SS_MWI_ACTIVATE 80
- #define SS_MWI_DEACTIVATE 81
- #define SS_MWI_INTERROGATE 82
-
-+/* ECMA 186 */
-+#define QSIG_CC_CCNRREQUEST PRI_CC_CCNRREQUEST /* 27 */
-+#define QSIG_CC_CANCEL PRI_CC_CANCEL /* 28 */
-+#define QSIG_CC_EXECPOSIBLE 29
-+#define QSIG_CC_PATHRESERVE 30
-+#define QSIG_CC_RINGOUT 31
-+#define QSIG_CC_SUSPEND 32
-+#define QSIG_CC_RESUME 33
-+#define QSIG_CC_CCBSREQUEST PRI_CC_CCBSREQUEST /* 40 */
-+
-+#define QSIG_CC_UNSPECIFIED 1008
-+#define QSIG_CC_REMOTE_USER_BUSY_AGAIN 1012
-+#define QSIG_CC_FAILURE_TO_MATCH 1013
-+
- /* ROSE definitions and data structures */
- #define INVOKE_IDENTIFIER 0x02
- #define INVOKE_LINKED_IDENTIFIER 0x80
-@@ -128,6 +136,12 @@
- #define ASN1_TAG_7 0x07
- #define ASN1_TAG_8 0x08
- #define ASN1_TAG_9 0x09
-+#define ASN1_TAG_10 0x0a
-+#define ASN1_TAG_11 0x0b
-+#define ASN1_TAG_12 0x0c
-+#define ASN1_TAG_13 0x0d
-+#define ASN1_TAG_14 0x0e
-+#define ASN1_TAG_15 0x0f
-
- /* ASN.1 Identifier Octet - Primitive/Constructor Bit */
- #define ASN1_PC_MASK 0x20
-@@ -169,6 +183,20 @@
- #define Q932_TON_SUBSCRIBER 0x04
- #define Q932_TON_ABBREVIATED 0x06
-
-+/* Q.SIG Character Sets. Listed in ISO/IEC 8859 */
-+#define CHARACTER_SET_UNKNOWN 0x00
-+#define CHARACTER_SET_ISO8859_1 0x01
-+#define CHARACTER_SET_ISO8859_2 0x03
-+#define CHARACTER_SET_ISO8859_3 0x04
-+#define CHARACTER_SET_ISO8859_4 0x05
-+#define CHARACTER_SET_ISO8859_5 0x06
-+#define CHARACTER_SET_ISO8859_7 0x07
-+
-+/* Q.SIG Subscription Option. Listed in ECMA-174 */
-+#define QSIG_NO_NOTIFICATION 0x00
-+#define QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR 0x01
-+#define QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR 0x02
-+
- /* RLT related Operations */
- #define RLT_SERVICE_ID 0x3e
- #define RLT_OPERATION_IND 0x01
-@@ -314,6 +342,18 @@
- /* starts a QSIG Path Replacement */
- int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2);
-
-+int qsig_initiate_diverting_leg_information1(struct pri *pri, q931_call *call);
-+
-+int qsig_initiate_call_transfer_complete(struct pri *pri, q931_call *call, int call_status);
-+
-+int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call);
-+
-+int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype);
-+
-+int rose_connected_name_encode(struct pri *pri, q931_call *call, int messagetype);
-+
-+int rose_called_name_encode(struct pri *pri, q931_call *call, int messagetype);
-+
- /* Use this function to queue a facility-IE born APDU onto a call
- * call is the call to use, messagetype is any one of the Q931 messages,
- * apdu is the apdu data, apdu_len is the length of the apdu data */
-@@ -325,6 +365,8 @@
- /* Adds the "standard" APDUs to a call */
- int pri_call_add_standard_apdus(struct pri *pri, q931_call *call);
-
-+int add_qsigCcInv_facility_ie (struct pri *pri, q931_call *c, int messagetype);
-+
- int asn1_dump(struct pri *pri, void *comp, int len);
-
- #endif /* _PRI_FACILITY_H */
-Index: libpri.h
-===================================================================
---- a/libpri.h (.../tags/1.4.9) (revision 700)
-+++ b/libpri.h (.../team/group/issue14292) (revision 700)
-@@ -81,6 +81,7 @@
- #define PRI_EVENT_NOTIFY 16 /* Notification received */
- #define PRI_EVENT_PROGRESS 17 /* When we get CALL_PROCEEDING or PROGRESS */
- #define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state */
-+#define PRI_EVENT_FACILITY 19 /* Facility received */
-
- /* Simple states */
- #define PRI_STATE_DOWN 0
-@@ -135,16 +136,45 @@
- #define PRI_UNKNOWN 0x0
-
- /* Presentation */
--#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00
--#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01
--#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02
--#define PRES_ALLOWED_NETWORK_NUMBER 0x03
--#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20
--#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21
--#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22
--#define PRES_PROHIB_NETWORK_NUMBER 0x23
--#define PRES_NUMBER_NOT_AVAILABLE 0x43
-+#define PRES_NUMBER_TYPE 0x03
-+#define PRES_USER_NUMBER_UNSCREENED 0x00
-+#define PRES_USER_NUMBER_PASSED_SCREEN 0x01
-+#define PRES_USER_NUMBER_FAILED_SCREEN 0x02
-+#define PRES_NETWORK_NUMBER 0x03
-
-+#define PRES_RESTRICTION 0x60
-+#define PRES_ALLOWED 0x00
-+#define PRES_RESTRICTED 0x20
-+#define PRES_UNAVAILABLE 0x40
-+#define PRES_RESERVED 0x60
-+
-+#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED \
-+ (PRES_ALLOWED | PRES_USER_NUMBER_UNSCREENED)
-+
-+#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN \
-+ (PRES_ALLOWED | PRES_USER_NUMBER_PASSED_SCREEN)
-+
-+#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN \
-+ (PRES_ALLOWED | PRES_USER_NUMBER_FAILED_SCREEN)
-+
-+#define PRES_ALLOWED_NETWORK_NUMBER \
-+ (PRES_ALLOWED | PRES_NETWORK_NUMBER)
-+
-+#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED \
-+ (PRES_RESTRICTED | PRES_USER_NUMBER_UNSCREENED)
-+
-+#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN \
-+ (PRES_RESTRICTED | PRES_USER_NUMBER_PASSED_SCREEN)
-+
-+#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN \
-+ (PRES_RESTRICTED | PRES_USER_NUMBER_FAILED_SCREEN)
-+
-+#define PRES_PROHIB_NETWORK_NUMBER \
-+ (PRES_RESTRICTED | PRES_NETWORK_NUMBER)
-+
-+#define PRES_NUMBER_NOT_AVAILABLE \
-+ (PRES_UNAVAILABLE | PRES_NETWORK_NUMBER)
-+
- /* Causes for disconnection */
- #define PRI_CAUSE_UNALLOCATED 1
- #define PRI_CAUSE_NO_ROUTE_TRANSIT_NET 2 /* !Q.SIG */
-@@ -303,8 +333,141 @@
- #define PRI_NSF_ATT_MULTIQUEST 0xF0
- #define PRI_NSF_CALL_REDIRECTION_SERVICE 0xF7
-
-+/* ECMA 186 */
-+#define PRI_CC_CCNRREQUEST 27
-+#define PRI_CC_CANCEL 28
-+#define PRI_CC_CCBSREQUEST 40
-+
- typedef struct q931_call q931_call;
-
-+/* Connected line update source code */
-+enum PRI_CONNECTED_LINE_UPDATE_SOURCE {
-+ PRI_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN, /* Update for unknown reason (May be interpreted to mean from answer) */
-+ PRI_CONNECTED_LINE_UPDATE_SOURCE_ANSWER, /* Update from normal call answering */
-+ PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER, /* Update from call transfer(active) (Party has already answered) */
-+ PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING /* Update from call transfer(alerting) (Party has not answered yet) */
-+};
-+
-+/* Information needed to identify an endpoint in a call. */
-+struct pri_party_id {
-+ char number[256]; /* Subscriber phone number */
-+ char name[256]; /* Subscriber name */
-+ int number_type; /* Q.931 encoded "type of number" and "numbering plan identification" */
-+ int number_presentation; /* Q.931 encoded "presentation indicator" and "screening indicator" */
-+};
-+
-+/* Connected Line/Party information */
-+struct pri_party_connected_line {
-+ struct pri_party_id id; /* Connected party ID */
-+ int source; /* Information about the source of an update .
-+ * enum PRI_CONNECTED_LINE_UPDATE_SOURCE values
-+ * for Normal-Answer, Call-transfer */
-+};
-+
-+/* Redirecting Line information.
-+ * RDNIS (Redirecting Directory Number Information Service)
-+ * Where a call diversion or transfer was invoked. */
-+struct pri_party_redirecting {
-+ struct pri_party_id from; /* Who is redirecting the call (Sent to the party the call is redirected toward) */
-+ struct pri_party_id to; /* Call is redirecting to a new party (Sent to the caller) */
-+ int count; /* Number of times the call was redirected */
-+ int reason; /* Redirection reasons */
-+};
-+
-+/* Structures for qsig_cc_facilities */
-+struct qsig_cc_extension {
-+ int cc_extension_tag;
-+ char extension[256];
-+};
-+
-+struct qsig_cc_optional_arg {
-+ char number_A[256];
-+ char number_B[256];
-+ int service;
-+ struct qsig_cc_extension cc_extension;
-+};
-+
-+struct qsig_cc_request_res {
-+ int no_path_reservation;
-+ int retain_service;
-+ struct qsig_cc_extension cc_extension;
-+};
-+
-+/* Command derived from Facility */
-+#define CMD_REDIRECTING 1
-+#define CMD_CONNECTEDLINE 2
-+#define CMD_CC_CCBSREQUEST_RR 3
-+#define CMD_CC_CCNRREQUEST_RR 4
-+#define CMD_CC_CANCEL_INV 5
-+#define CMD_CC_EXECPOSIBLE_INV 6
-+#define CMD_CC_RINGOUT_INV 7
-+#define CMD_CC_SUSPEND_INV 8
-+#define CMD_CC_ERROR 9
-+
-+#define CCERROR_UNSPECIFIED 1008
-+#define CCERROR_REMOTE_USER_BUSY_AGAIN 1012
-+#define CCERROR_FAILURE_TO_MATCH 1013
-+
-+struct cmd_connectedline {
-+ struct pri_party_connected_line connected;
-+};
-+
-+struct cmd_redirecting {
-+ struct pri_party_redirecting redirecting;
-+};
-+
-+struct cmd_cc_ccbs_rr {
-+ struct qsig_cc_request_res cc_request_res;
-+};
-+
-+struct cmd_cc_ccnr_rr {
-+ struct qsig_cc_request_res cc_request_res;
-+};
-+
-+struct cmd_cc_cancel_inv {
-+ struct qsig_cc_optional_arg cc_optional_arg;
-+};
-+
-+struct cmd_cc_execposible_inv {
-+ struct qsig_cc_optional_arg cc_optional_arg;
-+};
-+
-+struct cmd_cc_suspend_inv {
-+ struct qsig_cc_extension cc_extension;
-+};
-+
-+struct cmd_cc_ringout_inv {
-+ struct qsig_cc_extension cc_extension;
-+};
-+
-+struct cmd_cc_error {
-+ int error_value;
-+};
-+
-+struct subcommand {
-+ int cmd;
-+ union {
-+ struct cmd_connectedline connectedline;
-+ struct cmd_redirecting redirecting;
-+ struct cmd_cc_ccbs_rr cc_ccbs_rr;
-+ struct cmd_cc_ccnr_rr cc_ccnr_rr;
-+ struct cmd_cc_cancel_inv cc_cancel_inv;
-+ struct cmd_cc_execposible_inv cc_execposible_inv;
-+ struct cmd_cc_suspend_inv cc_suspend_inv;
-+ struct cmd_cc_ringout_inv cc_ringout_inv;
-+ struct cmd_cc_error cc_error;
-+ };
-+};
-+
-+/* Max number of subcommands per event message */
-+#define MAX_SUBCOMMANDS 4
-+
-+struct subcommands {
-+ int counter_subcmd;
-+ struct subcommand subcmd[MAX_SUBCOMMANDS];
-+};
-+
-+
- typedef struct pri_event_generic {
- /* Events with no additional information fall in this category */
- int e;
-@@ -328,6 +491,11 @@
- int progressmask;
- q931_call *call;
- char useruserinfo[260]; /* User->User info */
-+ char calledname[256];
-+ char callednum[256];
-+ int calledpres;
-+ int calledplan;
-+ struct subcommands subcmds;
- } pri_event_ringing;
-
- typedef struct pri_event_answer {
-@@ -338,6 +506,12 @@
- int progressmask;
- q931_call *call;
- char useruserinfo[260]; /* User->User info */
-+ char connectednum[256];
-+ char connectedname[256];
-+ int connectedpres;
-+ int connectedplan;
-+ int source;
-+ struct subcommands subcmds;
- } pri_event_answer;
-
- typedef struct pri_event_facname {
-@@ -351,6 +525,14 @@
- int callingplan; /* Dialing plan of Calling entity */
- } pri_event_facname;
-
-+struct pri_event_facility {
-+ int e;
-+ int channel;
-+ int cref;
-+ q931_call *call;
-+ struct subcommands subcmds;
-+};
-+
- #define PRI_CALLINGPLANANI
- #define PRI_CALLINGPLANRDNIS
- typedef struct pri_event_ring {
-@@ -383,6 +565,9 @@
- char origcallednum[256];
- int callingplanorigcalled; /* Dialing plan of Originally Called Number */
- int origredirectingreason;
-+ int redirectingpres;
-+ int redirectingcount;
-+ struct subcommands subcmds;
- } pri_event_ring;
-
- typedef struct pri_event_hangup {
-@@ -393,6 +578,7 @@
- q931_call *call; /* Opaque call pointer */
- long aoc_units; /* Advise of Charge number of charged units */
- char useruserinfo[260]; /* User->User info */
-+ struct subcommands subcmds;
- } pri_event_hangup;
-
- typedef struct pri_event_restart_ack {
-@@ -445,6 +631,7 @@
- pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */
- pri_event_notify notify; /* Notification */
- pri_event_keypad_digit digit; /* Digits that come during a call */
-+ struct pri_event_facility facility;
- } pri_event;
-
- struct pri;
-@@ -531,6 +718,12 @@
- Set non-isdn to non-zero if you are not connecting to ISDN equipment */
- int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
-
-+/* Give connected line information to a call */
-+int pri_connected_line_update(struct pri *pri, q931_call *call, struct pri_party_connected_line *connected);
-+
-+/* Give redirection information to a call */
-+int pri_redirecting_update(struct pri *pri, q931_call *call, struct pri_party_redirecting *redirecting);
-+
- /* Set CRV reference for GR-303 calls */
-
-
-@@ -558,7 +751,12 @@
-
- /* Create a new call */
- q931_call *pri_new_call(struct pri *pri);
-+q931_call *pri_new_nochannel_call(struct pri *pri, int *cr);
-
-+q931_call *pri_find_call(struct pri *pri, int cr);
-+
-+void pri_call_set_cc_operation(q931_call *call, int cc_operation);
-+
- /* Retrieve CRV reference for GR-303 calls. Returns >0 on success. */
- int pri_get_crv(struct pri *pri, q931_call *call, int *callmode);
-
-@@ -584,6 +782,11 @@
- int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int complete);
- int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres);
- int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason);
-+void pri_sr_set_redirecting_name(struct pri_sr *sr, char *name);
-+
-+int pri_sr_set_ccringout(struct pri_sr *sr, int ccringout);
-+int pri_sr_set_ccbsnr(struct pri_sr *sr, int ccbsnr);
-+
- #define PRI_USER_USER_TX
- /* Set the user user field. Warning! don't send binary data accross this field */
- void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars);
-@@ -595,7 +798,10 @@
- /* Set a call has a call indpendent signalling connection (i.e. no bchan) */
- int pri_sr_set_connection_call_independent(struct pri_sr *req);
-
--/* Send an MWI indication to a remote location. If activate is non zero, activates, if zero, decativates */
-+/* Set a no channel call (i.e. QSIG-CCBS/CCNR) */
-+int pri_sr_set_no_channel_call(struct pri_sr *req);
-+
-+/* Send an MWI indication to a remote location. If activate is non zero, activates, if zero, deactivates */
- int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan);
-
- /* Send an MWI deactivate request to a remote location */
-@@ -698,6 +904,7 @@
- #define PRI_TIMER_TM20 28 /* maximum time avaiting XID response */
- #define PRI_TIMER_NM20 29 /* number of XID retransmits */
-
-+#define PRI_TIMER_CCBST2 30 /* maximum time on completion of CC Call */
- /* Get PRI version */
- const char *pri_get_version(void);
-
-Index: pri.c
-===================================================================
---- a/pri.c (.../tags/1.4.9) (revision 700)
-+++ b/pri.c (.../team/group/issue14292) (revision 700)
-@@ -166,6 +166,8 @@
- return PRI_TIMER_T321;
- else if (!strcasecmp(timer, "T322"))
- return PRI_TIMER_T322;
-+ else if (!strcasecmp(timer, "CCT2"))
-+ return PRI_TIMER_CCBST2;
- else
- return -1;
- }
-@@ -348,6 +350,8 @@
- return "Restart ACK";
- case PRI_EVENT_FACNAME:
- return "FacName";
-+ case PRI_EVENT_FACILITY:
-+ return "Facility";
- case PRI_EVENT_INFO_RECEIVED:
- return "Info Received";
- case PRI_EVENT_PROCEEDING:
-@@ -551,6 +555,131 @@
- return q931_connect(pri, call, channel, nonisdn);
- }
-
-+int pri_connected_line_update(struct pri *pri, q931_call *call, struct pri_party_connected_line *connected)
-+{
-+ if (!pri || !call)
-+ return -1;
-+
-+ libpri_copy_string(call->connectednum, connected->id.number, sizeof(call->connectednum));
-+ libpri_copy_string(call->connectedname, connected->id.name, sizeof(call->connectedname));
-+ call->connectedplan = connected->id.number_type;
-+ call->connectedpres = connected->id.number_presentation;
-+
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ switch (call->ourcallstate) {
-+ case Q931_CALL_STATE_ACTIVE:
-+ /* immediately send callTransferComplete APDU, callStatus=answered(0) */
-+ qsig_initiate_call_transfer_complete(pri, call, 0);
-+ break;
-+ case Q931_CALL_STATE_OVERLAP_RECEIVING:
-+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
-+ /* queue updates for next ALERTING */
-+ if (call->connectedname[0]) {
-+ /* queue connectedName to be send with next Q931_ALERTING */
-+ rose_called_name_encode(pri, call, Q931_ALERTING);
-+ }
-+
-+ if (call->divertedstate != DIVERTEDSTATE_NONE) {
-+ libpri_copy_string(call->divertedtonum, connected->id.number, sizeof(call->divertedtonum));
-+ libpri_copy_string(call->divertedtoname, connected->id.name, sizeof(call->divertedtoname));
-+ call->divertedtoplan = connected->id.number_type;
-+ call->divertedtopres = connected->id.number_presentation;
-+
-+ if ((call->divertedstate == DIVERTEDSTATE_DIVERTED) && call->divertedtonum[0]) {
-+ /* immediately send divertingLegInformation1 APDU */
-+ qsig_initiate_diverting_leg_information1(pri, call);
-+ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO1SEND;
-+ }
-+ if ((call->divertedstate == DIVERTEDSTATE_DIVLEGINFO1SEND) && call->divertedtoname[0]) {
-+ /* queue divertingLegInformation3 to be send with next Q931_ALERTING */
-+ rose_diverting_leg_information3_encode(pri, call, Q931_ALERTING);
-+ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO3SEND;
-+ }
-+ }
-+ break;
-+ case Q931_CALL_STATE_CALL_RECEIVED:
-+ /* queue updates for next CONNECT */
-+ if (call->connectedname[0] && ((call->divertedstate == DIVERTEDSTATE_NONE) || (call->divertedstate == DIVERTEDSTATE_DIVLEGINFO3SEND))) {
-+ /* queue connectedName to be send with next Q931_CONNECT */
-+ rose_connected_name_encode(pri, call, Q931_CONNECT);
-+ }
-+
-+ if (call->divertedstate != DIVERTEDSTATE_NONE) {
-+ libpri_copy_string(call->divertedtonum, connected->id.number, sizeof(call->divertedtonum));
-+ libpri_copy_string(call->divertedtoname, connected->id.name, sizeof(call->divertedtoname));
-+ call->divertedtoplan = connected->id.number_type;
-+ call->divertedtopres = connected->id.number_presentation;
-+
-+ if ((call->divertedstate == DIVERTEDSTATE_DIVERTED) && call->divertedtonum[0]) {
-+ /* queue divertingLegInformation1 to be send with next Q931_FACILITY */
-+ rose_diverting_leg_information1_encode(pri, call);
-+ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO1SEND;
-+
-+ if (call->divertedtoname[0]) {
-+ /* queue divertingLegInformation3 to be send with next Q931_FACILITY */
-+ rose_diverting_leg_information3_encode(pri, call, Q931_FACILITY);
-+ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO3SEND;
-+ }
-+
-+ /* immediately send Q931_FACILITY */
-+ if (q931_facility(pri, call)) {
-+ pri_message(pri, "Could not schedule facility message for divertingLegInfo1+3\n");
-+ }
-+ }
-+ if ((call->divertedstate == DIVERTEDSTATE_DIVLEGINFO1SEND) && call->divertedtoname[0]) {
-+ /* queue divertingLegInformation3 to be send with next Q931_CONNECT */
-+ rose_diverting_leg_information3_encode(pri, call, Q931_CONNECT);
-+ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO3SEND;
-+ }
-+ }
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+int pri_redirecting_update(struct pri *pri, q931_call *call, struct pri_party_redirecting *redirecting)
-+{
-+ if (!pri || !call)
-+ return -1;
-+
-+ libpri_copy_string(call->divertedtonum, redirecting->to.number, sizeof(call->divertedtonum));
-+ libpri_copy_string(call->divertedtoname, redirecting->to.name, sizeof(call->divertedtoname));
-+ call->divertedtoplan = redirecting->to.number_type;
-+ call->divertedtopres = redirecting->to.number_presentation;
-+ call->divertedtoreason = redirecting->reason;
-+
-+ if (pri->switchtype == PRI_SWITCH_QSIG) {
-+ switch (call->ourcallstate) {
-+ case Q931_CALL_STATE_ACTIVE:
-+ /* immediately send callTransferComplete APDU, callStatus=alerting(1) */
-+ qsig_initiate_call_transfer_complete(pri, call, 1);
-+ break;
-+ case Q931_CALL_STATE_OVERLAP_RECEIVING:
-+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
-+ call->divertedstate = DIVERTEDSTATE_DIVERTED;
-+
-+ if (call->divertedtonum[0]) {
-+ /* immediately send divertingLegInformation1 APDU */
-+ qsig_initiate_diverting_leg_information1(pri, call);
-+ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO1SEND;
-+ }
-+ if ((call->divertedstate == DIVERTEDSTATE_DIVLEGINFO1SEND) && call->divertedtoname[0]) {
-+ /* queue divertingLegInformation3 to be send with next Q931_ALERTING */
-+ rose_diverting_leg_information3_encode(pri, call, Q931_ALERTING);
-+ call->divertedstate = DIVERTEDSTATE_DIVLEGINFO3SEND;
-+ }
-+ break;
-+ default:
-+ pri_message(pri, "Redirecting update in state %d\n", call->ourcallstate);
-+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
- #if 0
- /* deprecated routines, use pri_hangup */
- int pri_release(struct pri *pri, q931_call *call, int cause)
-@@ -637,6 +766,17 @@
- return q931_new_call(pri);
- }
-
-+q931_call *pri_new_nochannel_call(struct pri *pri, int *cr)
-+{
-+ q931_call *call;
-+ if (!pri)
-+ return NULL;
-+ call = q931_new_call(pri);
-+ if (cr)
-+ *cr = call->cr;
-+ return call;
-+}
-+
- void pri_dump_event(struct pri *pri, pri_event *e)
- {
- if (!pri || !e)
-@@ -679,6 +819,15 @@
- return 0;
- }
-
-+int pri_sr_set_no_channel_call(struct pri_sr *req)
-+{
-+ if (!req)
-+ return -1;
-+
-+ req->nochannelsignalling = 1;
-+ return 0;
-+}
-+
- /* Don't call any other pri functions on this */
- int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called,
- int calledplan)
-@@ -829,6 +978,10 @@
- struct q921_frame *f;
- int q921outstanding = 0;
- #endif
-+ q931_call *cur, *prev;
-+ struct pri *master;
-+ int counter = 0;
-+
- if (!pri)
- return NULL;
-
-@@ -862,10 +1015,57 @@
- len += sprintf(buf + len, "T309 Timer: %d\n", pri->timers[PRI_TIMER_T309]);
- len += sprintf(buf + len, "T313 Timer: %d\n", pri->timers[PRI_TIMER_T313]);
- len += sprintf(buf + len, "N200 Counter: %d\n", pri->timers[PRI_TIMER_N200]);
-+ len += sprintf(buf + len, "CCT2 Timer: %d\n", pri->timers[PRI_TIMER_CCBST2]);
-+ /* Find the master - He has the call pool */
-+ if (pri->master)
-+ master = pri->master;
-+ else
-+ master = pri;
-
-+ cur = *master->callpool;
-+ prev = NULL;
-+ while(cur) {
-+ if (cur->cctimer2) {
-+ struct timeval tv;
-+ int time_ms_to_go, time_to_go_min, time_to_go_sec;
-+ gettimeofday(&tv, NULL);
-+ time_ms_to_go = (pri->pri_sched[cur->cctimer2].when.tv_sec - tv.tv_sec)*1000;
-+ time_to_go_min = time_ms_to_go/1000/60;
-+ time_to_go_sec = (time_ms_to_go-(time_to_go_min*60*1000))/1000;
-+
-+ len += sprintf(buf + len, "%d. Active Q.931 Call: %p cr=%d: (%dmin %dsec)\n",
-+ ++counter, cur, cur->cr,
-+ time_to_go_min, time_to_go_sec);
-+ } else {
-+ len += sprintf(buf + len, "%d. Active Q.931 Call: %p cr=%d\n", ++counter, cur, cur->cr);
-+ }
-+ cur = cur->next;
-+ }
-+
- return strdup(buf);
- }
-
-+q931_call *pri_find_call(struct pri *pri, int cr)
-+{
-+ q931_call *cur;
-+ struct pri *master;
-+
-+ /* Find the master - He has the call pool */
-+ if (pri->master)
-+ master = pri->master;
-+ else
-+ master = pri;
-+
-+ cur = *master->callpool;
-+ while(cur) {
-+ if (cur->cr == cr)
-+ return cur;
-+ cur = cur->next;
-+ }
-+
-+ return NULL;
-+}
-+
- int pri_get_crv(struct pri *pri, q931_call *call, int *callmode)
- {
- return q931_call_getcrv(pri, call, callmode);
-@@ -936,3 +1136,25 @@
- sr->redirectingreason = reason;
- return 0;
- }
-+
-+void pri_sr_set_redirecting_name(struct pri_sr *sr, char *name)
-+{
-+ sr->redirectingname = name;
-+}
-+
-+int pri_sr_set_ccringout(struct pri_sr *sr, int ccringout)
-+{
-+ sr->ccringout = ccringout;
-+ return 0;
-+}
-+
-+int pri_sr_set_ccbsnr(struct pri_sr *sr, int ccbsnr)
-+{
-+ sr->ccbsnr = ccbsnr;
-+ return 0;
-+}
-+
-+void pri_call_set_cc_operation(q931_call *call, int cc_operation)
-+{
-+ call->ccoperation = cc_operation;
-+}
-Index: pri_internal.h
-===================================================================
---- a/pri_internal.h (.../tags/1.4.9) (revision 700)
-+++ b/pri_internal.h (.../team/group/issue14292) (revision 700)
-@@ -36,6 +36,12 @@
- #define DBGHEAD __FILE__ ":%d %s: "
- #define DBGINFO __LINE__,__PRETTY_FUNCTION__
-
-+/* divertedstate */
-+#define DIVERTEDSTATE_NONE 0
-+#define DIVERTEDSTATE_DIVERTED 1
-+#define DIVERTEDSTATE_DIVLEGINFO1SEND 2
-+#define DIVERTEDSTATE_DIVLEGINFO3SEND 3
-+
- struct pri_sched {
- struct timeval when;
- void (*callback)(void *data);
-@@ -47,7 +53,7 @@
- enum q931_mode;
-
- /* No more than 128 scheduled events */
--#define MAX_SCHED 128
-+#define MAX_SCHED 128+256 /* 256 ccT2 timer events*/
-
- #define MAX_TIMERS 32
-
-@@ -142,13 +148,17 @@
- int calledplan;
- int userl1;
- int numcomplete;
-+ char *redirectingname;
- char *redirectingnum;
- int redirectingplan;
- int redirectingpres;
- int redirectingreason;
- int justsignalling;
-+ int nochannelsignalling;
-+ int ccbsnr;
- const char *useruserinfo;
- int transferable;
-+ int ccringout;
- };
-
- /* Internal switch types */
-@@ -202,6 +212,7 @@
-
- int sentchannel;
- int justsignalling; /* for a signalling-only connection */
-+ int nochannelsignalling;
-
- int progcode; /* Progress coding */
- int progloc; /* Progress Location */
-@@ -225,12 +236,19 @@
- char callernum[256];
- char callername[256];
-
-+ int ccoperation; /* QSIG_CCBSREQUEST/QSIG_CCNRREQUEST */
-+ int ccrequestresult;
-+ int cctimer2; /* Timer for QSIG-timer2 */
-+ /* QSIG cc infos (receive) */
-+ struct subcommands subcmds;
-+
- char keypad_digits[64]; /* Buffer for digits that come in KEYPAD_FACILITY */
-
- int ani2; /* ANI II */
-
- int calledplan;
- int nonisdn;
-+ char calledname[256];
- char callednum[256]; /* Called Number */
- int complete; /* no more digits coming */
- int newcall; /* if the received message has a new call reference value */
-@@ -241,6 +259,7 @@
- int redirectingplan;
- int redirectingpres;
- int redirectingreason;
-+ int redirectingcount;
- char redirectingnum[256]; /* Number of redirecting party */
- char redirectingname[256]; /* Name of redirecting party */
-
-@@ -251,6 +270,39 @@
- char origcalledname[256]; /* Original name of person being called */
- char origcallednum[256]; /* Orignal number of person being called */
-
-+ int connectedplan;
-+ int connectedpres;
-+ char connectednum[256];
-+ char connectedname[256];
-+
-+ /* divertingLegInformation1 */
-+ int divleginfo1activeflag;
-+ int divertedtoplan;
-+ int divertedtopres;
-+ int divertedtoreason;
-+ char divertedtonum[256];
-+ int divertedtocount;
-+
-+ /* divertingLegInformation3 */
-+ int divleginfo3activeflag;
-+ char divertedtoname[256];
-+ int divertedstate;
-+
-+ /* callTransferComplete */
-+ int ctcompleteflag;
-+ int ctcompletepres;
-+ int ctcompleteplan;
-+ char ctcompletenum[256];
-+ char ctcompletename[256];
-+ int ctcompletecallstatus;
-+
-+ /* callTransferActive */
-+ int ctactiveflag;
-+ int ctactivepres;
-+ int ctactiveplan;
-+ char ctactivenum[256];
-+ char ctactivename[256];
-+
- int useruserprotocoldisc;
- char useruserinfo[256];
- char callingsubaddr[256]; /* Calling parties sub address */
-Index: q921.c
-===================================================================
---- a/q921.c (.../tags/1.4.9) (revision 700)
-+++ b/q921.c (.../team/group/issue14292) (revision 700)
-@@ -268,12 +268,31 @@
- pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T203], t203_expire, pri);
- }
-
-+static void q921_send_queued_iframes(struct pri *pri)
-+{
-+ struct q921_frame *f;
-+
-+ f = pri->txqueue;
-+ while(f && (pri->windowlen < pri->window)) {
-+ if (!f->transmitted) {
-+ /* Send it now... */
-+ if (pri->debug & PRI_DEBUG_Q921_DUMP)
-+ pri_message(pri, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, pri->windowlen);
-+ f->transmitted++;
-+ pri->windowlen++;
-+ f->h.n_r = pri->v_r;
-+ f->h.p_f = 0;
-+ q921_transmit(pri, (q921_h *)(&f->h), f->len);
-+ }
-+ f = f->next;
-+ }
-+}
-+
- static pri_event *q921_ack_rx(struct pri *pri, int ack, int send_untransmitted_frames)
- {
- int x;
- int cnt=0;
- pri_event *ev;
-- struct q921_frame *f;
- /* Make sure the ACK was within our window */
- for (x=pri->v_a; (x != pri->v_s) && (x != ack); Q921_INC(x));
- if (x != ack) {
-@@ -309,20 +328,7 @@
- if (!pri->busy && send_untransmitted_frames) {
- pri->retrans = 0;
- /* Search for something to send */
-- f = pri->txqueue;
-- while(f && (pri->windowlen < pri->window)) {
-- if (!f->transmitted) {
-- /* Send it now... */
-- if (pri->debug & PRI_DEBUG_Q921_DUMP)
-- pri_message(pri, "-- Finally transmitting %d, since window opened up (%d)\n", f->h.n_s, pri->windowlen);
-- f->transmitted++;
-- pri->windowlen++;
-- f->h.n_r = pri->v_r;
-- f->h.p_f = 0;
-- q921_transmit(pri, (q921_h *)(&f->h), f->len);
-- }
-- f = f->next;
-- }
-+ q921_send_queued_iframes(pri);
- }
- if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "-- Waiting for acknowledge, restarting T200 counter\n");
-@@ -515,7 +521,7 @@
- pri->txqueue = f;
- /* Immediately transmit unless we're in a recovery state, or the window
- size is too big */
-- if (!pri->retrans && !pri->busy) {
-+ if ((pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) && (!pri->retrans && !pri->busy)) {
- if (pri->windowlen < pri->window) {
- pri->windowlen++;
- q921_transmit(pri, (q921_h *)(&f->h), f->len);
-@@ -532,9 +538,14 @@
- pri_schedule_del(pri, pri->t203_timer);
- pri->t203_timer = 0;
- }
-- if (pri->debug & PRI_DEBUG_Q921_DUMP)
-- pri_message(pri, "Starting T_200 timer\n");
-- reschedule_t200(pri);
-+
-+ /* Check this so that we don't try to send frames while multi frame mode is down */
-+ if (pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) {
-+ if (pri->debug & PRI_DEBUG_Q921_DUMP)
-+ pri_message(pri, "Starting T_200 timer\n");
-+
-+ reschedule_t200(pri);
-+ }
- } else {
- pri_error(pri, "!! Out of memory for Q.921 transmit\n");
- return -1;
-@@ -776,9 +787,6 @@
-
- static pri_event *q921_dchannel_up(struct pri *pri)
- {
-- /* Reset counters, etc */
-- q921_reset(pri);
--
- /* Stop any SABME retransmissions */
- if (pri->sabme_timer) {
- pri_schedule_del(pri, pri->sabme_timer);
-@@ -799,6 +807,8 @@
- /* Notify Layer 3 */
- q931_dl_indication(pri, PRI_EVENT_DCHAN_UP);
-
-+ q921_send_queued_iframes(pri);
-+
- /* Report event that D-Channel is now up */
- pri->ev.gen.e = PRI_EVENT_DCHAN_UP;
- return &pri->ev;
-Index: q931.c
-===================================================================
---- a/q931.c (.../tags/1.4.9) (revision 700)
-+++ b/q931.c (.../team/group/issue14292) (revision 700)
-@@ -362,6 +362,11 @@
- /* We are ready to transmit single IE only */
- if (order > 1)
- return 0;
-+
-+ if (call->nochannelsignalling) {
-+ ie->data[pos++] = 0xac;
-+ return pos + 2;
-+ }
-
- if (call->justsignalling) {
- ie->data[pos++] = 0xac; /* Read the standards docs to figure this out
-@@ -804,7 +809,13 @@
- ie->data[1] = 0x90;
- return 4;
- }
--
-+
-+ if (call->nochannelsignalling) {
-+ ie->data[0] = 0xa8;
-+ ie->data[1] = 0x80;
-+ return 4;
-+ }
-+
- if (call->justsignalling) {
- ie->data[0] = 0xa8;
- ie->data[1] = 0x80;
-@@ -992,12 +1003,45 @@
- prefix, ie->data[2] >> 7, redirection_reason2str(ie->data[2] & 0x7f), ie->data[2] & 0x7f);
- break;
- }
-- }
-- while(!(ie->data[i++]& 0x80));
-+ } while(!(ie->data[i++]& 0x80));
- q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
- pri_message(pri, " '%s' ]\n", cnum);
- }
-
-+static FUNC_RECV(receive_connected_number)
-+{
-+ int i = 0;
-+
-+ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by
-+ walking through all bytes until one with ext bit (8) set to 1 */
-+ do {
-+ switch(i) {
-+ case 0:
-+ call->connectedplan = ie->data[i] & 0x7f;
-+ break;
-+ case 1:
-+ call->connectedpres = ie->data[i] & 0x7f;
-+ break;
-+ }
-+ } while(!(ie->data[i++] & 0x80));
-+ q931_get_number((unsigned char *) call->connectednum, sizeof(call->connectednum), ie->data + i, ie->len - i);
-+
-+ return 0;
-+}
-+
-+static FUNC_SEND(transmit_connected_number)
-+{
-+ int datalen = strlen(call->connectednum);
-+ if (datalen > 0) {
-+ ie->data[0] = call->connectedplan;
-+ ie->data[1] = 0x80 | call->connectedpres;
-+ memcpy(ie->data + 2, call->connectednum, strlen(call->connectednum));
-+ return datalen + 4;
-+ }
-+
-+ return 0;
-+}
-+
- static FUNC_DUMP(dump_connected_number)
- {
- unsigned char cnum[256];
-@@ -1015,8 +1059,7 @@
- prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f);
- break;
- }
-- }
-- while(!(ie->data[i++]& 0x80));
-+ } while(!(ie->data[i++]& 0x80));
- q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i);
- pri_message(pri, " '%s' ]\n", cnum);
- }
-@@ -1040,8 +1083,7 @@
- call->redirectingreason = ie->data[i] & 0x0f;
- break;
- }
-- }
-- while(!(ie->data[i++] & 0x80));
-+ } while(!(ie->data[i++] & 0x80));
- q931_get_number((unsigned char *) call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i);
- return 0;
- }
-@@ -2183,7 +2225,7 @@
- { 1, Q931_IE_CALL_STATUS, "Call Status" },
- { 1, Q931_IE_CHANGE_STATUS, "Change Status" },
- { 1, Q931_IE_CONNECTED_ADDR, "Connected Number", dump_connected_number },
-- { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number },
-+ { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number, receive_connected_number, transmit_connected_number },
- { 1, Q931_IE_ORIGINAL_CALLED_NUMBER, "Original Called Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number },
- { 1, Q931_IE_USER_USER_FACILITY, "User-User Facility" },
- { 1, Q931_IE_UPDATE, "Update" },
-@@ -2478,8 +2520,7 @@
- maxlen -= res;
- iet = (q931_ie *)((char *)iet + res);
- }
-- }
-- while (res > 0 && order < ies_count);
-+ } while (res > 0 && order < ies_count);
- if (have_shift && total_res) {
- if (Q931_IE_CODESET(ies[x].ie))
- *codeset = Q931_IE_CODESET(ies[x].ie);
-@@ -2820,9 +2861,9 @@
- return send_message(pri, c, Q931_CALL_PROCEEDING, call_proceeding_ies);
- }
- #ifndef ALERTING_NO_PROGRESS
--static int alerting_ies[] = { Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, -1 };
-+static int alerting_ies[] = { Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, Q931_IE_FACILITY, -1 };
- #else
--static int alerting_ies[] = { -1 };
-+static int alerting_ies[] = { Q931_IE_FACILITY, -1 };
- #endif
-
- int q931_alerting(struct pri *pri, q931_call *c, int channel, int info)
-@@ -2841,7 +2882,7 @@
- return send_message(pri, c, Q931_ALERTING, alerting_ies);
- }
-
--static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 };
-+static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, Q931_IE_CONNECTED_NUM, Q931_IE_FACILITY, -1 };
-
- int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn)
- {
-@@ -2923,6 +2964,18 @@
- q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);
- }
-
-+static void pri_cctimer2_timeout(void *data)
-+{
-+ int cause = 16;
-+ struct q931_call *c = data;
-+ struct pri *pri = c->pri;
-+ if (pri->debug & PRI_DEBUG_Q931_STATE)
-+ pri_message(pri, "Timed out no-channel call\n");
-+ c->ccoperation = QSIG_CC_CANCEL;
-+ /* normal clear cause */
-+ q931_hangup(pri, c, cause);
-+}
-+
- int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn)
- {
- if (channel) {
-@@ -2954,7 +3007,7 @@
- return send_message(pri, c, Q931_CONNECT, connect_ies);
- }
-
--static int release_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 };
-+static int release_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, Q931_IE_FACILITY, -1 };
-
- int q931_release(struct pri *pri, q931_call *c, int cause)
- {
-@@ -3002,7 +3055,7 @@
- return send_message(pri, c, Q931_RESTART, restart_ies);
- }
-
--static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 };
-+static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, Q931_IE_FACILITY, -1 };
-
- int q931_disconnect(struct pri *pri, q931_call *c, int cause)
- {
-@@ -3030,6 +3083,8 @@
-
- static int cis_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLED_PARTY_NUMBER, -1 };
-
-+static int nochannel_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_SENDING_COMPLETE, -1 };
-+
- int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req)
- {
- int res;
-@@ -3055,6 +3110,7 @@
- c->nonisdn = req->nonisdn;
- c->newcall = 0;
- c->justsignalling = req->justsignalling;
-+ c->nochannelsignalling = req->nochannelsignalling;
- c->complete = req->numcomplete;
- if (req->exclusive)
- c->chanflags = FLAG_EXCLUSIVE;
-@@ -3082,6 +3138,10 @@
- }
- if (req->redirectingnum) {
- libpri_copy_string(c->redirectingnum, req->redirectingnum, sizeof(c->redirectingnum));
-+ if (req->redirectingname)
-+ libpri_copy_string(c->redirectingname, req->redirectingname, sizeof(c->redirectingname));
-+ else
-+ c->redirectingname[0] = '\0';
- c->redirectingplan = req->redirectingplan;
- if ((pri->switchtype == PRI_SWITCH_DMS100) ||
- (pri->switchtype == PRI_SWITCH_ATT4ESS)) {
-@@ -3092,6 +3152,7 @@
- c->redirectingpres = req->redirectingpres;
- c->redirectingreason = req->redirectingreason;
- } else {
-+ c->redirectingname[0] = '\0';
- c->redirectingnum[0] = '\0';
- c->redirectingplan = PRI_UNKNOWN;
- c->redirectingpres = PRES_NUMBER_NOT_AVAILABLE;
-@@ -3113,12 +3174,19 @@
- else
- c->progressmask = 0;
-
-+ if (req->ccringout)
-+ c->ccoperation = QSIG_CC_RINGOUT;
-+ if (req->ccbsnr)
-+ c->ccoperation = req->ccbsnr;
-+
- pri_call_add_standard_apdus(pri, c);
-
- if (pri->subchannel && !pri->bri)
- res = send_message(pri, c, Q931_SETUP, gr303_setup_ies);
- else if (c->justsignalling)
- res = send_message(pri, c, Q931_SETUP, cis_setup_ies);
-+ else if (c->nochannelsignalling)
-+ res = send_message(pri, c, Q931_SETUP, nochannel_setup_ies);
- else
- res = send_message(pri, c, Q931_SETUP, setup_ies);
- if (!res) {
-@@ -3132,7 +3200,7 @@
-
- }
-
--static int release_complete_ies[] = { Q931_IE_USER_USER, -1 };
-+static int release_complete_ies[] = { Q931_IE_USER_USER, Q931_IE_FACILITY, -1 };
-
- static int q931_release_complete(struct pri *pri, q931_call *c, int cause)
- {
-@@ -3187,6 +3255,18 @@
- /* We'll send RELEASE with these causes */
- disconnect = 0;
- }
-+ if (c->nochannelsignalling) {
-+ if (c->ccoperation == QSIG_CC_CANCEL) {
-+ add_qsigCcInv_facility_ie(pri, c, Q931_RELEASE);
-+ }
-+ if (c->cctimer2) {
-+ pri_schedule_del(pri, c->cctimer2);
-+ c->cctimer2 = 0;
-+ pri_message(pri, "NEW_HANGUP DEBUG: stop CC-Timer2\n");
-+ }
-+ disconnect = 0;
-+ }
-+
- /* All other causes we send with DISCONNECT */
- switch(c->ourcallstate) {
- case Q931_CALL_STATE_NULL:
-@@ -3227,6 +3307,10 @@
- break;
- case Q931_CALL_STATE_ACTIVE:
- /* received CONNECT */
-+ if (c->nochannelsignalling) {
-+ q931_release(pri,c,cause);
-+ break;
-+ }
- q931_disconnect(pri,c,cause);
- break;
- case Q931_CALL_STATE_DISCONNECT_REQUEST:
-@@ -3260,6 +3344,132 @@
- return 0;
- }
-
-+static void clr_subcommands(struct subcommands *sub)
-+{
-+ sub->counter_subcmd = 0;
-+}
-+
-+static struct subcommand *get_ptr_subcommand(struct subcommands *sub)
-+{
-+ if (sub->counter_subcmd < MAX_SUBCOMMANDS) {
-+ int count = sub->counter_subcmd;
-+ sub->counter_subcmd++;
-+ return &sub->subcmd[count];
-+ }
-+
-+ return NULL;
-+}
-+
-+static struct subcommand *get_ptr_q931_subcommand_by_index(struct subcommands *sub, int index)
-+{
-+ if (index < MAX_SUBCOMMANDS) {
-+ sub->counter_subcmd--;
-+ return &sub->subcmd[index];
-+ }
-+
-+ return NULL;
-+}
-+
-+static int q931_facilities2eventfacilities(struct pri *pri, q931_call *c, struct subcommands *subcmds)
-+{
-+ int facilitypos;
-+ int facility_number;
-+ struct subcommand *c_subcmd;
-+ struct subcommand *e_subcmd;
-+
-+ if (c->subcmds.counter_subcmd) {
-+ facility_number = c->subcmds.counter_subcmd;
-+
-+ for (facilitypos = 0; facilitypos < facility_number; facilitypos++) {
-+ c->subcmds.counter_subcmd--;
-+ c_subcmd = get_ptr_q931_subcommand_by_index(&c->subcmds, facilitypos);
-+ e_subcmd = get_ptr_subcommand(subcmds);
-+ if (c_subcmd && e_subcmd) {
-+ switch (c_subcmd->cmd) {
-+ case CMD_CC_CCBSREQUEST_RR:
-+ e_subcmd->cmd = c_subcmd->cmd;
-+ memcpy(&c_subcmd->cc_ccbs_rr, &e_subcmd->cc_ccbs_rr, sizeof(c_subcmd->cc_ccbs_rr));
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "facility(QSIG_CC_CCBSREQUEST) (%d/%d)\n",
-+ e_subcmd->cc_ccbs_rr.cc_request_res.no_path_reservation,
-+ e_subcmd->cc_ccbs_rr.cc_request_res.retain_service);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd);
-+ c->ccrequestresult = 1;
-+ break;
-+ case CMD_CC_CCNRREQUEST_RR:
-+ e_subcmd->cmd = c_subcmd->cmd;
-+ memcpy(&c_subcmd->cc_ccnr_rr, &e_subcmd->cc_ccnr_rr, sizeof(c_subcmd->cc_ccnr_rr));
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "facility(QSIG_CC_CCNRREQUEST) (%d/%d)\n",
-+ e_subcmd->cc_ccnr_rr.cc_request_res.no_path_reservation,
-+ e_subcmd->cc_ccnr_rr.cc_request_res.retain_service);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd);
-+ c->ccrequestresult = 1;
-+ break;
-+ case CMD_CC_CANCEL_INV:
-+ e_subcmd->cmd = c_subcmd->cmd;
-+ memcpy(&c_subcmd->cc_cancel_inv, &e_subcmd->cc_cancel_inv, sizeof(c_subcmd->cc_cancel_inv));
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "facility(QSIG_CC_CANCEL) (%s/%s)\n",
-+ e_subcmd->cc_cancel_inv.cc_optional_arg.number_A,
-+ e_subcmd->cc_cancel_inv.cc_optional_arg.number_B);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd);
-+ break;
-+ case CMD_CC_EXECPOSIBLE_INV:
-+ e_subcmd->cmd = c_subcmd->cmd;
-+ memcpy(&c_subcmd->cc_execposible_inv, &e_subcmd->cc_execposible_inv, sizeof(c_subcmd->cc_execposible_inv));
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "facility(QSIG_CC_EXECPOSIBLE) (%s/%s)\n",
-+ e_subcmd->cc_execposible_inv.cc_optional_arg.number_A,
-+ e_subcmd->cc_execposible_inv.cc_optional_arg.number_B);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd);
-+ break;
-+ case CMD_CC_RINGOUT_INV:
-+ e_subcmd->cmd = c_subcmd->cmd;
-+ memcpy(&c_subcmd->cc_ringout_inv, &e_subcmd->cc_ringout_inv, sizeof(c_subcmd->cc_ringout_inv));
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "facility(QSIG_CC_RINGOUT) (%d)\n",
-+ e_subcmd->cc_ringout_inv.cc_extension.cc_extension_tag);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd);
-+ break;
-+ case CMD_CC_SUSPEND_INV:
-+ e_subcmd->cmd = c_subcmd->cmd;
-+ memcpy(&c_subcmd->cc_suspend_inv, &e_subcmd->cc_suspend_inv, sizeof(c_subcmd->cc_suspend_inv));
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "facility(QSIG_CC_SUSPEND) (%d)\n",
-+ e_subcmd->cc_suspend_inv.cc_extension.cc_extension_tag);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd);
-+ break;
-+ case CMD_CC_ERROR:
-+ e_subcmd->cmd = c_subcmd->cmd;
-+ memcpy(&c_subcmd->cc_error, &e_subcmd->cc_error, sizeof(c_subcmd->cc_error));
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "facility(QSIG_CC_ERROR) (%d)\n",
-+ e_subcmd->cc_error.error_value);
-+ if (pri->debug & PRI_DEBUG_APDU)
-+ pri_message(pri, "counter_subcmd(%d)\n", subcmds->counter_subcmd);
-+ break;
-+ default:
-+ pri_error(pri, "Don't know how to handle Facility subcmd %d\n", c_subcmd->cmd);
-+ break;
-+ }
-+ }
-+ }
-+#if 0
-+ } else {
-+ pri_message(pri, "No facilities specified\n");
-+#endif
-+ }
-+ return 0;
-+}
-+
-+
- int q931_receive(struct pri *pri, q931_h *h, int len)
- {
- q931_mh *mh;
-@@ -3312,6 +3522,7 @@
- break;
- case Q931_FACILITY:
- c->callername[0] = '\0';
-+ c->subcmds.counter_subcmd = 0;
- break;
- case Q931_SETUP:
- if (pri->debug & PRI_DEBUG_Q931_STATE)
-@@ -3339,6 +3550,7 @@
- c->redirectingplan = -1;
- c->redirectingpres = -1;
- c->redirectingreason = -1;
-+ c->redirectingcount = 0;
- c->origcalledplan = -1;
- c->origcalledpres = -1;
- c->origredirectingreason = -1;
-@@ -3346,6 +3558,29 @@
- c->origcallednum[0] = '\0';
- c->redirectingname[0] = '\0';
- c->origcalledname[0] = '\0';
-+ c->connectedplan = -1;
-+ c->connectedpres = -1;
-+ c->connectednum[0] = '\0';
-+ c->connectedname[0] = '\0';
-+ c->divleginfo1activeflag = 0;
-+ c->divertedtocount = 0;
-+ c->divertedtoplan = -1;
-+ c->divertedtopres = -1;
-+ c->divertedtoreason = -1;
-+ c->divertedtonum[0] = '\0';
-+ c->divleginfo3activeflag = 0;
-+ c->divertedtoname[0] = '\0';
-+ c->divertedstate = DIVERTEDSTATE_NONE;
-+ c->ctcompleteflag = 0;
-+ c->ctcompleteplan = -1;
-+ c->ctcompletepres = -1;
-+ c->ctcompletenum[0] = '\0';
-+ c->ctcompletename[0] = '\0';
-+ c->ctactiveflag = 0;
-+ c->ctactiveplan = -1;
-+ c->ctactivepres = -1;
-+ c->ctactivenum[0] = '\0';
-+ c->ctactivename[0] = '\0';
- c->useruserprotocoldisc = -1;
- c->useruserinfo[0] = '\0';
- c->complete = 0;
-@@ -3353,7 +3588,9 @@
- c->aoc_units = -1;
- /* Fall through */
- case Q931_CONNECT:
-+ c->ccrequestresult = 0;
- case Q931_ALERTING:
-+ c->subcmds.counter_subcmd = 0;
- case Q931_PROGRESS:
- c->useruserinfo[0] = '\0';
- c->cause = -1;
-@@ -3369,6 +3606,7 @@
- break;
- case Q931_RELEASE:
- case Q931_DISCONNECT:
-+ c->subcmds.counter_subcmd = 0;
- c->cause = -1;
- c->causecode = -1;
- c->causeloc = -1;
-@@ -3383,6 +3621,7 @@
- pri_schedule_del(pri, c->retranstimer);
- c->retranstimer = 0;
- c->useruserinfo[0] = '\0';
-+ c->subcmds.counter_subcmd = 0;
- /* Fall through */
- case Q931_STATUS:
- c->cause = -1;
-@@ -3539,6 +3778,9 @@
- if (!c->newcall) {
- break;
- }
-+
-+ clr_subcommands(&pri->ev.ring.subcmds);
-+
- if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN)
- c->nonisdn = 1;
- c->newcall = 0;
-@@ -3570,7 +3812,9 @@
- libpri_copy_string(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname));
- libpri_copy_string(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo));
- c->useruserinfo[0] = '\0';
-+ pri->ev.ring.redirectingpres = c->redirectingpres;
- pri->ev.ring.redirectingreason = c->redirectingreason;
-+ pri->ev.ring.redirectingcount = c->redirectingcount;
- pri->ev.ring.origredirectingreason = c->origredirectingreason;
- pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE);
- pri->ev.ring.cref = c->cr;
-@@ -3578,15 +3822,21 @@
- pri->ev.ring.layer1 = c->userl1;
- pri->ev.ring.complete = c->complete;
- pri->ev.ring.ctype = c->transcapability;
-- pri->ev.ring.redirectingreason = c->redirectingreason;
- pri->ev.ring.progress = c->progress;
- pri->ev.ring.progressmask = c->progressmask;
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "Sending ring event (%d) nochannelsignalling (%d) facility_number (%d)\n",
-+ pri->ev.ring.cref, c->nochannelsignalling, pri->ev.ring.subcmds.counter_subcmd);
-+ }
-+ q931_facilities2eventfacilities(pri, c, &pri->ev.ring.subcmds);
- return Q931_RES_HAVEEVENT;
- case Q931_ALERTING:
- if (c->newcall) {
- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
- break;
- }
-+ clr_subcommands(&pri->ev.ringing.subcmds);
-+
- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_DELIVERED);
- c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED;
- pri->ev.e = PRI_EVENT_RINGING;
-@@ -3595,8 +3845,26 @@
- pri->ev.ringing.call = c;
- pri->ev.ringing.progress = c->progress;
- pri->ev.ringing.progressmask = c->progressmask;
-+
-+ if (c->divleginfo3activeflag) {
-+ c->divleginfo3activeflag = 0;
-+ libpri_copy_string(pri->ev.ringing.calledname, c->divertedtoname, sizeof(pri->ev.ringing.calledname));
-+ libpri_copy_string(pri->ev.ringing.callednum, (c->divertedtonum[0]) ? c->divertedtonum : c->callednum, sizeof(pri->ev.ringing.callednum));
-+ pri->ev.ringing.calledpres = c->divertedtopres;
-+ pri->ev.ringing.calledplan = c->divertedtoplan;
-+ } else {
-+ libpri_copy_string(pri->ev.ringing.calledname, c->calledname, sizeof(pri->ev.ringing.calledname));
-+ libpri_copy_string(pri->ev.ringing.callednum, (c->divertedtonum[0]) ? c->divertedtonum : c->callednum, sizeof(pri->ev.ringing.callednum));
-+ pri->ev.ringing.calledpres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
-+ pri->ev.ringing.calledplan = c->calledplan;
-+ }
- libpri_copy_string(pri->ev.ringing.useruserinfo, c->useruserinfo, sizeof(pri->ev.ringing.useruserinfo));
- c->useruserinfo[0] = '\0';
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "Sending ringing event (%d) nochannelsignalling (%d) facility_number (%d)\n",
-+ pri->ev.ringing.cref, c->nochannelsignalling, pri->ev.ringing.subcmds.counter_subcmd);
-+ }
-+ q931_facilities2eventfacilities(pri, c, &pri->ev.ringing.subcmds);
-
- cur = c->apdus;
- while (cur) {
-@@ -3617,6 +3885,8 @@
- q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE);
- break;
- }
-+ clr_subcommands(&pri->ev.answer.subcmds);
-+
- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE);
- c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
- pri->ev.e = PRI_EVENT_ANSWER;
-@@ -3625,31 +3895,166 @@
- pri->ev.answer.call = c;
- pri->ev.answer.progress = c->progress;
- pri->ev.answer.progressmask = c->progressmask;
-+ libpri_copy_string(pri->ev.answer.connectednum, c->connectednum, sizeof(pri->ev.answer.connectednum));
-+ libpri_copy_string(pri->ev.answer.connectedname, c->connectedname, sizeof(pri->ev.answer.connectedname));
-+ pri->ev.answer.connectedpres = c->connectedpres;
-+ pri->ev.answer.connectedplan = c->connectedplan;
-+ pri->ev.answer.source = PRI_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
- libpri_copy_string(pri->ev.answer.useruserinfo, c->useruserinfo, sizeof(pri->ev.answer.useruserinfo));
- c->useruserinfo[0] = '\0';
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "Sending answer event (%d) nochannelsignalling (%d) facility_number (%d)\n",
-+ pri->ev.answer.cref, c->nochannelsignalling, pri->ev.answer.subcmds.counter_subcmd);
-+ }
-+ q931_facilities2eventfacilities(pri, c, &pri->ev.answer.subcmds);
- q931_connect_acknowledge(pri, c);
-+ if (c->nochannelsignalling) {
-+ if (c->ccrequestresult) {
-+ pri_message(pri, "Q931_CONNECT: start CC-Timer2\n");
-+ c->cctimer2 = pri_schedule_event(pri, pri->timers[PRI_TIMER_CCBST2], pri_cctimer2_timeout, c);
-+ }
-+ return Q931_RES_HAVEEVENT;
-+ }
- if (c->justsignalling) { /* Make sure WE release when we initiatie a signalling only connection */
- q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING);
- break;
- } else
- return Q931_RES_HAVEEVENT;
- case Q931_FACILITY:
-- if (c->newcall) {
-- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
-- break;
-+ {
-+ int haveevent = 0;
-+ clr_subcommands(&pri->ev.facility.subcmds);
-+
-+ if (c->newcall) {
-+ q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
-+ break;
-+ }
-+ if (c->subcmds.counter_subcmd) {
-+ pri->ev.e = PRI_EVENT_FACILITY;
-+ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
-+ pri->ev.facility.cref = c->cr;
-+ pri->ev.facility.call = c;
-+
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "Sending facility event (%d) nochannelsignalling (%d) facility_number (%d)\n",
-+ pri->ev.facility.cref, c->nochannelsignalling, pri->ev.facility.subcmds.counter_subcmd);
-+ }
-+ q931_facilities2eventfacilities(pri, c, &pri->ev.facility.subcmds);
-+ haveevent = 1;
-+ }
-+ if (c->ctcompleteflag) {
-+ c->ctcompleteflag = 0;
-+
-+ if (c->ctcompletecallstatus == 0) {
-+ /* answered(0) */
-+ struct subcommand *subcmd;
-+
-+ pri_message(pri, "Got CT-Complete, callStatus = answered(0)\n");
-+ pri->ev.e = PRI_EVENT_FACILITY;
-+ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
-+ pri->ev.facility.call = c;
-+
-+ subcmd = get_ptr_subcommand(&pri->ev.facility.subcmds);
-+ if (subcmd) {
-+ struct cmd_connectedline *cmdcl = &subcmd->connectedline;
-+
-+ subcmd->cmd = CMD_CONNECTEDLINE;
-+ libpri_copy_string(cmdcl->connected.id.number, c->ctcompletenum, sizeof(cmdcl->connected.id.number));
-+ libpri_copy_string(cmdcl->connected.id.name, c->ctcompletename, sizeof(cmdcl->connected.id.name));
-+ cmdcl->connected.id.number_type = c->ctcompleteplan;
-+ cmdcl->connected.id.number_presentation = c->ctcompletepres;
-+ cmdcl->connected.source = PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
-+ haveevent = 1;
-+ pri_message(pri, "CT-Complete, sending facility/CMD_CONNECTEDLINE (%s/%s)\n", cmdcl->connected.id.name, cmdcl->connected.id.number);
-+ }
-+ } else if (c->ctcompletecallstatus == 1) {
-+ /* alerting(1) */
-+ struct subcommand *subcmd;
-+
-+ pri_message(pri, "Got CT-Complete, callStatus = alerting(1)\n");
-+ pri->ev.e = PRI_EVENT_FACILITY;
-+ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
-+ pri->ev.facility.call = c;
-+
-+ subcmd = get_ptr_subcommand(&pri->ev.facility.subcmds);
-+ if (subcmd) {
-+ struct cmd_redirecting *cmdr = &subcmd->redirecting;
-+
-+ subcmd->cmd = CMD_REDIRECTING;
-+ libpri_copy_string(cmdr->redirecting.from.number, c->connectednum, sizeof(cmdr->redirecting.from.number));
-+ libpri_copy_string(cmdr->redirecting.from.name, c->connectedname, sizeof(cmdr->redirecting.from.name));
-+ cmdr->redirecting.from.number_type = c->connectedplan;
-+ cmdr->redirecting.from.number_presentation = c->connectedpres;
-+ libpri_copy_string(cmdr->redirecting.to.number, c->ctcompletenum, sizeof(cmdr->redirecting.to.number));
-+ libpri_copy_string(cmdr->redirecting.to.name, c->ctcompletename, sizeof(cmdr->redirecting.to.name));
-+ cmdr->redirecting.to.number_type = c->ctcompleteplan;
-+ cmdr->redirecting.to.number_presentation = c->ctcompletepres;
-+ cmdr->redirecting.count = 0;
-+ cmdr->redirecting.reason = PRI_REDIR_UNKNOWN;
-+ haveevent = 1;
-+ pri_message(pri, "CT-Complete, sending facility/CMD_REDIRECTING (%s/%s)\n", cmdr->redirecting.to.name, cmdr->redirecting.to.number);
-+ }
-+ } else {
-+ pri_message(pri, "illegal value for callStatus=%d\n", c->ctcompletecallstatus);
-+ }
-+ } else if (c->ctactiveflag) {
-+ struct subcommand *subcmd;
-+
-+ c->ctactiveflag = 0;
-+
-+ pri_message(pri, "Got CT-Active\n");
-+ pri->ev.e = PRI_EVENT_FACILITY;
-+ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
-+ pri->ev.facility.call = c;
-+
-+ subcmd = get_ptr_subcommand(&pri->ev.facility.subcmds);
-+ if (subcmd) {
-+ struct cmd_connectedline *cmdcl = &subcmd->connectedline;
-+
-+ subcmd->cmd = CMD_CONNECTEDLINE;
-+ libpri_copy_string(cmdcl->connected.id.number, c->ctcompletenum, sizeof(cmdcl->connected.id.number));
-+ libpri_copy_string(cmdcl->connected.id.name, c->ctcompletename, sizeof(cmdcl->connected.id.name));
-+ cmdcl->connected.id.number_type = c->ctcompleteplan;
-+ cmdcl->connected.id.number_presentation = c->ctcompletepres;
-+ cmdcl->connected.source = PRI_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER;
-+ haveevent = 1;
-+ pri_message(pri, "CT-Active, sending facility CMD_CONNECTEDLINE (%s/%s)\n", cmdcl->connected.id.name, cmdcl->connected.id.number);
-+ }
-+ }
-+ else if (c->divleginfo1activeflag) {
-+ struct subcommand *subcmd;
-+
-+ c->divleginfo1activeflag = 0;
-+
-+ pri_message(pri, "Got DivertingLegInformation1\n");
-+ pri->ev.e = PRI_EVENT_FACILITY;
-+ pri->ev.facility.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
-+ pri->ev.facility.call = c;
-+
-+ subcmd = get_ptr_subcommand(&pri->ev.facility.subcmds);
-+ if (subcmd) {
-+ struct cmd_redirecting *cmdr = &subcmd->redirecting;
-+
-+ subcmd->cmd = CMD_REDIRECTING;
-+ libpri_copy_string(cmdr->redirecting.from.number, c->callednum, sizeof(cmdr->redirecting.from.number));
-+ cmdr->redirecting.from.name[0] = '\0';
-+ cmdr->redirecting.from.number_type = c->calledplan;
-+ cmdr->redirecting.from.number_presentation = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
-+ libpri_copy_string(cmdr->redirecting.to.number, c->divertedtonum, sizeof(cmdr->redirecting.to.number));
-+ cmdr->redirecting.to.name[0] = '\0';
-+ cmdr->redirecting.to.number_type = c->divertedtoplan;
-+ cmdr->redirecting.to.number_presentation = c->divertedtopres;
-+ cmdr->redirecting.count = c->divertedtocount;
-+ cmdr->redirecting.reason = c->divertedtoreason;
-+ haveevent = 1;
-+ pri_message(pri, "DivertingLegInformation1, sending facility/CMD_REDIRECTING (%s/%s)\n", cmdr->redirecting.to.name, cmdr->redirecting.to.number);
-+ }
-+ }
-+
-+ if (haveevent)
-+ return Q931_RES_HAVEEVENT;
- }
-- pri->ev.e = PRI_EVENT_FACNAME;
-- libpri_copy_string(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname));
-- libpri_copy_string(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingnum));
-- pri->ev.facname.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
-- pri->ev.facname.callingpres = c->callerpres;
-- pri->ev.facname.callingplan = c->callerplan;
-- pri->ev.facname.cref = c->cr;
-- pri->ev.facname.call = c;
--#if 0
-- pri_message(pri, "Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum);
--#endif
-- return Q931_RES_HAVEEVENT;
-+ break;
- case Q931_PROGRESS:
- if (missingmand) {
- q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING);
-@@ -3757,6 +4162,8 @@
- }
- break;
- case Q931_RELEASE_COMPLETE:
-+ clr_subcommands(&pri->ev.hangup.subcmds);
-+
- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL);
- c->peercallstate = Q931_CALL_STATE_NULL;
- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16);
-@@ -3766,6 +4173,11 @@
- pri->ev.hangup.aoc_units = c->aoc_units;
- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
- c->useruserinfo[0] = '\0';
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "Sending hangup event (%d) nochannelsignalling (%d) facility_number (%d)\n",
-+ pri->ev.hangup.cref, c->nochannelsignalling, pri->ev.hangup.subcmds.counter_subcmd);
-+ }
-+ q931_facilities2eventfacilities(pri, c, &pri->ev.hangup.subcmds);
- /* Free resources */
- if (c->alive) {
- pri->ev.e = PRI_EVENT_HANGUP;
-@@ -3783,6 +4195,8 @@
- q931_hangup(pri,c,c->cause);
- break;
- case Q931_RELEASE:
-+ clr_subcommands(&pri->ev.hangup.subcmds);
-+
- if (missingmand) {
- /* Force cause to be mandatory IE missing */
- c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
-@@ -3801,6 +4215,11 @@
- pri->ev.hangup.aoc_units = c->aoc_units;
- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
- c->useruserinfo[0] = '\0';
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "Sending hangup event (%d) nochannelsignalling (%d) facility_number (%d)\n",
-+ pri->ev.hangup.cref, c->nochannelsignalling, pri->ev.hangup.subcmds.counter_subcmd);
-+ }
-+ q931_facilities2eventfacilities(pri, c, &pri->ev.hangup.subcmds);
- /* Don't send release complete if they send us release
- while we sent it, assume a NULL state */
- if (c->newcall)
-@@ -3809,6 +4228,8 @@
- return Q931_RES_HAVEEVENT;
- break;
- case Q931_DISCONNECT:
-+ clr_subcommands(&pri->ev.hangup.subcmds);
-+
- if (missingmand) {
- /* Still let user call release */
- c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
-@@ -3835,6 +4256,11 @@
- pri->ev.hangup.aoc_units = c->aoc_units;
- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo));
- c->useruserinfo[0] = '\0';
-+ if (pri->debug & PRI_DEBUG_APDU) {
-+ pri_message(pri, "Sending hangup event (%d) nochannelsignalling (%d) facility_number (%d)\n",
-+ pri->ev.hangup.cref, c->nochannelsignalling, pri->ev.hangup.subcmds.counter_subcmd);
-+ }
-+ q931_facilities2eventfacilities(pri, c, &pri->ev.hangup.subcmds);
- if (c->alive)
- return Q931_RES_HAVEEVENT;
- else
-
-Property changes on: .
-___________________________________________________________________
-Added: automerge
- + *
-Added: automerge-propname
- + issue14292-integrated
-Added: svnmerge-integrated
- + /branches/1.4:1-688
-Added: automerge-email
- + rmudgett@digium.com
-Added: issue14292-integrated
- + /team/group/issue14068:1-699
-