diff options
author | Timo Teräs <timo.teras@iki.fi> | 2011-07-07 16:14:24 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2011-07-07 16:14:24 +0300 |
commit | 491adc1d879b67ff4095fd32eb376f9e580e97ad (patch) | |
tree | 45caf5b64a48186352e8fe7e502c9c9bd296750f /main | |
parent | 05a00bd3b1689298d2ad59c797d43424c18ea855 (diff) | |
download | aports-491adc1d879b67ff4095fd32eb376f9e580e97ad.tar.bz2 aports-491adc1d879b67ff4095fd32eb376f9e580e97ad.tar.xz |
main/libpri: upgrade to 1.4.12
* remove unneeded patches
Diffstat (limited to 'main')
-rw-r--r-- | main/libpri/APKBUILD | 7 | ||||
-rw-r--r-- | main/libpri/libpri-1.4-r1357.patch | 39961 | ||||
-rw-r--r-- | main/libpri/libpri-cflags.patch | 21 |
3 files changed, 4 insertions, 39985 deletions
diff --git a/main/libpri/APKBUILD b/main/libpri/APKBUILD index aec4f4683..fef96994f 100644 --- a/main/libpri/APKBUILD +++ b/main/libpri/APKBUILD @@ -1,8 +1,8 @@ # Contributor: Timo Teras <timo.teras@iki.fi> # Maintainer: Timo Teras <timo.teras@iki.fi> pkgname=libpri -pkgver=1.4.12_beta3 -_pkgver=1.4.12-beta3 +pkgver=1.4.12 +_pkgver=$pkgver pkgrel=0 pkgdesc="Primary Rate ISDN (PRI) library" url="http://www.asterisk.orig" @@ -30,4 +30,5 @@ package() { make LDCONFIG="echo" INSTALL_PREFIX="$pkgdir" install } -md5sums="9cbbaa009264b76af930529e8aae8cfd libpri-1.4.12-beta3.tar.gz" +md5sums="9de39b866f049cc20a4f431cc6245166 libpri-1.4.12.tar.gz +8df2ca48ce7db4f1a8604b0904bc9394 libpri-cflags.patch" diff --git a/main/libpri/libpri-1.4-r1357.patch b/main/libpri/libpri-1.4-r1357.patch deleted file mode 100644 index be827eebb..000000000 --- a/main/libpri/libpri-1.4-r1357.patch +++ /dev/null @@ -1,39961 +0,0 @@ -=================================================================== ---- 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, ¤cy_info->u.duration)); -+ break; -+ case 2: /* flatRateCurrency */ -+ ASN1_CALL(pos, rose_enc_qsig_AOC_FlatRateCurrency(ctrl, pos, end, -+ ASN1_CLASS_CONTEXT_SPECIFIC | 2, ¤cy_info->u.flat_rate)); -+ break; -+ case 3: /* volumeRateCurrency */ -+ ASN1_CALL(pos, rose_enc_qsig_AOC_VolumeRateCurrency(ctrl, pos, end, -+ ASN1_CLASS_CONTEXT_SPECIFIC | 3, ¤cy_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, -+ ¤cy_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, ¤cy_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, ¤cy_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, ¤cy_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, ¤cy_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, ¤cy_info->u.duration)); -+ break; -+ case 2: /* flatRateCurrency */ -+ ASN1_CALL(pos, rose_enc_etsi_AOC_FlatRateCurrency(ctrl, pos, end, -+ ASN1_CLASS_CONTEXT_SPECIFIC | 2, ¤cy_info->u.flat_rate)); -+ break; -+ case 3: /* volumeRateCurrency */ -+ ASN1_CALL(pos, rose_enc_etsi_AOC_VolumeRateCurrency(ctrl, pos, end, -+ ASN1_CLASS_CONTEXT_SPECIFIC | 3, ¤cy_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, -+ ¤cy_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, ¤cy_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, -+ ¤cy_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, ¤cy_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, ¤cy_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, ¤cy_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, ¤cy_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, ¤cy_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, ¤cy_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-cflags.patch b/main/libpri/libpri-cflags.patch deleted file mode 100644 index 7bf31c7ac..000000000 --- a/main/libpri/libpri-cflags.patch +++ /dev/null @@ -1,21 +0,0 @@ -Index: Makefile -=================================================================== ---- a/Makefile (revision 650) -+++ b/Makefile (working copy) -@@ -43,7 +43,7 @@ - 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) -+CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) - INSTALL_PREFIX=$(DESTDIR) - INSTALL_BASE=/usr - libdir?=$(INSTALL_BASE)/lib -@@ -102,7 +102,6 @@ - ifneq (${OSARCH},SunOS) - install -m 644 libpri.h $(INSTALL_PREFIX)$(INSTALL_BASE)/include - install -m 755 $(DYNAMIC_LIBRARY) $(INSTALL_PREFIX)$(libdir) -- if [ -x /usr/sbin/sestatus ] && ( /usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled"); then /sbin/restorecon -v $(INSTALL_PREFIX)$(libdir)/$(DYNAMIC_LIBRARY); fi - ( cd $(INSTALL_PREFIX)$(libdir) ; ln -sf libpri.so.$(SONAME) libpri.so) - install -m 644 $(STATIC_LIBRARY) $(INSTALL_PREFIX)$(libdir) - if test $$(id -u) = 0; then $(LDCONFIG) $(LDCONFIG_FLAGS) $(INSTALL_PREFIX)$(libdir); fi |