diff options
author | Timo Teras <timo.teras@iki.fi> | 2009-11-28 02:49:14 +0200 |
---|---|---|
committer | Timo Teras <timo.teras@iki.fi> | 2009-11-28 02:50:34 +0200 |
commit | bf4a081b091fc26e782bb24c786ae5ceb0577fb3 (patch) | |
tree | 872c7b04573804463a6fe5dfa00dc58d6a68a899 /main/libpri/libpri-1.4-r1357.patch | |
parent | 25668b00edf92d80fc2f15691948b659a4ac3b59 (diff) | |
download | aports-bf4a081b091fc26e782bb24c786ae5ceb0577fb3.tar.bz2 aports-bf4a081b091fc26e782bb24c786ae5ceb0577fb3.tar.xz |
main/libpri: upgrade to latest svn snapshot
Diffstat (limited to 'main/libpri/libpri-1.4-r1357.patch')
-rw-r--r-- | main/libpri/libpri-1.4-r1357.patch | 39961 |
1 files changed, 39961 insertions, 0 deletions
diff --git a/main/libpri/libpri-1.4-r1357.patch b/main/libpri/libpri-1.4-r1357.patch new file mode 100644 index 0000000000..be827eebb7 --- /dev/null +++ b/main/libpri/libpri-1.4-r1357.patch @@ -0,0 +1,39961 @@ +=================================================================== +--- a/pri_timers.h (.../tags/1.4.10.2) (revision 1357) ++++ b/pri_timers.h (.../branches/1.4) (revision 1357) +@@ -1,97 +0,0 @@ +-/* +- * libpri: An implementation of Primary Rate ISDN +- * +- * Written by Mark Spencer <markster@digium.com> +- * +- * Copyright (C) 2001, Digium, Inc. +- * All Rights Reserved. +- */ +- +-/* +- * See http://www.asterisk.org for more information about +- * the Asterisk project. Please do not directly contact +- * any of the maintainers of this project for assistance; +- * the project provides a web site, mailing lists and IRC +- * channels for your use. +- * +- * This program is free software, distributed under the terms of +- * the GNU General Public License Version 2 as published by the +- * Free Software Foundation. See the LICENSE file included with +- * this program for more details. +- * +- * In addition, when this program is distributed with Asterisk in +- * any form that would qualify as a 'combined work' or as a +- * 'derivative work' (but not mere aggregation), you can redistribute +- * and/or modify the combination under the terms of the license +- * provided with that copy of Asterisk, instead of the license +- * terms granted here. +- */ +- +-#ifndef _PRI_TIMERS_H +-#define _PRI_TIMERS_H +- +-/* -1 means we dont currently support the timer/counter */ +-#define PRI_TIMERS_DEFAULT { \ +- 3, /* N200 */ \ +- -1, /* N201 */ \ +- 3, /* N202 */ \ +- 7, /* K */ \ +- 1000, /* T200 */ \ +- -1, /* T201 */ \ +- 10000, /* T202 */ \ +- 10000, /* T203 */ \ +- -1, /* T300 */ \ +- -1, /* T301 */ \ +- -1, /* T302 */ \ +- -1, /* T303 */ \ +- -1, /* T304 */ \ +- 30000, /* T305 */ \ +- -1, /* T306 */ \ +- -1, /* T307 */ \ +- 4000, /* T308 */ \ +- -1, /* T309 */ \ +- -1, /* T310 */ \ +- 4000, /* T313 */ \ +- -1, /* T314 */ \ +- -1, /* T316 */ \ +- -1, /* T317 */ \ +- -1, /* T318 */ \ +- -1, /* T319 */ \ +- -1, /* T320 */ \ +- -1, /* T321 */ \ +- -1, /* T322 */ \ +- 2500, /* TM20 - Q.921 Appendix IV */ \ +- 3, /* NM20 - Q.921 Appendix IV */ \ +- } +- +-/* XXX Only our default timers are setup now XXX */ +-#define PRI_TIMERS_UNKNOWN PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_NI2 PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_DMS100 PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_LUCENT5E PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_ATT4ESS PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_EUROISDN_E1 PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_EUROISDN_T1 PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_NI1 PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_GR303_EOC PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_GR303_TMC PRI_TIMERS_DEFAULT +-#define PRI_TIMERS_QSIG PRI_TIMERS_DEFAULT +-#define __PRI_TIMERS_GR303_EOC_INT PRI_TIMERS_DEFAULT +-#define __PRI_TIMERS_GR303_TMC_INT PRI_TIMERS_DEFAULT +- +-#define PRI_TIMERS_ALL { PRI_TIMERS_UNKNOWN, \ +- PRI_TIMERS_NI2, \ +- PRI_TIMERS_DMS100, \ +- PRI_TIMERS_LUCENT5E, \ +- PRI_TIMERS_ATT4ESS, \ +- PRI_TIMERS_EUROISDN_E1, \ +- PRI_TIMERS_EUROISDN_T1, \ +- PRI_TIMERS_NI1, \ +- PRI_TIMERS_QSIG, \ +- PRI_TIMERS_GR303_EOC, \ +- PRI_TIMERS_GR303_TMC, \ +- __PRI_TIMERS_GR303_EOC_INT, \ +- __PRI_TIMERS_GR303_TMC_INT, \ +- } +- +-#endif +Index: .version +=================================================================== +--- a/.version (.../tags/1.4.10.2) (revision 1357) ++++ b/.version (.../branches/1.4) (revision 1357) +@@ -1 +1 @@ +-1.4.10.2 ++1.4.10.2-r1357 +Index: prisched.c +=================================================================== +--- a/prisched.c (.../tags/1.4.10.2) (revision 1357) ++++ b/prisched.c (.../branches/1.4) (revision 1357) +@@ -33,25 +33,43 @@ + #include "pri_internal.h" + + ++/*! \brief The maximum number of timers that were active at once. */ + static int maxsched = 0; + + /* Scheduler routines */ +-int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data) ++ ++/*! ++ * \brief Start a timer to schedule an event. ++ * ++ * \param ctrl D channel controller. ++ * \param ms Number of milliseconds to scheduled event. ++ * \param function Callback function to call when timeout. ++ * \param data Value to give callback function when timeout. ++ * ++ * \retval 0 if scheduler table is full and could not schedule the event. ++ * \retval id Scheduled event id. ++ */ ++int pri_schedule_event(struct pri *ctrl, int ms, void (*function)(void *data), void *data) + { + int x; + struct timeval tv; ++ + /* Scheduling runs on master channels only */ +- while (pri->master) +- pri = pri->master; +- for (x=1;x<MAX_SCHED;x++) +- if (!pri->pri_sched[x].callback) ++ while (ctrl->master) { ++ ctrl = ctrl->master; ++ } ++ for (x = 0; x < MAX_SCHED; ++x) { ++ if (!ctrl->pri_sched[x].callback) { + break; ++ } ++ } + if (x == MAX_SCHED) { +- pri_error(pri, "No more room in scheduler\n"); +- return -1; ++ pri_error(ctrl, "No more room in scheduler\n"); ++ return 0; + } +- if (x > maxsched) +- maxsched = x; ++ if (x >= maxsched) { ++ maxsched = x + 1; ++ } + gettimeofday(&tv, NULL); + tv.tv_sec += ms / 1000; + tv.tv_usec += (ms % 1000) * 1000; +@@ -59,71 +77,110 @@ + tv.tv_usec -= 1000000; + tv.tv_sec += 1; + } +- pri->pri_sched[x].when = tv; +- pri->pri_sched[x].callback = function; +- pri->pri_sched[x].data = data; +- return x; ++ ctrl->pri_sched[x].when = tv; ++ ctrl->pri_sched[x].callback = function; ++ ctrl->pri_sched[x].data = data; ++ return x + 1; + } + +-struct timeval *pri_schedule_next(struct pri *pri) ++/*! ++ * \brief Determine the time of the next scheduled event to expire. ++ * ++ * \param ctrl D channel controller. ++ * ++ * \return Time of the next scheduled event to expire or NULL if no timers active. ++ */ ++struct timeval *pri_schedule_next(struct pri *ctrl) + { + struct timeval *closest = NULL; + int x; +- /* Check subchannels */ +- if (pri->subchannel) +- closest = pri_schedule_next(pri->subchannel); +- for (x=1;x<MAX_SCHED;x++) { +- if (pri->pri_sched[x].callback && +- (!closest || (closest->tv_sec > pri->pri_sched[x].when.tv_sec) || +- ((closest->tv_sec == pri->pri_sched[x].when.tv_sec) && +- (closest->tv_usec > pri->pri_sched[x].when.tv_usec)))) +- closest = &pri->pri_sched[x].when; ++ ++ /* Scheduling runs on master channels only */ ++ while (ctrl->master) { ++ ctrl = ctrl->master; + } ++ for (x = 0; x < MAX_SCHED; ++x) { ++ if (ctrl->pri_sched[x].callback && (!closest ++ || (closest->tv_sec > ctrl->pri_sched[x].when.tv_sec) ++ || ((closest->tv_sec == ctrl->pri_sched[x].when.tv_sec) ++ && (closest->tv_usec > ctrl->pri_sched[x].when.tv_usec)))) { ++ closest = &ctrl->pri_sched[x].when; ++ } ++ } + return closest; + } + +-static pri_event *__pri_schedule_run(struct pri *pri, struct timeval *tv) ++/*! ++ * \internal ++ * \brief Run all expired timers or return an event generated by an expired timer. ++ * ++ * \param ctrl D channel controller. ++ * \param tv Current time. ++ * ++ * \return Event for upper layer to process or NULL if all expired timers run. ++ */ ++static pri_event *__pri_schedule_run(struct pri *ctrl, struct timeval *tv) + { + int x; + void (*callback)(void *); + void *data; +- pri_event *e; +- if (pri->subchannel) { +- if ((e = __pri_schedule_run(pri->subchannel, tv))) { +- return e; ++ ++ /* Scheduling runs on master channels only */ ++ while (ctrl->master) { ++ ctrl = ctrl->master; ++ } ++ for (x = 0; x < MAX_SCHED; ++x) { ++ if (ctrl->pri_sched[x].callback && ((ctrl->pri_sched[x].when.tv_sec < tv->tv_sec) ++ || ((ctrl->pri_sched[x].when.tv_sec == tv->tv_sec) ++ && (ctrl->pri_sched[x].when.tv_usec <= tv->tv_usec)))) { ++ /* This timer has expired. */ ++ ctrl->schedev = 0; ++ callback = ctrl->pri_sched[x].callback; ++ data = ctrl->pri_sched[x].data; ++ ctrl->pri_sched[x].callback = NULL; ++ callback(data); ++ if (ctrl->schedev) { ++ return &ctrl->ev; ++ } + } + } +- for (x=1;x<MAX_SCHED;x++) { +- if (pri->pri_sched[x].callback && +- ((pri->pri_sched[x].when.tv_sec < tv->tv_sec) || +- ((pri->pri_sched[x].when.tv_sec == tv->tv_sec) && +- (pri->pri_sched[x].when.tv_usec <= tv->tv_usec)))) { +- pri->schedev = 0; +- callback = pri->pri_sched[x].callback; +- data = pri->pri_sched[x].data; +- pri->pri_sched[x].callback = NULL; +- pri->pri_sched[x].data = NULL; +- callback(data); +- if (pri->schedev) +- return &pri->ev; +- } +- } + return NULL; + } + +-pri_event *pri_schedule_run(struct pri *pri) ++/*! ++ * \brief Run all expired timers or return an event generated by an expired timer. ++ * ++ * \param ctrl D channel controller. ++ * ++ * \return Event for upper layer to process or NULL if all expired timers run. ++ */ ++pri_event *pri_schedule_run(struct pri *ctrl) + { + struct timeval tv; ++ + gettimeofday(&tv, NULL); +- return __pri_schedule_run(pri, &tv); ++ return __pri_schedule_run(ctrl, &tv); + } + +- +-void pri_schedule_del(struct pri *pri,int id) ++/*! ++ * \brief Delete a scheduled event. ++ * ++ * \param ctrl D channel controller. ++ * \param id Scheduled event id to delete. ++ * 0 is a disabled/unscheduled event id that is ignored. ++ * 1 - MAX_SCHED is a valid event id. ++ * ++ * \return Nothing ++ */ ++void pri_schedule_del(struct pri *ctrl, int id) + { +- while (pri->master) +- pri = pri->master; +- if ((id >= MAX_SCHED) || (id < 0)) +- pri_error(pri, "Asked to delete sched id %d???\n", id); +- pri->pri_sched[id].callback = NULL; ++ /* Scheduling runs on master channels only */ ++ while (ctrl->master) { ++ ctrl = ctrl->master; ++ } ++ if (0 < id && id <= MAX_SCHED) { ++ ctrl->pri_sched[id - 1].callback = NULL; ++ } else if (id) { ++ pri_error(ctrl, "Asked to delete sched id %d???\n", id); ++ } + } +Index: rose_qsig_mwi.c +=================================================================== +--- a/rose_qsig_mwi.c (.../tags/1.4.10.2) (revision 0) ++++ b/rose_qsig_mwi.c (.../branches/1.4) (revision 1357) +@@ -0,0 +1,790 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief Q.SIG ROSE SS-MWI-Operations ++ * ++ * SS-MWI-Operations ECMA-242 Annex E Table E.1 ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++ ++#include "compat.h" ++#include "libpri.h" ++#include "pri_internal.h" ++#include "rose.h" ++#include "rose_internal.h" ++#include "asn1.h" ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++/*! ++ * \internal ++ * \brief Encode the MsgCentreId type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param msg_centre_id ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_MsgCentreId(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct roseQsigMsgCentreId *msg_centre_id) ++{ ++ unsigned char *seq_len; ++ ++ switch (msg_centre_id->type) { ++ case 0: /* integer */ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0, ++ msg_centre_id->u.integer)); ++ break; ++ case 1: /* partyNumber */ ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &msg_centre_id->u.number)); ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ break; ++ case 2: /* numericString */ ++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, ++ msg_centre_id->u.str, sizeof(msg_centre_id->u.str) - 1)); ++ break; ++ default: ++ ASN1_ENC_ERROR(ctrl, "Unknown MsgCentreId type"); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the MWIActivate invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigMWIActivateArg *mwi_activate; ++ unsigned char *seq_len; ++ unsigned char *explicit_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ mwi_activate = &args->qsig.MWIActivate; ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &mwi_activate->served_user_number)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ mwi_activate->basic_service)); ++ if (mwi_activate->msg_centre_id_present) { ++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end, ++ &mwi_activate->msg_centre_id)); ++ } ++ if (mwi_activate->number_of_messages_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3, ++ mwi_activate->number_of_messages)); ++ } ++ if (mwi_activate->originating_number.length) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &mwi_activate->originating_number)); ++ ASN1_CONSTRUCTED_END(explicit_len, pos, end); ++ } ++ if (mwi_activate->timestamp_present) { ++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME, ++ mwi_activate->timestamp, sizeof(mwi_activate->timestamp) - 1)); ++ } ++ if (mwi_activate->priority_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5, ++ mwi_activate->priority)); ++ } ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the MWIDeactivate invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigMWIDeactivateArg *mwi_deactivate; ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ mwi_deactivate = &args->qsig.MWIDeactivate; ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &mwi_deactivate->served_user_number)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ mwi_deactivate->basic_service)); ++ if (mwi_deactivate->msg_centre_id_present) { ++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end, ++ &mwi_deactivate->msg_centre_id)); ++ } ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the MWIInterrogate invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigMWIInterrogateArg *mwi_interrogate; ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ mwi_interrogate = &args->qsig.MWIInterrogate; ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &mwi_interrogate->served_user_number)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ mwi_interrogate->basic_service)); ++ if (mwi_interrogate->msg_centre_id_present) { ++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end, ++ &mwi_interrogate->msg_centre_id)); ++ } ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the MWIInterrogateResElt type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param record ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_MWIInterrogateResElt(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, unsigned tag, ++ const struct roseQsigMWIInterrogateResElt *record) ++{ ++ unsigned char *seq_len; ++ unsigned char *explicit_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, record->basic_service)); ++ if (record->msg_centre_id_present) { ++ ASN1_CALL(pos, rose_enc_qsig_MsgCentreId(ctrl, pos, end, ++ &record->msg_centre_id)); ++ } ++ if (record->number_of_messages_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3, ++ record->number_of_messages)); ++ } ++ if (record->originating_number.length) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &record->originating_number)); ++ ASN1_CONSTRUCTED_END(explicit_len, pos, end); ++ } ++ if (record->timestamp_present) { ++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_TYPE_GENERALIZED_TIME, ++ record->timestamp, sizeof(record->timestamp) - 1)); ++ } ++ if (record->priority_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5, ++ record->priority)); ++ } ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the MWIInterrogate result facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args) ++{ ++ unsigned index; ++ unsigned char *seq_len; ++ const struct roseQsigMWIInterrogateRes *mwi_interrogate; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ mwi_interrogate = &args->qsig.MWIInterrogate; ++ for (index = 0; index < mwi_interrogate->num_records; ++index) { ++ ASN1_CALL(pos, rose_enc_qsig_MWIInterrogateResElt(ctrl, pos, end, ++ ASN1_TAG_SEQUENCE, &mwi_interrogate->list[index])); ++ } ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the MsgCentreId argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param msg_centre_id Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_dec_qsig_MsgCentreId(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct roseQsigMsgCentreId *msg_centre_id) ++{ ++ int32_t value; ++ size_t str_len; ++ int length; ++ int explicit_offset; ++ const unsigned char *explicit_end; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s MsgCentreId\n", name); ++ } ++ switch (tag) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0: ++ msg_centre_id->type = 0; /* integer */ ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "integer", tag, pos, end, &value)); ++ msg_centre_id->u.integer = value; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1: ++ msg_centre_id->type = 1; /* partyNumber */ ++ ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, explicit_end, ++ &msg_centre_id->u.number)); ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2: ++ msg_centre_id->type = 2; /* numericString */ ++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "numericString", tag, pos, end, ++ sizeof(msg_centre_id->u.str), msg_centre_id->u.str, &str_len)); ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG MWIActivate invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ size_t str_len; ++ int length; ++ int seq_offset; ++ int explicit_offset; ++ const unsigned char *explicit_end; ++ const unsigned char *seq_end; ++ const unsigned char *save_pos; ++ struct roseQsigMWIActivateArg *mwi_activate; ++ ++ mwi_activate = &args->qsig.MWIActivate; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " MWIActivateArg %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end, ++ &mwi_activate->served_user_number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); ++ mwi_activate->basic_service = value; ++ ++ /* ++ * A sequence specifies an ordered list of component types. ++ * However, for simplicity we are not checking the order of ++ * the remaining optional components. ++ */ ++ mwi_activate->msg_centre_id_present = 0; ++ mwi_activate->number_of_messages_present = 0; ++ mwi_activate->originating_number.length = 0; ++ mwi_activate->timestamp_present = 0; ++ mwi_activate->priority_present = 0; ++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag & ~ASN1_PC_MASK) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos, ++ seq_end, &mwi_activate->msg_centre_id)); ++ mwi_activate->msg_centre_id_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3: ++ /* Must not be constructed but we will not check for it for simplicity. */ ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "nbOfMessages", tag, pos, seq_end, ++ &value)); ++ mwi_activate->number_of_messages = value; ++ mwi_activate->number_of_messages_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4: ++ /* Must be constructed but we will not check for it for simplicity. */ ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "originatingNr", tag, pos, ++ explicit_end, &mwi_activate->originating_number)); ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_TYPE_GENERALIZED_TIME: ++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "timestamp", tag, pos, end, ++ sizeof(mwi_activate->timestamp), mwi_activate->timestamp, &str_len)); ++ mwi_activate->timestamp_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5: ++ /* Must not be constructed but we will not check for it for simplicity. */ ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "priority", tag, pos, seq_end, &value)); ++ mwi_activate->priority = value; ++ mwi_activate->priority_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 6: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag)); ++ } ++ /* Fixup will skip over the manufacturer extension information */ ++ default: ++ pos = save_pos; ++ goto cancel_options; ++ } ++ } ++cancel_options:; ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG MWIDeactivate invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ const unsigned char *save_pos; ++ struct roseQsigMWIDeactivateArg *mwi_deactivate; ++ ++ mwi_deactivate = &args->qsig.MWIDeactivate; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " MWIDeactivateArg %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end, ++ &mwi_deactivate->served_user_number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); ++ mwi_deactivate->basic_service = value; ++ ++ /* ++ * A sequence specifies an ordered list of component types. ++ * However, for simplicity we are not checking the order of ++ * the remaining optional components. ++ */ ++ mwi_deactivate->msg_centre_id_present = 0; ++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag & ~ASN1_PC_MASK) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos, ++ seq_end, &mwi_deactivate->msg_centre_id)); ++ mwi_deactivate->msg_centre_id_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag)); ++ } ++ /* Fixup will skip over the manufacturer extension information */ ++ default: ++ pos = save_pos; ++ goto cancel_options; ++ } ++ } ++cancel_options:; ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG MWIInterrogate invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ const unsigned char *save_pos; ++ struct roseQsigMWIInterrogateArg *mwi_interrogate; ++ ++ mwi_interrogate = &args->qsig.MWIInterrogate; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " MWIInterrogateArg %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end, ++ &mwi_interrogate->served_user_number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); ++ mwi_interrogate->basic_service = value; ++ ++ /* ++ * A sequence specifies an ordered list of component types. ++ * However, for simplicity we are not checking the order of ++ * the remaining optional components. ++ */ ++ mwi_interrogate->msg_centre_id_present = 0; ++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag & ~ASN1_PC_MASK) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos, ++ seq_end, &mwi_interrogate->msg_centre_id)); ++ mwi_interrogate->msg_centre_id_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag)); ++ } ++ /* Fixup will skip over the manufacturer extension information */ ++ default: ++ pos = save_pos; ++ goto cancel_options; ++ } ++ } ++cancel_options:; ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the MWIInterrogateResElt argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param record Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_dec_qsig_MWIInterrogateResElt(struct pri *ctrl, ++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct roseQsigMWIInterrogateResElt *record) ++{ ++ int32_t value; ++ size_t str_len; ++ int length; ++ int seq_offset; ++ int explicit_offset; ++ const unsigned char *explicit_end; ++ const unsigned char *seq_end; ++ const unsigned char *save_pos; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " MWIInterrogateResElt %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); ++ record->basic_service = value; ++ ++ /* ++ * A sequence specifies an ordered list of component types. ++ * However, for simplicity we are not checking the order of ++ * the remaining optional components. ++ */ ++ record->msg_centre_id_present = 0; ++ record->number_of_messages_present = 0; ++ record->originating_number.length = 0; ++ record->timestamp_present = 0; ++ record->priority_present = 0; ++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag & ~ASN1_PC_MASK) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ ASN1_CALL(pos, rose_dec_qsig_MsgCentreId(ctrl, "msgCentreId", tag, pos, ++ seq_end, &record->msg_centre_id)); ++ record->msg_centre_id_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3: ++ /* Must not be constructed but we will not check for it for simplicity. */ ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "nbOfMessages", tag, pos, seq_end, ++ &value)); ++ record->number_of_messages = value; ++ record->number_of_messages_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4: ++ /* Must be constructed but we will not check for it for simplicity. */ ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "originatingNr", tag, pos, ++ explicit_end, &record->originating_number)); ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_TYPE_GENERALIZED_TIME: ++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, "timestamp", tag, pos, end, ++ sizeof(record->timestamp), record->timestamp, &str_len)); ++ record->timestamp_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5: ++ /* Must not be constructed but we will not check for it for simplicity. */ ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "priority", tag, pos, seq_end, &value)); ++ record->priority = value; ++ record->priority_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 6: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 7: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " argumentExt %s\n", asn1_tag2str(tag)); ++ } ++ /* Fixup will skip over the manufacturer extension information */ ++ default: ++ pos = save_pos; ++ goto cancel_options; ++ } ++ } ++cancel_options:; ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG MWIInterrogate result argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args) ++{ ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ struct roseQsigMWIInterrogateRes *mwi_interrogate; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " MWIInterrogateRes %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ mwi_interrogate = &args->qsig.MWIInterrogate; ++ ++ mwi_interrogate->num_records = 0; ++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ if (mwi_interrogate->num_records < ARRAY_LEN(mwi_interrogate->list)) { ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ ASN1_CALL(pos, rose_dec_qsig_MWIInterrogateResElt(ctrl, "listEntry", tag, ++ pos, seq_end, &mwi_interrogate->list[mwi_interrogate->num_records])); ++ ++mwi_interrogate->num_records; ++ } else { ++ /* Too many records */ ++ return NULL; ++ } ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++ ++/* ------------------------------------------------------------------- */ ++/* end rose_qsig_mwi.c */ + +Property changes on: rose_qsig_mwi.c +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: rosetest.c +=================================================================== +--- a/rosetest.c (.../tags/1.4.10.2) (revision 0) ++++ b/rosetest.c (.../branches/1.4) (revision 1357) +@@ -0,0 +1,2473 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief ROSE encode/decode test program ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++ ++#include "compat.h" ++#include "libpri.h" ++#include "pri_internal.h" ++#include "rose.h" ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++static const struct fac_extension_header fac_headers[] = { ++/* *INDENT-OFF* */ ++ { ++ .nfe_present = 0, ++ }, ++ { ++ .nfe_present = 1, ++ .nfe.source_entity = 1, ++ .nfe.destination_entity = 1, ++ }, ++ { ++ .nfe_present = 1, ++ .nfe.source_entity = 1, ++ .nfe.source_number.plan = 4, ++ .nfe.source_number.length = 4, ++ .nfe.source_number.str = "9834", ++ .nfe.destination_entity = 1, ++ .nfe.destination_number.plan = 4, ++ .nfe.destination_number.length = 4, ++ .nfe.destination_number.str = "9834", ++ }, ++ { ++ .nfe_present = 1, ++ .nfe.source_entity = 1, ++ .nfe.destination_entity = 1, ++ .npp_present = 1, ++ .npp = 19, ++ .interpretation_present = 1, ++ .interpretation = 2, ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++static const struct rose_message rose_etsi_msgs[] = { ++/* *INDENT-OFF* */ ++ /* Error messages */ ++ { ++ .type = ROSE_COMP_TYPE_ERROR, ++ .component.error.invoke_id = 82, ++ .component.error.code = ROSE_ERROR_Div_SpecialServiceNr, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_ERROR, ++ .component.error.invoke_id = 8, ++ .component.error.code = ROSE_ERROR_ECT_LinkIdNotAssignedByNetwork, ++ }, ++ ++ /* Reject messages */ ++ { ++ .type = ROSE_COMP_TYPE_REJECT, ++ .component.reject.code = ROSE_REJECT_Gen_BadlyStructuredComponent, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_REJECT, ++ .component.reject.invoke_id_present = 1, ++ .component.reject.invoke_id = 10, ++ .component.reject.code = ROSE_REJECT_Inv_InitiatorReleasing, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_REJECT, ++ .component.reject.invoke_id_present = 1, ++ .component.reject.invoke_id = 11, ++ .component.reject.code = ROSE_REJECT_Res_MistypedResult, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_REJECT, ++ .component.reject.invoke_id_present = 1, ++ .component.reject.invoke_id = 12, ++ .component.reject.code = ROSE_REJECT_Err_ErrorResponseUnexpected, ++ }, ++ ++ /* Anonymous result or result without any arguments. */ ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_None, ++ .component.result.invoke_id = 9, ++ }, ++ ++ /* Advice Of Charge (AOC) */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_ChargingRequest, ++ .component.invoke.invoke_id = 98, ++ .component.invoke.args.etsi.ChargingRequest.charging_case = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_ChargingRequest, ++ .component.result.invoke_id = 99, ++ .component.result.args.etsi.ChargingRequest.type = 0, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 0, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.special_charging_code = 3, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_ChargingRequest, ++ .component.result.invoke_id = 100, ++ .component.result.args.etsi.ChargingRequest.type = 0, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.currency = "Dollars", ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.currency = 7, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.multiplier = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.charging_type = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.length = 8, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.scale = 4, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_ChargingRequest, ++ .component.result.invoke_id = 101, ++ .component.result.args.etsi.ChargingRequest.type = 0, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.currency = "Dollars", ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.currency = 7, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.amount.multiplier = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.charging_type = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.length = 8, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.time.scale = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.granularity_present = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.granularity.length = 20, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.duration.granularity.scale = 3, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_ChargingRequest, ++ .component.result.invoke_id = 102, ++ .component.result.args.etsi.ChargingRequest.type = 0, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 2, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.currency = "Euros", ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.currency = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.multiplier = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_ChargingRequest, ++ .component.result.invoke_id = 103, ++ .component.result.args.etsi.ChargingRequest.type = 0, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 3, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.currency = "Yen", ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.amount.currency = 300, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.amount.multiplier = 5, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.volume_rate.unit = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_ChargingRequest, ++ .component.result.invoke_id = 104, ++ .component.result.args.etsi.ChargingRequest.type = 0, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 2, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 2, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.currency = "Euros", ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.currency = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].u.flat_rate.amount.multiplier = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].charged_item = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].currency_type = 3, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.currency = "Yen", ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.amount.currency = 300, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.amount.multiplier = 5, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[1].u.volume_rate.unit = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_ChargingRequest, ++ .component.result.invoke_id = 105, ++ .component.result.args.etsi.ChargingRequest.type = 0, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 4, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_ChargingRequest, ++ .component.result.invoke_id = 106, ++ .component.result.args.etsi.ChargingRequest.type = 0, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.num_records = 1, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].charged_item = 4, ++ .component.result.args.etsi.ChargingRequest.u.currency_info.list[0].currency_type = 5, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCSCurrency, ++ .component.invoke.invoke_id = 107, ++ .component.invoke.args.etsi.AOCSCurrency.type = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCSCurrency, ++ .component.invoke.invoke_id = 108, ++ .component.invoke.args.etsi.AOCSCurrency.type = 1, ++ .component.invoke.args.etsi.AOCSCurrency.currency_info.num_records = 1, ++ .component.invoke.args.etsi.AOCSCurrency.currency_info.list[0].charged_item = 3, ++ .component.invoke.args.etsi.AOCSCurrency.currency_info.list[0].currency_type = 4, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCSSpecialArr, ++ .component.invoke.invoke_id = 109, ++ .component.invoke.args.etsi.AOCSSpecialArr.type = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCSSpecialArr, ++ .component.invoke.invoke_id = 110, ++ .component.invoke.args.etsi.AOCSSpecialArr.type = 1, ++ .component.invoke.args.etsi.AOCSSpecialArr.special_arrangement = 9, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency, ++ .component.invoke.invoke_id = 111, ++ .component.invoke.args.etsi.AOCDCurrency.type = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency, ++ .component.invoke.invoke_id = 112, ++ .component.invoke.args.etsi.AOCDCurrency.type = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency, ++ .component.invoke.invoke_id = 113, ++ .component.invoke.args.etsi.AOCDCurrency.type = 2, ++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.currency = "Francs", ++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.currency = 674, ++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.multiplier = 3, ++ .component.invoke.args.etsi.AOCDCurrency.specific.type_of_charging_info = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDCurrency, ++ .component.invoke.invoke_id = 114, ++ .component.invoke.args.etsi.AOCDCurrency.type = 2, ++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.currency = "Francs", ++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.currency = 674, ++ .component.invoke.args.etsi.AOCDCurrency.specific.recorded.amount.multiplier = 3, ++ .component.invoke.args.etsi.AOCDCurrency.specific.type_of_charging_info = 1, ++ .component.invoke.args.etsi.AOCDCurrency.specific.billing_id_present = 1, ++ .component.invoke.args.etsi.AOCDCurrency.specific.billing_id = 2, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit, ++ .component.invoke.invoke_id = 115, ++ .component.invoke.args.etsi.AOCDChargingUnit.type = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit, ++ .component.invoke.invoke_id = 116, ++ .component.invoke.args.etsi.AOCDChargingUnit.type = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit, ++ .component.invoke.invoke_id = 117, ++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit, ++ .component.invoke.invoke_id = 118, ++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 0, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].number_of_units = 8523, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.billing_id_present = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.billing_id = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit, ++ .component.invoke.invoke_id = 119, ++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit_present = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit = 13, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit, ++ .component.invoke.invoke_id = 120, ++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 0, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].number_of_units = 8523, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit_present = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].type_of_unit = 13, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCDChargingUnit, ++ .component.invoke.invoke_id = 121, ++ .component.invoke.args.etsi.AOCDChargingUnit.type = 2, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.num_records = 2, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[0].not_available = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].not_available = 0, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].number_of_units = 8523, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].type_of_unit_present = 1, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.recorded.list[1].type_of_unit = 13, ++ .component.invoke.args.etsi.AOCDChargingUnit.specific.type_of_charging_info = 1, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCECurrency, ++ .component.invoke.invoke_id = 122, ++ .component.invoke.args.etsi.AOCECurrency.type = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCECurrency, ++ .component.invoke.invoke_id = 123, ++ .component.invoke.args.etsi.AOCECurrency.type = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCECurrency, ++ .component.invoke.invoke_id = 124, ++ .component.invoke.args.etsi.AOCECurrency.type = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 0, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.id = -37, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCECurrency, ++ .component.invoke.invoke_id = 125, ++ .component.invoke.args.etsi.AOCECurrency.type = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.number.plan = 0, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.number.length = 7, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.number.str = "5551212", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCECurrency, ++ .component.invoke.invoke_id = 126, ++ .component.invoke.args.etsi.AOCECurrency.type = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs", ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCECurrency, ++ .component.invoke.invoke_id = 127, ++ .component.invoke.args.etsi.AOCECurrency.type = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs", ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 0, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.id = -37, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCECurrency, ++ .component.invoke.invoke_id = 128, ++ .component.invoke.args.etsi.AOCECurrency.type = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs", ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id_present = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCECurrency, ++ .component.invoke.invoke_id = 129, ++ .component.invoke.args.etsi.AOCECurrency.type = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.free_of_charge = 0, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.currency = "Francs", ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.currency = 674, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.recorded.amount.multiplier = 3, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id_present = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.specific.billing_id = 2, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association_present = 1, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.type = 0, ++ .component.invoke.args.etsi.AOCECurrency.currency_info.charging_association.id = -37, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit, ++ .component.invoke.invoke_id = 130, ++ .component.invoke.args.etsi.AOCEChargingUnit.type = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit, ++ .component.invoke.invoke_id = 131, ++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit, ++ .component.invoke.invoke_id = 132, ++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id = -37, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit, ++ .component.invoke.invoke_id = 133, ++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit, ++ .component.invoke.invoke_id = 134, ++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id = -37, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit, ++ .component.invoke.invoke_id = 135, ++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id_present = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_AOCEChargingUnit, ++ .component.invoke.invoke_id = 136, ++ .component.invoke.args.etsi.AOCEChargingUnit.type = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 0, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0].not_available = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id_present = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.specific.billing_id = 2, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association_present = 1, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.type = 0, ++ .component.invoke.args.etsi.AOCEChargingUnit.charging_unit.charging_association.id = -37, ++ }, ++ ++ /* Call diversion */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_ActivationDiversion, ++ .component.invoke.invoke_id = 67, ++ .component.invoke.linked_id_present = 1, ++ .component.invoke.linked_id = 27, ++ .component.invoke.args.etsi.ActivationDiversion.procedure = 2, ++ .component.invoke.args.etsi.ActivationDiversion.basic_service = 3, ++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.plan = 4, ++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.length = 4, ++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.str = "1803", ++ .component.invoke.args.etsi.ActivationDiversion.served_user_number.plan = 4, ++ .component.invoke.args.etsi.ActivationDiversion.served_user_number.length = 4, ++ .component.invoke.args.etsi.ActivationDiversion.served_user_number.str = "5398", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_ActivationDiversion, ++ .component.invoke.invoke_id = 68, ++ .component.invoke.args.etsi.ActivationDiversion.procedure = 1, ++ .component.invoke.args.etsi.ActivationDiversion.basic_service = 5, ++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.plan = 4, ++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.length = 4, ++ .component.invoke.args.etsi.ActivationDiversion.forwarded_to.number.str = "1803", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_ActivationDiversion, ++ .component.result.invoke_id = 69, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DeactivationDiversion, ++ .component.invoke.invoke_id = 70, ++ .component.invoke.args.etsi.DeactivationDiversion.procedure = 1, ++ .component.invoke.args.etsi.DeactivationDiversion.basic_service = 5, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_DeactivationDiversion, ++ .component.result.invoke_id = 71, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_ActivationStatusNotificationDiv, ++ .component.invoke.invoke_id = 72, ++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.procedure = 1, ++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.basic_service = 5, ++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.forwarded_to.number.plan = 4, ++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.forwarded_to.number.length = 4, ++ .component.invoke.args.etsi.ActivationStatusNotificationDiv.forwarded_to.number.str = "1803", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DeactivationStatusNotificationDiv, ++ .component.invoke.invoke_id = 73, ++ .component.invoke.args.etsi.DeactivationStatusNotificationDiv.procedure = 1, ++ .component.invoke.args.etsi.DeactivationStatusNotificationDiv.basic_service = 5, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_InterrogationDiversion, ++ .component.invoke.invoke_id = 74, ++ .component.invoke.args.etsi.InterrogationDiversion.procedure = 1, ++ .component.invoke.args.etsi.InterrogationDiversion.basic_service = 5, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_InterrogationDiversion, ++ .component.invoke.invoke_id = 75, ++ .component.invoke.args.etsi.InterrogationDiversion.procedure = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_InterrogationDiversion, ++ .component.result.invoke_id = 76, ++ .component.result.args.etsi.InterrogationDiversion.num_records = 2, ++ .component.result.args.etsi.InterrogationDiversion.list[0].procedure = 2, ++ .component.result.args.etsi.InterrogationDiversion.list[0].basic_service = 5, ++ .component.result.args.etsi.InterrogationDiversion.list[0].forwarded_to.number.plan = 4, ++ .component.result.args.etsi.InterrogationDiversion.list[0].forwarded_to.number.length = 4, ++ .component.result.args.etsi.InterrogationDiversion.list[0].forwarded_to.number.str = "1803", ++ .component.result.args.etsi.InterrogationDiversion.list[1].procedure = 1, ++ .component.result.args.etsi.InterrogationDiversion.list[1].basic_service = 3, ++ .component.result.args.etsi.InterrogationDiversion.list[1].forwarded_to.number.plan = 4, ++ .component.result.args.etsi.InterrogationDiversion.list[1].forwarded_to.number.length = 4, ++ .component.result.args.etsi.InterrogationDiversion.list[1].forwarded_to.number.str = "1903", ++ .component.result.args.etsi.InterrogationDiversion.list[1].served_user_number.plan = 4, ++ .component.result.args.etsi.InterrogationDiversion.list[1].served_user_number.length = 4, ++ .component.result.args.etsi.InterrogationDiversion.list[1].served_user_number.str = "5398", ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DiversionInformation, ++ .component.invoke.invoke_id = 77, ++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 3, ++ .component.invoke.args.etsi.DiversionInformation.basic_service = 5, ++ .component.invoke.args.etsi.DiversionInformation.served_user_subaddress.type = 1, ++ .component.invoke.args.etsi.DiversionInformation.served_user_subaddress.length = 4, ++ .component.invoke.args.etsi.DiversionInformation.served_user_subaddress.u.nsap = "6492", ++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1, ++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 0, ++ .component.invoke.args.etsi.DiversionInformation.calling.screened.screening_indicator = 3, ++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.plan = 4, ++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.length = 4, ++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.str = "1803", ++ .component.invoke.args.etsi.DiversionInformation.original_called_present = 1, ++ .component.invoke.args.etsi.DiversionInformation.original_called.presentation = 1, ++ .component.invoke.args.etsi.DiversionInformation.last_diverting_present = 1, ++ .component.invoke.args.etsi.DiversionInformation.last_diverting.presentation = 2, ++ .component.invoke.args.etsi.DiversionInformation.last_diverting_reason_present = 1, ++ .component.invoke.args.etsi.DiversionInformation.last_diverting_reason = 3, ++ .component.invoke.args.etsi.DiversionInformation.q931ie.length = 5, ++ .component.invoke.args.etsi.DiversionInformation.q931ie_contents = "79828", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DiversionInformation, ++ .component.invoke.invoke_id = 78, ++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 3, ++ .component.invoke.args.etsi.DiversionInformation.basic_service = 5, ++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1, ++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 1, ++ .component.invoke.args.etsi.DiversionInformation.original_called_present = 1, ++ .component.invoke.args.etsi.DiversionInformation.original_called.presentation = 2, ++ .component.invoke.args.etsi.DiversionInformation.last_diverting_present = 1, ++ .component.invoke.args.etsi.DiversionInformation.last_diverting.presentation = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DiversionInformation, ++ .component.invoke.invoke_id = 79, ++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 2, ++ .component.invoke.args.etsi.DiversionInformation.basic_service = 3, ++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1, ++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DiversionInformation, ++ .component.invoke.invoke_id = 80, ++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 3, ++ .component.invoke.args.etsi.DiversionInformation.basic_service = 5, ++ .component.invoke.args.etsi.DiversionInformation.calling_present = 1, ++ .component.invoke.args.etsi.DiversionInformation.calling.presentation = 3, ++ .component.invoke.args.etsi.DiversionInformation.calling.screened.screening_indicator = 2, ++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.plan = 4, ++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.length = 4, ++ .component.invoke.args.etsi.DiversionInformation.calling.screened.number.str = "1803", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DiversionInformation, ++ .component.invoke.invoke_id = 81, ++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 2, ++ .component.invoke.args.etsi.DiversionInformation.basic_service = 4, ++ .component.invoke.args.etsi.DiversionInformation.q931ie.length = 5, ++ .component.invoke.args.etsi.DiversionInformation.q931ie_contents = "79828", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DiversionInformation, ++ .component.invoke.invoke_id = 82, ++ .component.invoke.args.etsi.DiversionInformation.diversion_reason = 2, ++ .component.invoke.args.etsi.DiversionInformation.basic_service = 4, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_CallDeflection, ++ .component.invoke.invoke_id = 83, ++ .component.invoke.args.etsi.CallDeflection.deflection.number.plan = 4, ++ .component.invoke.args.etsi.CallDeflection.deflection.number.length = 4, ++ .component.invoke.args.etsi.CallDeflection.deflection.number.str = "1803", ++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1, ++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_CallDeflection, ++ .component.invoke.invoke_id = 84, ++ .component.invoke.args.etsi.CallDeflection.deflection.number.plan = 4, ++ .component.invoke.args.etsi.CallDeflection.deflection.number.length = 4, ++ .component.invoke.args.etsi.CallDeflection.deflection.number.str = "1803", ++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1, ++ .component.invoke.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_CallDeflection, ++ .component.invoke.invoke_id = 85, ++ .component.invoke.args.etsi.CallDeflection.deflection.number.plan = 4, ++ .component.invoke.args.etsi.CallDeflection.deflection.number.length = 4, ++ .component.invoke.args.etsi.CallDeflection.deflection.number.str = "1803", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_CallDeflection, ++ .component.result.invoke_id = 86, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_CallRerouting, ++ .component.invoke.invoke_id = 87, ++ .component.invoke.args.etsi.CallRerouting.rerouting_reason = 3, ++ .component.invoke.args.etsi.CallRerouting.rerouting_counter = 2, ++ .component.invoke.args.etsi.CallRerouting.called_address.number.plan = 4, ++ .component.invoke.args.etsi.CallRerouting.called_address.number.length = 4, ++ .component.invoke.args.etsi.CallRerouting.called_address.number.str = "1803", ++ .component.invoke.args.etsi.CallRerouting.q931ie.length = 129, ++ .component.invoke.args.etsi.CallRerouting.q931ie_contents = ++ "YEHAW." ++ " The quick brown fox jumped over the lazy dog test." ++ " Now is the time for all good men to come to the aid of their country.", ++ .component.invoke.args.etsi.CallRerouting.last_rerouting.presentation = 1, ++ .component.invoke.args.etsi.CallRerouting.subscription_option = 2, ++ .component.invoke.args.etsi.CallRerouting.calling_subaddress.type = 1, ++ .component.invoke.args.etsi.CallRerouting.calling_subaddress.length = 4, ++ .component.invoke.args.etsi.CallRerouting.calling_subaddress.u.nsap = "6492", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_CallRerouting, ++ .component.invoke.invoke_id = 88, ++ .component.invoke.args.etsi.CallRerouting.rerouting_reason = 3, ++ .component.invoke.args.etsi.CallRerouting.rerouting_counter = 2, ++ .component.invoke.args.etsi.CallRerouting.called_address.number.plan = 4, ++ .component.invoke.args.etsi.CallRerouting.called_address.number.length = 4, ++ .component.invoke.args.etsi.CallRerouting.called_address.number.str = "1803", ++ .component.invoke.args.etsi.CallRerouting.q931ie.length = 2, ++ .component.invoke.args.etsi.CallRerouting.q931ie_contents = "RT", ++ .component.invoke.args.etsi.CallRerouting.last_rerouting.presentation = 1, ++ .component.invoke.args.etsi.CallRerouting.subscription_option = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_CallRerouting, ++ .component.invoke.invoke_id = 89, ++ .component.invoke.args.etsi.CallRerouting.rerouting_reason = 3, ++ .component.invoke.args.etsi.CallRerouting.rerouting_counter = 2, ++ .component.invoke.args.etsi.CallRerouting.called_address.number.plan = 4, ++ .component.invoke.args.etsi.CallRerouting.called_address.number.length = 4, ++ .component.invoke.args.etsi.CallRerouting.called_address.number.str = "1803", ++ .component.invoke.args.etsi.CallRerouting.q931ie.length = 2, ++ .component.invoke.args.etsi.CallRerouting.q931ie_contents = "RT", ++ .component.invoke.args.etsi.CallRerouting.last_rerouting.presentation = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_CallRerouting, ++ .component.result.invoke_id = 90, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_InterrogateServedUserNumbers, ++ .component.invoke.invoke_id = 91, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_InterrogateServedUserNumbers, ++ .component.result.invoke_id = 92, ++ .component.result.args.etsi.InterrogateServedUserNumbers.num_records = 2, ++ .component.result.args.etsi.InterrogateServedUserNumbers.number[0].plan = 4, ++ .component.result.args.etsi.InterrogateServedUserNumbers.number[0].length = 4, ++ .component.result.args.etsi.InterrogateServedUserNumbers.number[0].str = "1803", ++ .component.result.args.etsi.InterrogateServedUserNumbers.number[1].plan = 4, ++ .component.result.args.etsi.InterrogateServedUserNumbers.number[1].length = 4, ++ .component.result.args.etsi.InterrogateServedUserNumbers.number[1].str = "5786", ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation1, ++ .component.invoke.invoke_id = 93, ++ .component.invoke.args.etsi.DivertingLegInformation1.diversion_reason = 4, ++ .component.invoke.args.etsi.DivertingLegInformation1.subscription_option = 1, ++ .component.invoke.args.etsi.DivertingLegInformation1.diverted_to_present = 1, ++ .component.invoke.args.etsi.DivertingLegInformation1.diverted_to.presentation = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation1, ++ .component.invoke.invoke_id = 94, ++ .component.invoke.args.etsi.DivertingLegInformation1.diversion_reason = 4, ++ .component.invoke.args.etsi.DivertingLegInformation1.subscription_option = 1, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation2, ++ .component.invoke.invoke_id = 95, ++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_counter = 3, ++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_reason = 2, ++ .component.invoke.args.etsi.DivertingLegInformation2.diverting_present = 1, ++ .component.invoke.args.etsi.DivertingLegInformation2.diverting.presentation = 2, ++ .component.invoke.args.etsi.DivertingLegInformation2.original_called_present = 1, ++ .component.invoke.args.etsi.DivertingLegInformation2.original_called.presentation = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation2, ++ .component.invoke.invoke_id = 96, ++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_counter = 3, ++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_reason = 2, ++ .component.invoke.args.etsi.DivertingLegInformation2.original_called_present = 1, ++ .component.invoke.args.etsi.DivertingLegInformation2.original_called.presentation = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation2, ++ .component.invoke.invoke_id = 97, ++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_counter = 1, ++ .component.invoke.args.etsi.DivertingLegInformation2.diversion_reason = 2, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_DivertingLegInformation3, ++ .component.invoke.invoke_id = 98, ++ .component.invoke.args.etsi.DivertingLegInformation3.presentation_allowed_indicator = 1, ++ }, ++ ++ /* Explicit Call Transfer (ECT) */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_EctExecute, ++ .component.invoke.invoke_id = 54, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_ExplicitEctExecute, ++ .component.invoke.invoke_id = 55, ++ .component.invoke.args.etsi.ExplicitEctExecute.link_id = 23, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_RequestSubaddress, ++ .component.invoke.invoke_id = 56, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_SubaddressTransfer, ++ .component.invoke.invoke_id = 57, ++ .component.invoke.args.etsi.SubaddressTransfer.subaddress.type = 1, ++ .component.invoke.args.etsi.SubaddressTransfer.subaddress.length = 4, ++ .component.invoke.args.etsi.SubaddressTransfer.subaddress.u.nsap = "6492", ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_EctLinkIdRequest, ++ .component.invoke.invoke_id = 58, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_EctLinkIdRequest, ++ .component.result.invoke_id = 59, ++ .component.result.args.etsi.EctLinkIdRequest.link_id = 76, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_EctInform, ++ .component.invoke.invoke_id = 60, ++ .component.invoke.args.etsi.EctInform.status = 1, ++ .component.invoke.args.etsi.EctInform.redirection_present = 1, ++ .component.invoke.args.etsi.EctInform.redirection.presentation = 0, ++ .component.invoke.args.etsi.EctInform.redirection.number.plan = 8, ++ .component.invoke.args.etsi.EctInform.redirection.number.length = 4, ++ .component.invoke.args.etsi.EctInform.redirection.number.str = "6229", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_EctInform, ++ .component.invoke.invoke_id = 61, ++ .component.invoke.args.etsi.EctInform.status = 1, ++ .component.invoke.args.etsi.EctInform.redirection_present = 1, ++ .component.invoke.args.etsi.EctInform.redirection.presentation = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_EctInform, ++ .component.invoke.invoke_id = 62, ++ .component.invoke.args.etsi.EctInform.status = 1, ++ .component.invoke.args.etsi.EctInform.redirection_present = 1, ++ .component.invoke.args.etsi.EctInform.redirection.presentation = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_EctInform, ++ .component.invoke.invoke_id = 63, ++ .component.invoke.args.etsi.EctInform.status = 1, ++ .component.invoke.args.etsi.EctInform.redirection_present = 1, ++ .component.invoke.args.etsi.EctInform.redirection.presentation = 3, ++ .component.invoke.args.etsi.EctInform.redirection.number.plan = 8, ++ .component.invoke.args.etsi.EctInform.redirection.number.length = 4, ++ .component.invoke.args.etsi.EctInform.redirection.number.str = "3340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_EctInform, ++ .component.invoke.invoke_id = 64, ++ .component.invoke.args.etsi.EctInform.status = 1, ++ .component.invoke.args.etsi.EctInform.redirection_present = 0, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_ETSI_EctLoopTest, ++ .component.invoke.invoke_id = 65, ++ .component.invoke.args.etsi.EctLoopTest.call_transfer_id = 7, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_ETSI_EctLoopTest, ++ .component.result.invoke_id = 66, ++ .component.result.args.etsi.EctLoopTest.loop_result = 2, ++ }, ++/* *INDENT-ON* */ ++}; ++ ++static unsigned char rose_etsi_indefinite_len[] = { ++/* *INDENT-OFF* */ ++/* ++ * Context Specific/C [1 0x01] <A1> Len:24 <80> ++ * Integer(2 0x02) <02> Len:1 <01> ++ * <44> ++ * Integer(2 0x02) <02> Len:1 <01> ++ * <07> ++ * Sequence/C(48 0x30) <30> Len:16 <80> ++ * Enumerated(10 0x0A) <0A> Len:1 <01> ++ * <01> ++ * Enumerated(10 0x0A) <0A> Len:1 <01> ++ * <05> ++ * Sequence/C(48 0x30) <30> Len:6 <80> ++ * Context Specific [4 0x04] <84> Len:4 <80> ++ * <31 38 30 33> ++ * 0x00, 0x00, ++ * 0x00, 0x00, ++ * NULL(5 0x05) <05> Len:0 <00> ++ * 0x00, 0x00, ++ * 0x00, 0x00 ++ */ ++ 0x91, ++ 0xA1, 0x80, ++ 0x02, 0x01, ++ 0x44, ++ 0x02, 0x01, ++ 0x07, ++ 0x30, 0x80, ++ 0x0A, 0x01, ++ 0x01, ++ 0x0A, 0x01, ++ 0x05, ++ 0x30, 0x80, ++ 0x84, 0x80, ++ 0x31, 0x38, 0x30, 0x33, ++ 0x00, 0x00, ++ 0x00, 0x00, ++ 0x05, 0x00, ++ 0x00, 0x00, ++ 0x00, 0x00, ++ 0x00, 0x00 ++/* *INDENT-ON* */ ++}; ++ ++static unsigned char rose_etsi_unused_indefinite_len[] = { ++/* *INDENT-OFF* */ ++/* ++ * Context Specific/C [1 0x01] <A1> Len:24 <80> ++ * Integer(2 0x02) <02> Len:1 <01> ++ * <44> ++ * Integer(2 0x02) <02> Len:1 <01> ++ * <06> -- EctExecute ++ * Sequence/C(48 0x30) <30> Len:16 <80> ++ * Enumerated(10 0x0A) <0A> Len:1 <01> ++ * <01> ++ * Enumerated(10 0x0A) <0A> Len:1 <01> ++ * <05> ++ * Sequence/C(48 0x30) <30> Len:6 <80> ++ * Context Specific [4 0x04] <84> Len:4 <80> ++ * <31 38 30 33> ++ * 0x00, 0x00, ++ * 0x00, 0x00, ++ * NULL(5 0x05) <05> Len:0 <00> ++ * 0x00, 0x00, ++ * 0x00, 0x00 ++ */ ++ 0x91, ++ 0xA1, 0x80, ++ 0x02, 0x01, ++ 0x44, ++ 0x02, 0x01, ++ 0x06, ++ 0x30, 0x80, ++ 0x0A, 0x01, ++ 0x01, ++ 0x0A, 0x01, ++ 0x05, ++ 0x30, 0x80, ++ 0x84, 0x80, ++ 0x31, 0x38, 0x30, 0x33, ++ 0x00, 0x00, ++ 0x00, 0x00, ++ 0x05, 0x00, ++ 0x00, 0x00, ++ 0x00, 0x00, ++ 0x00, 0x00 ++/* *INDENT-ON* */ ++}; ++ ++static unsigned char rose_etsi_unused[] = { ++/* *INDENT-OFF* */ ++/* ++ * Context Specific/C [1 0x01] <A1> Len:24 <18> ++ * Integer(2 0x02) <02> Len:1 <01> ++ * <44> ++ * Integer(2 0x02) <02> Len:1 <01> ++ * <06> -- EctExecute ++ * Sequence/C(48 0x30) <30> Len:16 <10> ++ * Enumerated(10 0x0A) <0A> Len:1 <01> ++ * <01> ++ * Enumerated(10 0x0A) <0A> Len:1 <01> ++ * <05> ++ * Sequence/C(48 0x30) <30> Len:6 <06> ++ * Context Specific [4 0x04] <84> Len:4 <04> ++ * <31 38 30 33> ++ * NULL(5 0x05) <05> Len:0 <00> ++ */ ++ 0x91, ++ 0xA1, 0x18, ++ 0x02, 0x01, ++ 0x44, ++ 0x02, 0x01, ++ 0x06, ++ 0x30, 0x10, ++ 0x0A, 0x01, ++ 0x01, ++ 0x0A, 0x01, ++ 0x05, ++ 0x30, 0x06, ++ 0x84, 0x04, ++ 0x31, 0x38, 0x30, 0x33, ++ 0x05, 0x00, ++ 0x00, 0x00 ++/* *INDENT-ON* */ ++}; ++ ++static unsigned char rose_etsi_extra[] = { ++/* *INDENT-OFF* */ ++/* ++ * Context Specific/C [1 0x01] <A1> Len:24 <18> ++ * Integer(2 0x02) <02> Len:1 <01> ++ * <44> ++ * Integer(2 0x02) <02> Len:1 <01> ++ * <07> ++ * Sequence/C(48 0x30) <30> Len:16 <10> ++ * Enumerated(10 0x0A) <0A> Len:1 <01> ++ * <01> ++ * Enumerated(10 0x0A) <0A> Len:1 <01> ++ * <05> ++ * Sequence/C(48 0x30) <30> Len:6 <06> ++ * Context Specific [4 0x04] <84> Len:4 <04> ++ * <31 38 30 33> ++ * NULL(5 0x05) <05> Len:0 <00> ++ */ ++ 0x91, ++ 0xA1, 0x18, ++ 0x02, 0x01, ++ 0x44, ++ 0x02, 0x01, ++ 0x07, ++ 0x30, 0x10, ++ 0x0A, 0x01, ++ 0x01, ++ 0x0A, 0x01, ++ 0x05, ++ 0x30, 0x06, ++ 0x84, 0x04, ++ 0x31, 0x38, 0x30, 0x33, ++ 0x05, 0x00, ++ 0x00, 0x00 ++/* *INDENT-ON* */ ++}; ++ ++ ++static const struct rose_message rose_qsig_msgs[] = { ++/* *INDENT-OFF* */ ++ /* Q.SIG Name-Operations */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallingName, ++ .component.invoke.invoke_id = 2, ++ .component.invoke.args.qsig.CallingName.name.presentation = 1, ++ .component.invoke.args.qsig.CallingName.name.char_set = 1, ++ .component.invoke.args.qsig.CallingName.name.length = 7, ++ .component.invoke.args.qsig.CallingName.name.data = "Alphred", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallingName, ++ .component.invoke.invoke_id = 3, ++ .component.invoke.args.qsig.CallingName.name.presentation = 1, ++ .component.invoke.args.qsig.CallingName.name.char_set = 3, ++ .component.invoke.args.qsig.CallingName.name.length = 7, ++ .component.invoke.args.qsig.CallingName.name.data = "Alphred", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallingName, ++ .component.invoke.invoke_id = 4, ++ .component.invoke.args.qsig.CallingName.name.presentation = 2, ++ .component.invoke.args.qsig.CallingName.name.char_set = 1, ++ .component.invoke.args.qsig.CallingName.name.length = 7, ++ .component.invoke.args.qsig.CallingName.name.data = "Alphred", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallingName, ++ .component.invoke.invoke_id = 5, ++ .component.invoke.args.qsig.CallingName.name.presentation = 2, ++ .component.invoke.args.qsig.CallingName.name.char_set = 3, ++ .component.invoke.args.qsig.CallingName.name.length = 7, ++ .component.invoke.args.qsig.CallingName.name.data = "Alphred", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallingName, ++ .component.invoke.invoke_id = 6, ++ .component.invoke.args.qsig.CallingName.name.presentation = 3, ++ .component.invoke.args.qsig.CallingName.name.char_set = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallingName, ++ .component.invoke.invoke_id = 7, ++ .component.invoke.args.qsig.CallingName.name.presentation = 4, ++ .component.invoke.args.qsig.CallingName.name.char_set = 1, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CalledName, ++ .component.invoke.invoke_id = 8, ++ .component.invoke.args.qsig.CallingName.name.presentation = 4, ++ .component.invoke.args.qsig.CallingName.name.char_set = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_ConnectedName, ++ .component.invoke.invoke_id = 9, ++ .component.invoke.args.qsig.CallingName.name.presentation = 4, ++ .component.invoke.args.qsig.CallingName.name.char_set = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_BusyName, ++ .component.invoke.invoke_id = 10, ++ .component.invoke.args.qsig.CallingName.name.presentation = 4, ++ .component.invoke.args.qsig.CallingName.name.char_set = 1, ++ }, ++ ++ /* Q.SIG SS-AOC-Operations */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_ChargeRequest, ++ .component.invoke.invoke_id = 11, ++ .component.invoke.args.qsig.ChargeRequest.num_records = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_ChargeRequest, ++ .component.invoke.invoke_id = 12, ++ .component.invoke.args.qsig.ChargeRequest.num_records = 1, ++ .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[0] = 3, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_ChargeRequest, ++ .component.invoke.invoke_id = 13, ++ .component.invoke.args.qsig.ChargeRequest.num_records = 2, ++ .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[0] = 4, ++ .component.invoke.args.qsig.ChargeRequest.advice_mode_combinations[1] = 3, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_ChargeRequest, ++ .component.result.invoke_id = 14, ++ .component.result.args.qsig.ChargeRequest.advice_mode_combination = 3, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_GetFinalCharge, ++ .component.invoke.invoke_id = 15, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocFinal, ++ .component.invoke.invoke_id = 16, ++ .component.invoke.args.qsig.AocFinal.type = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocFinal, ++ .component.invoke.invoke_id = 17, ++ .component.invoke.args.qsig.AocFinal.type = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocFinal, ++ .component.invoke.invoke_id = 18, ++ .component.invoke.args.qsig.AocFinal.type = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocFinal, ++ .component.invoke.invoke_id = 19, ++ .component.invoke.args.qsig.AocFinal.type = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", ++ .component.invoke.args.qsig.AocFinal.specific.billing_id_present = 1, ++ .component.invoke.args.qsig.AocFinal.specific.billing_id = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocFinal, ++ .component.invoke.invoke_id = 20, ++ .component.invoke.args.qsig.AocFinal.type = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", ++ .component.invoke.args.qsig.AocFinal.charging_association_present = 1, ++ .component.invoke.args.qsig.AocFinal.charging_association.type = 0, ++ .component.invoke.args.qsig.AocFinal.charging_association.id = 200, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocFinal, ++ .component.invoke.invoke_id = 21, ++ .component.invoke.args.qsig.AocFinal.type = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", ++ .component.invoke.args.qsig.AocFinal.specific.billing_id_present = 1, ++ .component.invoke.args.qsig.AocFinal.specific.billing_id = 2, ++ .component.invoke.args.qsig.AocFinal.charging_association_present = 1, ++ .component.invoke.args.qsig.AocFinal.charging_association.type = 0, ++ .component.invoke.args.qsig.AocFinal.charging_association.id = 200, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocFinal, ++ .component.invoke.invoke_id = 22, ++ .component.invoke.args.qsig.AocFinal.type = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.currency = 800, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.amount.multiplier = 2, ++ .component.invoke.args.qsig.AocFinal.specific.recorded.currency = "Rupies", ++ .component.invoke.args.qsig.AocFinal.charging_association_present = 1, ++ .component.invoke.args.qsig.AocFinal.charging_association.type = 1, ++ .component.invoke.args.qsig.AocFinal.charging_association.number.plan = 4, ++ .component.invoke.args.qsig.AocFinal.charging_association.number.length = 4, ++ .component.invoke.args.qsig.AocFinal.charging_association.number.str = "1802", ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocInterim, ++ .component.invoke.invoke_id = 23, ++ .component.invoke.args.qsig.AocInterim.type = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocInterim, ++ .component.invoke.invoke_id = 24, ++ .component.invoke.args.qsig.AocInterim.type = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocInterim, ++ .component.invoke.invoke_id = 25, ++ .component.invoke.args.qsig.AocInterim.type = 2, ++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.currency = 800, ++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.multiplier = 2, ++ .component.invoke.args.qsig.AocInterim.specific.recorded.currency = "Rupies", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocInterim, ++ .component.invoke.invoke_id = 26, ++ .component.invoke.args.qsig.AocInterim.type = 2, ++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.currency = 800, ++ .component.invoke.args.qsig.AocInterim.specific.recorded.amount.multiplier = 2, ++ .component.invoke.args.qsig.AocInterim.specific.recorded.currency = "Rupies", ++ .component.invoke.args.qsig.AocInterim.specific.billing_id_present = 1, ++ .component.invoke.args.qsig.AocInterim.specific.billing_id = 2, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 27, ++ .component.invoke.args.qsig.AocRate.type = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 28, ++ .component.invoke.args.qsig.AocRate.type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 0, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.special_charging_code = 3, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 29, ++ .component.invoke.args.qsig.AocRate.type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.currency = "Dollars", ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.currency = 7, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.multiplier = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.charging_type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.length = 8, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.scale = 4, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 30, ++ .component.invoke.args.qsig.AocRate.type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.currency = "Dollars", ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.currency = 7, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.amount.multiplier = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.charging_type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.length = 8, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.time.scale = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity_present = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity.length = 20, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.duration.granularity.scale = 3, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 31, ++ .component.invoke.args.qsig.AocRate.type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 2, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.currency = "Euros", ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.currency = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.multiplier = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 32, ++ .component.invoke.args.qsig.AocRate.type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 3, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.currency = "Yen", ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.amount.currency = 300, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.amount.multiplier = 5, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.volume_rate.unit = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 33, ++ .component.invoke.args.qsig.AocRate.type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 2, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 2, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.currency = "Euros", ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.currency = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].u.flat_rate.amount.multiplier = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[1].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[1].currency_type = 3, ++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.currency = "Yen", ++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.amount.currency = 300, ++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.amount.multiplier = 5, ++ .component.invoke.args.qsig.AocRate.currency_info.list[1].u.volume_rate.unit = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 34, ++ .component.invoke.args.qsig.AocRate.type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 4, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 35, ++ .component.invoke.args.qsig.AocRate.type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 5, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocRate, ++ .component.invoke.invoke_id = 36, ++ .component.invoke.args.qsig.AocRate.type = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.num_records = 1, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].charged_item = 4, ++ .component.invoke.args.qsig.AocRate.currency_info.list[0].currency_type = 6, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocComplete, ++ .component.invoke.invoke_id = 37, ++ .component.invoke.args.qsig.AocComplete.charged_user_number.plan = 4, ++ .component.invoke.args.qsig.AocComplete.charged_user_number.length = 4, ++ .component.invoke.args.qsig.AocComplete.charged_user_number.str = "8340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocComplete, ++ .component.invoke.invoke_id = 38, ++ .component.invoke.args.qsig.AocComplete.charged_user_number.plan = 4, ++ .component.invoke.args.qsig.AocComplete.charged_user_number.length = 4, ++ .component.invoke.args.qsig.AocComplete.charged_user_number.str = "8340", ++ .component.invoke.args.qsig.AocComplete.charging_association_present = 1, ++ .component.invoke.args.qsig.AocComplete.charging_association.type = 0, ++ .component.invoke.args.qsig.AocComplete.charging_association.id = 8298, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_AocComplete, ++ .component.result.invoke_id = 39, ++ .component.result.args.qsig.AocComplete.charging_option = 2, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocDivChargeReq, ++ .component.invoke.invoke_id = 40, ++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.plan = 4, ++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.length = 4, ++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.str = "8340", ++ .component.invoke.args.qsig.AocDivChargeReq.diversion_type = 3, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_AocDivChargeReq, ++ .component.invoke.invoke_id = 41, ++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.plan = 4, ++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.length = 4, ++ .component.invoke.args.qsig.AocDivChargeReq.diverting_user_number.str = "8340", ++ .component.invoke.args.qsig.AocDivChargeReq.charging_association_present = 1, ++ .component.invoke.args.qsig.AocDivChargeReq.charging_association.type = 0, ++ .component.invoke.args.qsig.AocDivChargeReq.charging_association.id = 8298, ++ .component.invoke.args.qsig.AocDivChargeReq.diversion_type = 3, ++ }, ++ ++ /* Q.SIG Call-Transfer-Operations (CT) */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferIdentify, ++ .component.invoke.invoke_id = 42, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_CallTransferIdentify, ++ .component.result.invoke_id = 43, ++ .component.result.args.qsig.CallTransferIdentify.call_id = "2345", ++ .component.result.args.qsig.CallTransferIdentify.rerouting_number.plan = 4, ++ .component.result.args.qsig.CallTransferIdentify.rerouting_number.length = 4, ++ .component.result.args.qsig.CallTransferIdentify.rerouting_number.str = "8340", ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferAbandon, ++ .component.invoke.invoke_id = 44, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferInitiate, ++ .component.invoke.invoke_id = 45, ++ .component.invoke.args.qsig.CallTransferInitiate.call_id = "2345", ++ .component.invoke.args.qsig.CallTransferInitiate.rerouting_number.plan = 4, ++ .component.invoke.args.qsig.CallTransferInitiate.rerouting_number.length = 4, ++ .component.invoke.args.qsig.CallTransferInitiate.rerouting_number.str = "8340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_CallTransferInitiate, ++ .component.result.invoke_id = 46, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferSetup, ++ .component.invoke.invoke_id = 47, ++ .component.invoke.args.qsig.CallTransferSetup.call_id = "23", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_CallTransferSetup, ++ .component.result.invoke_id = 48, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferActive, ++ .component.invoke.invoke_id = 49, ++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferActive, ++ .component.invoke.invoke_id = 50, ++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1, ++ .component.invoke.args.qsig.CallTransferActive.q931ie.length = 2, ++ .component.invoke.args.qsig.CallTransferActive.q931ie_contents = "RT", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferActive, ++ .component.invoke.invoke_id = 51, ++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1, ++ .component.invoke.args.qsig.CallTransferActive.connected_name_present = 1, ++ .component.invoke.args.qsig.CallTransferActive.connected_name.presentation = 1, ++ .component.invoke.args.qsig.CallTransferActive.connected_name.char_set = 1, ++ .component.invoke.args.qsig.CallTransferActive.connected_name.length = 7, ++ .component.invoke.args.qsig.CallTransferActive.connected_name.data = "Alphred", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferActive, ++ .component.invoke.invoke_id = 52, ++ .component.invoke.args.qsig.CallTransferActive.connected.presentation = 1, ++ .component.invoke.args.qsig.CallTransferActive.q931ie.length = 2, ++ .component.invoke.args.qsig.CallTransferActive.q931ie_contents = "RT", ++ .component.invoke.args.qsig.CallTransferActive.connected_name_present = 1, ++ .component.invoke.args.qsig.CallTransferActive.connected_name.presentation = 1, ++ .component.invoke.args.qsig.CallTransferActive.connected_name.char_set = 1, ++ .component.invoke.args.qsig.CallTransferActive.connected_name.length = 7, ++ .component.invoke.args.qsig.CallTransferActive.connected_name.data = "Alphred", ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete, ++ .component.invoke.invoke_id = 53, ++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 0, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.screening_indicator = 3, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.plan = 4, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.length = 4, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.str = "8340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete, ++ .component.invoke.invoke_id = 54, ++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete, ++ .component.invoke.invoke_id = 55, ++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete, ++ .component.invoke.invoke_id = 56, ++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 3, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.screening_indicator = 3, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.plan = 4, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.length = 4, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.screened.number.str = "8340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete, ++ .component.invoke.invoke_id = 57, ++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2, ++ .component.invoke.args.qsig.CallTransferComplete.q931ie.length = 2, ++ .component.invoke.args.qsig.CallTransferComplete.q931ie_contents = "RT", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete, ++ .component.invoke.invoke_id = 58, ++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2, ++ .component.invoke.args.qsig.CallTransferComplete.redirection_name_present = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.presentation = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.char_set = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.length = 7, ++ .component.invoke.args.qsig.CallTransferComplete.redirection_name.data = "Alphred", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete, ++ .component.invoke.invoke_id = 59, ++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2, ++ .component.invoke.args.qsig.CallTransferComplete.call_status = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferComplete, ++ .component.invoke.invoke_id = 60, ++ .component.invoke.args.qsig.CallTransferComplete.end_designation = 1, ++ .component.invoke.args.qsig.CallTransferComplete.redirection.presentation = 2, ++ .component.invoke.args.qsig.CallTransferComplete.q931ie.length = 2, ++ .component.invoke.args.qsig.CallTransferComplete.q931ie_contents = "RT", ++ .component.invoke.args.qsig.CallTransferComplete.call_status = 1, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate, ++ .component.invoke.invoke_id = 61, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate, ++ .component.invoke.invoke_id = 62, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name_present = 1, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.presentation = 1, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.char_set = 1, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.length = 7, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.data = "Alphred", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate, ++ .component.invoke.invoke_id = 63, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2, ++ .component.invoke.args.qsig.CallTransferUpdate.q931ie.length = 2, ++ .component.invoke.args.qsig.CallTransferUpdate.q931ie_contents = "RT", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallTransferUpdate, ++ .component.invoke.invoke_id = 64, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection.presentation = 2, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name_present = 1, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.presentation = 1, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.char_set = 1, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.length = 7, ++ .component.invoke.args.qsig.CallTransferUpdate.redirection_name.data = "Alphred", ++ .component.invoke.args.qsig.CallTransferUpdate.q931ie.length = 2, ++ .component.invoke.args.qsig.CallTransferUpdate.q931ie_contents = "RT", ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_SubaddressTransfer, ++ .component.invoke.invoke_id = 65, ++ .component.invoke.args.qsig.SubaddressTransfer.redirection_subaddress.type = 1, ++ .component.invoke.args.qsig.SubaddressTransfer.redirection_subaddress.length = 4, ++ .component.invoke.args.qsig.SubaddressTransfer.redirection_subaddress.u.nsap = "4356", ++ }, ++ ++ /* Q.SIG Call-Diversion-Operations */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_ActivateDiversionQ, ++ .component.invoke.invoke_id = 66, ++ .component.invoke.args.qsig.ActivateDiversionQ.procedure = 1, ++ .component.invoke.args.qsig.ActivateDiversionQ.basic_service = 3, ++ .component.invoke.args.qsig.ActivateDiversionQ.diverted_to.number.plan = 4, ++ .component.invoke.args.qsig.ActivateDiversionQ.diverted_to.number.length = 4, ++ .component.invoke.args.qsig.ActivateDiversionQ.diverted_to.number.str = "8340", ++ .component.invoke.args.qsig.ActivateDiversionQ.served_user_number.plan = 4, ++ .component.invoke.args.qsig.ActivateDiversionQ.served_user_number.length = 4, ++ .component.invoke.args.qsig.ActivateDiversionQ.served_user_number.str = "8340", ++ .component.invoke.args.qsig.ActivateDiversionQ.activating_user_number.plan = 4, ++ .component.invoke.args.qsig.ActivateDiversionQ.activating_user_number.length = 4, ++ .component.invoke.args.qsig.ActivateDiversionQ.activating_user_number.str = "8340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_ActivateDiversionQ, ++ .component.result.invoke_id = 67, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_DeactivateDiversionQ, ++ .component.invoke.invoke_id = 68, ++ .component.invoke.args.qsig.DeactivateDiversionQ.procedure = 1, ++ .component.invoke.args.qsig.DeactivateDiversionQ.basic_service = 3, ++ .component.invoke.args.qsig.DeactivateDiversionQ.served_user_number.plan = 4, ++ .component.invoke.args.qsig.DeactivateDiversionQ.served_user_number.length = 4, ++ .component.invoke.args.qsig.DeactivateDiversionQ.served_user_number.str = "8340", ++ .component.invoke.args.qsig.DeactivateDiversionQ.deactivating_user_number.plan = 4, ++ .component.invoke.args.qsig.DeactivateDiversionQ.deactivating_user_number.length = 4, ++ .component.invoke.args.qsig.DeactivateDiversionQ.deactivating_user_number.str = "8340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_DeactivateDiversionQ, ++ .component.result.invoke_id = 69, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_InterrogateDiversionQ, ++ .component.invoke.invoke_id = 70, ++ .component.invoke.args.qsig.InterrogateDiversionQ.procedure = 1, ++ .component.invoke.args.qsig.InterrogateDiversionQ.basic_service = 3, ++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.plan = 4, ++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.length = 4, ++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.str = "8340", ++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.plan = 4, ++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.length = 4, ++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.str = "8340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_InterrogateDiversionQ, ++ .component.invoke.invoke_id = 71, ++ .component.invoke.args.qsig.InterrogateDiversionQ.procedure = 1, ++ .component.invoke.args.qsig.InterrogateDiversionQ.basic_service = 0,/* default */ ++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.plan = 4, ++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.length = 4, ++ .component.invoke.args.qsig.InterrogateDiversionQ.served_user_number.str = "8340", ++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.plan = 4, ++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.length = 4, ++ .component.invoke.args.qsig.InterrogateDiversionQ.interrogating_user_number.str = "8340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ, ++ .component.result.invoke_id = 72, ++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ, ++ .component.result.invoke_id = 73, ++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 1, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.plan = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.length = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.str = "8340", ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].basic_service = 3, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].procedure = 2, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.plan = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.length = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.str = "8340", ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].remote_enabled = 0, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ, ++ .component.result.invoke_id = 74, ++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 1, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.plan = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.length = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.str = "8340", ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].basic_service = 3, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].procedure = 2, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.plan = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.length = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.str = "8340", ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].remote_enabled = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_InterrogateDiversionQ, ++ .component.result.invoke_id = 75, ++ .component.result.args.qsig.InterrogateDiversionQ.num_records = 2, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.plan = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.length = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].served_user_number.str = "8340", ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].basic_service = 3, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].procedure = 2, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.plan = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.length = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[0].diverted_to.number.str = "8340", ++ .component.result.args.qsig.InterrogateDiversionQ.list[1].served_user_number.plan = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[1].served_user_number.length = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[1].served_user_number.str = "8340", ++ .component.result.args.qsig.InterrogateDiversionQ.list[1].basic_service = 3, ++ .component.result.args.qsig.InterrogateDiversionQ.list[1].procedure = 2, ++ .component.result.args.qsig.InterrogateDiversionQ.list[1].diverted_to.number.plan = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[1].diverted_to.number.length = 4, ++ .component.result.args.qsig.InterrogateDiversionQ.list[1].diverted_to.number.str = "8340", ++ .component.result.args.qsig.InterrogateDiversionQ.list[1].remote_enabled = 1, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CheckRestriction, ++ .component.invoke.invoke_id = 76, ++ .component.invoke.args.qsig.CheckRestriction.served_user_number.plan = 4, ++ .component.invoke.args.qsig.CheckRestriction.served_user_number.length = 4, ++ .component.invoke.args.qsig.CheckRestriction.served_user_number.str = "8340", ++ .component.invoke.args.qsig.CheckRestriction.basic_service = 3, ++ .component.invoke.args.qsig.CheckRestriction.diverted_to_number.plan = 4, ++ .component.invoke.args.qsig.CheckRestriction.diverted_to_number.length = 4, ++ .component.invoke.args.qsig.CheckRestriction.diverted_to_number.str = "8340", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_CheckRestriction, ++ .component.result.invoke_id = 77, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallRerouting, ++ .component.invoke.invoke_id = 78, ++ .component.invoke.args.qsig.CallRerouting.rerouting_reason = 3, ++ .component.invoke.args.qsig.CallRerouting.called.number.plan = 4, ++ .component.invoke.args.qsig.CallRerouting.called.number.length = 4, ++ .component.invoke.args.qsig.CallRerouting.called.number.str = "8340", ++ .component.invoke.args.qsig.CallRerouting.diversion_counter = 5, ++ .component.invoke.args.qsig.CallRerouting.q931ie.length = 2, ++ .component.invoke.args.qsig.CallRerouting.q931ie_contents = "RT", ++ .component.invoke.args.qsig.CallRerouting.last_rerouting.presentation = 1, ++ .component.invoke.args.qsig.CallRerouting.subscription_option = 2, ++ .component.invoke.args.qsig.CallRerouting.calling.presentation = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CallRerouting, ++ .component.invoke.invoke_id = 79, ++ .component.invoke.args.qsig.CallRerouting.rerouting_reason = 3, ++ .component.invoke.args.qsig.CallRerouting.original_rerouting_reason_present = 1, ++ .component.invoke.args.qsig.CallRerouting.original_rerouting_reason = 2, ++ .component.invoke.args.qsig.CallRerouting.called.number.plan = 4, ++ .component.invoke.args.qsig.CallRerouting.called.number.length = 4, ++ .component.invoke.args.qsig.CallRerouting.called.number.str = "8340", ++ .component.invoke.args.qsig.CallRerouting.diversion_counter = 5, ++ .component.invoke.args.qsig.CallRerouting.q931ie.length = 2, ++ .component.invoke.args.qsig.CallRerouting.q931ie_contents = "RT", ++ .component.invoke.args.qsig.CallRerouting.last_rerouting.presentation = 1, ++ .component.invoke.args.qsig.CallRerouting.subscription_option = 2, ++ .component.invoke.args.qsig.CallRerouting.calling_subaddress.type = 1, ++ .component.invoke.args.qsig.CallRerouting.calling_subaddress.length = 4, ++ .component.invoke.args.qsig.CallRerouting.calling_subaddress.u.nsap = "3253", ++ .component.invoke.args.qsig.CallRerouting.calling.presentation = 1, ++ .component.invoke.args.qsig.CallRerouting.calling_name_present = 1, ++ .component.invoke.args.qsig.CallRerouting.calling_name.presentation = 4, ++ .component.invoke.args.qsig.CallRerouting.calling_name.char_set = 1, ++ .component.invoke.args.qsig.CallRerouting.original_called_present = 1, ++ .component.invoke.args.qsig.CallRerouting.original_called.presentation = 2, ++ .component.invoke.args.qsig.CallRerouting.redirecting_name_present = 1, ++ .component.invoke.args.qsig.CallRerouting.redirecting_name.presentation = 4, ++ .component.invoke.args.qsig.CallRerouting.redirecting_name.char_set = 1, ++ .component.invoke.args.qsig.CallRerouting.original_called_name_present = 1, ++ .component.invoke.args.qsig.CallRerouting.original_called_name.presentation = 4, ++ .component.invoke.args.qsig.CallRerouting.original_called_name.char_set = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_CallRerouting, ++ .component.result.invoke_id = 80, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation1, ++ .component.invoke.invoke_id = 81, ++ .component.invoke.args.qsig.DivertingLegInformation1.diversion_reason = 3, ++ .component.invoke.args.qsig.DivertingLegInformation1.subscription_option = 1, ++ .component.invoke.args.qsig.DivertingLegInformation1.nominated_number.plan = 4, ++ .component.invoke.args.qsig.DivertingLegInformation1.nominated_number.length = 4, ++ .component.invoke.args.qsig.DivertingLegInformation1.nominated_number.str = "8340", ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation2, ++ .component.invoke.invoke_id = 82, ++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_counter = 6, ++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_reason = 3, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation2, ++ .component.invoke.invoke_id = 83, ++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_counter = 6, ++ .component.invoke.args.qsig.DivertingLegInformation2.diversion_reason = 3, ++ .component.invoke.args.qsig.DivertingLegInformation2.original_diversion_reason_present = 1, ++ .component.invoke.args.qsig.DivertingLegInformation2.original_diversion_reason = 2, ++ .component.invoke.args.qsig.DivertingLegInformation2.diverting_present = 1, ++ .component.invoke.args.qsig.DivertingLegInformation2.diverting.presentation = 2, ++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_present = 1, ++ .component.invoke.args.qsig.DivertingLegInformation2.original_called.presentation = 2, ++ .component.invoke.args.qsig.DivertingLegInformation2.redirecting_name_present = 1, ++ .component.invoke.args.qsig.DivertingLegInformation2.redirecting_name.presentation = 4, ++ .component.invoke.args.qsig.DivertingLegInformation2.redirecting_name.char_set = 1, ++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_name_present = 1, ++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_name.presentation = 4, ++ .component.invoke.args.qsig.DivertingLegInformation2.original_called_name.char_set = 1, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation3, ++ .component.invoke.invoke_id = 84, ++ .component.invoke.args.qsig.DivertingLegInformation3.presentation_allowed_indicator = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_DivertingLegInformation3, ++ .component.invoke.invoke_id = 85, ++ .component.invoke.args.qsig.DivertingLegInformation3.presentation_allowed_indicator = 1, ++ .component.invoke.args.qsig.DivertingLegInformation3.redirection_name_present = 1, ++ .component.invoke.args.qsig.DivertingLegInformation3.redirection_name.presentation = 4, ++ .component.invoke.args.qsig.DivertingLegInformation3.redirection_name.char_set = 1, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_CfnrDivertedLegFailed, ++ .component.invoke.invoke_id = 86, ++ }, ++ ++ /* Q.SIG SS-MWI-Operations */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_MWIActivate, ++ .component.invoke.invoke_id = 102, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838", ++ .component.invoke.args.qsig.MWIActivate.basic_service = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_MWIActivate, ++ .component.invoke.invoke_id = 103, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838", ++ .component.invoke.args.qsig.MWIActivate.basic_service = 1, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id_present = 1, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.type = 0, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.integer = 532, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_MWIActivate, ++ .component.invoke.invoke_id = 104, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838", ++ .component.invoke.args.qsig.MWIActivate.basic_service = 1, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id_present = 1, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.type = 1, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.number.plan = 4, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.number.length = 4, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.number.str = "9838", ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_MWIActivate, ++ .component.invoke.invoke_id = 105, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.plan = 4, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.length = 4, ++ .component.invoke.args.qsig.MWIActivate.served_user_number.str = "9838", ++ .component.invoke.args.qsig.MWIActivate.basic_service = 1, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id_present = 1, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.type = 2, ++ .component.invoke.args.qsig.MWIActivate.msg_centre_id.u.str = "123456", ++ .component.invoke.args.qsig.MWIActivate.number_of_messages_present = 1, ++ .component.invoke.args.qsig.MWIActivate.number_of_messages = 6548, ++ .component.invoke.args.qsig.MWIActivate.originating_number.plan = 4, ++ .component.invoke.args.qsig.MWIActivate.originating_number.length = 4, ++ .component.invoke.args.qsig.MWIActivate.originating_number.str = "9838", ++ .component.invoke.args.qsig.MWIActivate.timestamp_present = 1, ++ .component.invoke.args.qsig.MWIActivate.timestamp = "19970621194530", ++ .component.invoke.args.qsig.MWIActivate.priority_present = 1, ++ .component.invoke.args.qsig.MWIActivate.priority = 7, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_MWIActivate, ++ .component.result.invoke_id = 106, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_MWIDeactivate, ++ .component.invoke.invoke_id = 107, ++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.plan = 4, ++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.length = 4, ++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.str = "9838", ++ .component.invoke.args.qsig.MWIDeactivate.basic_service = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_MWIDeactivate, ++ .component.invoke.invoke_id = 108, ++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.plan = 4, ++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.length = 4, ++ .component.invoke.args.qsig.MWIDeactivate.served_user_number.str = "9838", ++ .component.invoke.args.qsig.MWIDeactivate.basic_service = 1, ++ .component.invoke.args.qsig.MWIDeactivate.msg_centre_id_present = 1, ++ .component.invoke.args.qsig.MWIDeactivate.msg_centre_id.type = 0, ++ .component.invoke.args.qsig.MWIDeactivate.msg_centre_id.u.integer = 532, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_MWIDeactivate, ++ .component.result.invoke_id = 109, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_MWIInterrogate, ++ .component.invoke.invoke_id = 110, ++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.plan = 4, ++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.length = 4, ++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.str = "9838", ++ .component.invoke.args.qsig.MWIInterrogate.basic_service = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_QSIG_MWIInterrogate, ++ .component.invoke.invoke_id = 111, ++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.plan = 4, ++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.length = 4, ++ .component.invoke.args.qsig.MWIInterrogate.served_user_number.str = "9838", ++ .component.invoke.args.qsig.MWIInterrogate.basic_service = 1, ++ .component.invoke.args.qsig.MWIInterrogate.msg_centre_id_present = 1, ++ .component.invoke.args.qsig.MWIInterrogate.msg_centre_id.type = 0, ++ .component.invoke.args.qsig.MWIInterrogate.msg_centre_id.u.integer = 532, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_MWIInterrogate, ++ .component.result.invoke_id = 112, ++ .component.result.args.qsig.MWIInterrogate.num_records = 1, ++ .component.result.args.qsig.MWIInterrogate.list[0].basic_service = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_QSIG_MWIInterrogate, ++ .component.result.invoke_id = 113, ++ .component.result.args.qsig.MWIInterrogate.num_records = 2, ++ .component.result.args.qsig.MWIInterrogate.list[0].basic_service = 1, ++ .component.result.args.qsig.MWIInterrogate.list[0].msg_centre_id_present = 1, ++ .component.result.args.qsig.MWIInterrogate.list[0].msg_centre_id.type = 0, ++ .component.result.args.qsig.MWIInterrogate.list[0].msg_centre_id.u.integer = 987, ++ .component.result.args.qsig.MWIInterrogate.list[0].number_of_messages_present = 1, ++ .component.result.args.qsig.MWIInterrogate.list[0].number_of_messages = 6548, ++ .component.result.args.qsig.MWIInterrogate.list[0].originating_number.plan = 4, ++ .component.result.args.qsig.MWIInterrogate.list[0].originating_number.length = 4, ++ .component.result.args.qsig.MWIInterrogate.list[0].originating_number.str = "9838", ++ .component.result.args.qsig.MWIInterrogate.list[0].timestamp_present = 1, ++ .component.result.args.qsig.MWIInterrogate.list[0].timestamp = "19970621194530", ++ .component.result.args.qsig.MWIInterrogate.list[0].priority_present = 1, ++ .component.result.args.qsig.MWIInterrogate.list[0].priority = 7, ++ .component.result.args.qsig.MWIInterrogate.list[1].basic_service = 1, ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++static const struct rose_message rose_dms100_msgs[] = { ++/* *INDENT-OFF* */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_DMS100_RLT_OperationInd, ++ .component.invoke.invoke_id = ROSE_DMS100_RLT_OPERATION_IND, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_DMS100_RLT_OperationInd, ++ .component.result.invoke_id = ROSE_DMS100_RLT_OPERATION_IND, ++ .component.result.args.dms100.RLT_OperationInd.call_id = 130363, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_DMS100_RLT_ThirdParty, ++ .component.invoke.invoke_id = ROSE_DMS100_RLT_THIRD_PARTY, ++ .component.invoke.args.dms100.RLT_ThirdParty.call_id = 120047, ++ .component.invoke.args.dms100.RLT_ThirdParty.reason = 1, ++ }, ++ { ++ .type = ROSE_COMP_TYPE_RESULT, ++ .component.result.operation = ROSE_DMS100_RLT_ThirdParty, ++ .component.result.invoke_id = ROSE_DMS100_RLT_THIRD_PARTY, ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++static const struct rose_message rose_ni2_msgs[] = { ++/* *INDENT-OFF* */ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_NI2_InformationFollowing, ++ .component.invoke.invoke_id = 1, ++ .component.invoke.args.ni2.InformationFollowing.value = 7, ++ }, ++ ++ { ++ .type = ROSE_COMP_TYPE_INVOKE, ++ .component.invoke.operation = ROSE_NI2_InitiateTransfer, ++ .component.invoke.invoke_id = 2, ++ .component.invoke.args.ni2.InitiateTransfer.call_reference = 5, ++ }, ++/* *INDENT-ON* */ ++}; ++ ++/* ------------------------------------------------------------------- */ ++ ++static void rose_pri_message(struct pri *ctrl, char *stuff) ++{ ++ fprintf(stdout, "%s", stuff); ++} ++ ++static void rose_pri_error(struct pri *ctrl, char *stuff) ++{ ++ fprintf(stdout, "%s", stuff); ++ fprintf(stderr, "%s", stuff); ++} ++ ++/*! ++ * \internal ++ * \brief Test ROSE encoding and decoding the given message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param index Message number to report. ++ * \param header Facility message header data to encode. ++ * \param encode_msg Message data to encode. ++ * ++ * \return Nothing ++ */ ++static void rose_test_msg(struct pri *ctrl, unsigned index, ++ const struct fac_extension_header *header, const struct rose_message *encode_msg) ++{ ++ struct fac_extension_header decoded_header; ++ struct rose_message decoded_msg; ++ unsigned char *enc_pos; ++ unsigned char *enc_end; ++ const unsigned char *dec_pos; ++ const unsigned char *dec_end; ++ ++ static unsigned char buf[1024]; ++ ++ pri_message(ctrl, "\n\n"); ++ enc_end = buf + sizeof(buf); ++ enc_pos = facility_encode_header(ctrl, buf, enc_end, header); ++ if (!enc_pos) { ++ pri_error(ctrl, "Error: Message:%u failed to encode header\n", index); ++ } else { ++ enc_pos = rose_encode(ctrl, enc_pos, enc_end, encode_msg); ++ if (!enc_pos) { ++ pri_error(ctrl, "Error: Message:%u failed to encode ROSE\n", index); ++ } else { ++ pri_message(ctrl, "Message %u encoded length is %u\n", index, ++ (unsigned) (enc_pos - buf)); ++ ++ /* Clear the decoded message contents for comparison. */ ++ memset(&decoded_header, 0, sizeof(decoded_header)); ++ memset(&decoded_msg, 0, sizeof(decoded_msg)); ++ ++ dec_end = enc_pos; ++ dec_pos = facility_decode_header(ctrl, buf, dec_end, &decoded_header); ++ if (!dec_pos) { ++ pri_error(ctrl, "Error: Message:%u failed to decode header\n", index); ++ } else { ++ dec_pos = rose_decode(ctrl, dec_pos, dec_end, &decoded_msg); ++ if (!dec_pos) { ++ pri_error(ctrl, "Error: Message:%u failed to decode ROSE\n", index); ++ } else { ++ if (header ++ && memcmp(header, &decoded_header, sizeof(decoded_header))) { ++ pri_error(ctrl, "Error: Message:%u Header did not match\n", ++ index); ++ } ++ if (memcmp(encode_msg, &decoded_msg, sizeof(decoded_msg))) { ++ pri_error(ctrl, "Error: Message:%u ROSE did not match\n", index); ++ } ++ } ++ } ++ } ++ } ++ pri_message(ctrl, "\n\n" ++ "************************************************************\n"); ++} ++ ++/*! ++ * \internal ++ * \brief Test ROSE decoding messages of unusual encodings. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param name Test name for the encoded message. ++ * \param msg_buf Encoded message to decode. ++ * \param msg_len Length of encoded message buffer. ++ * ++ * \return Nothing ++ */ ++static void rose_test_exception(struct pri *ctrl, const char *name, ++ const unsigned char *msg, size_t msg_len) ++{ ++ const unsigned char *pos; ++ const unsigned char *end; ++ struct fac_extension_header header; ++ struct rose_message decoded_msg; ++ ++ pri_message(ctrl, "\n\n" ++ "%s test: Message encoded length is %u\n", name, (unsigned) msg_len); ++ ++ pos = msg; ++ end = msg + msg_len; ++ pos = facility_decode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ pri_error(ctrl, "Error: %s test: Message failed to decode header\n", name); ++ } else { ++ pos = rose_decode(ctrl, pos, end, &decoded_msg); ++ if (!pos) { ++ pri_error(ctrl, "Error: %s test: Message failed to decode ROSE\n", name); ++ } ++ } ++ ++ pri_message(ctrl, "\n\n" ++ "************************************************************\n"); ++} ++ ++/*! ++ * \brief ROSE encode/decode test program. ++ * ++ * \param argc Program argument count. ++ * \param argv Program argument string array. ++ * ++ * \retval 0 on success. ++ * \retval Nonzero on error. ++ */ ++int main(int argc, char *argv[]) ++{ ++ unsigned index; ++ unsigned offset; ++ static struct pri dummy_ctrl; ++ ++ pri_set_message(rose_pri_message); ++ pri_set_error(rose_pri_error); ++ ++ memset(&dummy_ctrl, 0, sizeof(dummy_ctrl)); ++ dummy_ctrl.debug = PRI_DEBUG_APDU; ++ ++ offset = 0; ++ pri_message(&dummy_ctrl, "Encode/decode message(s)\n"); ++ if (argc <= 1) { ++ dummy_ctrl.switchtype = PRI_SWITCH_EUROISDN_E1; ++ for (index = 0; index < ARRAY_LEN(rose_etsi_msgs); ++index) { ++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0], ++ &rose_etsi_msgs[index]); ++ } ++ offset += ARRAY_LEN(rose_etsi_msgs); ++ ++ dummy_ctrl.switchtype = PRI_SWITCH_QSIG; ++ for (index = 0; index < ARRAY_LEN(rose_qsig_msgs); ++index) { ++ rose_test_msg(&dummy_ctrl, index + offset, ++ &fac_headers[index % ARRAY_LEN(fac_headers)], &rose_qsig_msgs[index]); ++ } ++ offset += ARRAY_LEN(rose_qsig_msgs); ++ ++ dummy_ctrl.switchtype = PRI_SWITCH_DMS100; ++ for (index = 0; index < ARRAY_LEN(rose_dms100_msgs); ++index) { ++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0], ++ &rose_dms100_msgs[index]); ++ } ++ offset += ARRAY_LEN(rose_dms100_msgs); ++ ++ dummy_ctrl.switchtype = PRI_SWITCH_NI2; ++ for (index = 0; index < ARRAY_LEN(rose_ni2_msgs); ++index) { ++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0], ++ &rose_ni2_msgs[index]); ++ } ++ //offset += ARRAY_LEN(rose_ni2_msgs); ++ } else { ++ index = atoi(argv[1]); ++ ++ if (index < ARRAY_LEN(rose_etsi_msgs)) { ++ dummy_ctrl.switchtype = PRI_SWITCH_EUROISDN_E1; ++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0], ++ &rose_etsi_msgs[index]); ++ return 0; ++ } ++ offset += ARRAY_LEN(rose_etsi_msgs); ++ index -= ARRAY_LEN(rose_etsi_msgs); ++ ++ if (index < ARRAY_LEN(rose_qsig_msgs)) { ++ dummy_ctrl.switchtype = PRI_SWITCH_QSIG; ++ rose_test_msg(&dummy_ctrl, index + offset, ++ &fac_headers[index % ARRAY_LEN(fac_headers)], &rose_qsig_msgs[index]); ++ return 0; ++ } ++ offset += ARRAY_LEN(rose_qsig_msgs); ++ index -= ARRAY_LEN(rose_qsig_msgs); ++ ++ if (index < ARRAY_LEN(rose_dms100_msgs)) { ++ dummy_ctrl.switchtype = PRI_SWITCH_DMS100; ++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0], ++ &rose_dms100_msgs[index]); ++ return 0; ++ } ++ offset += ARRAY_LEN(rose_dms100_msgs); ++ index -= ARRAY_LEN(rose_dms100_msgs); ++ ++ if (index < ARRAY_LEN(rose_ni2_msgs)) { ++ dummy_ctrl.switchtype = PRI_SWITCH_NI2; ++ rose_test_msg(&dummy_ctrl, index + offset, &fac_headers[0], ++ &rose_ni2_msgs[index]); ++ return 0; ++ } ++ //offset += ARRAY_LEN(rose_ni2_msgs); ++ //index -= ARRAY_LEN(rose_ni2_msgs); ++ ++ fprintf(stderr, "Invalid option\n"); ++ return 0; ++ } ++ ++/* ------------------------------------------------------------------- */ ++ ++ pri_message(&dummy_ctrl, "\n\n" ++ "Decode unusually encoded messages\n"); ++ ++ dummy_ctrl.switchtype = PRI_SWITCH_EUROISDN_E1; ++ ++ rose_test_exception(&dummy_ctrl, "Extra bytes on end", rose_etsi_extra, ++ sizeof(rose_etsi_extra)); ++ ++ rose_test_exception(&dummy_ctrl, "Indefinite length", rose_etsi_indefinite_len, ++ sizeof(rose_etsi_indefinite_len) - 2); ++ rose_test_exception(&dummy_ctrl, "Indefinite length (extra)", ++ rose_etsi_indefinite_len, sizeof(rose_etsi_indefinite_len)); ++ ++ rose_test_exception(&dummy_ctrl, "Unused components (indefinite length)", ++ rose_etsi_unused_indefinite_len, sizeof(rose_etsi_unused_indefinite_len) - 2); ++ rose_test_exception(&dummy_ctrl, "Unused components (indefinite length, extra)", ++ rose_etsi_unused_indefinite_len, sizeof(rose_etsi_unused_indefinite_len)); ++ ++ rose_test_exception(&dummy_ctrl, "Unused components", rose_etsi_unused, ++ sizeof(rose_etsi_unused) - 2); ++ rose_test_exception(&dummy_ctrl, "Unused components (extra)", rose_etsi_unused, ++ sizeof(rose_etsi_unused)); ++ ++/* ------------------------------------------------------------------- */ ++ ++ pri_message(&dummy_ctrl, "\n\n" ++ "List of operation codes:\n"); ++ for (index = 0; index < ROSE_Num_Operation_Codes; ++index) { ++ pri_message(&dummy_ctrl, "%d: %s\n", index, rose_operation2str(index)); ++ } ++ pri_message(&dummy_ctrl, "\n\n" ++ "************************************************************\n"); ++ ++/* ------------------------------------------------------------------- */ ++ ++ pri_message(&dummy_ctrl, "\n\n" ++ "List of error codes:\n"); ++ for (index = 0; index < ROSE_ERROR_Num_Codes; ++index) { ++ pri_message(&dummy_ctrl, "%d: %s\n", index, rose_error2str(index)); ++ } ++ pri_message(&dummy_ctrl, "\n\n" ++ "************************************************************\n"); ++ ++/* ------------------------------------------------------------------- */ ++ ++ pri_message(&dummy_ctrl, "\n\n"); ++ pri_message(&dummy_ctrl, "sizeof(struct rose_message) = %u\n", ++ (unsigned) sizeof(struct rose_message)); ++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_invoke) = %u\n", ++ (unsigned) sizeof(struct rose_msg_invoke)); ++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_result) = %u\n", ++ (unsigned) sizeof(struct rose_msg_result)); ++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_error) = %u\n", ++ (unsigned) sizeof(struct rose_msg_error)); ++ pri_message(&dummy_ctrl, "sizeof(struct rose_msg_reject) = %u\n", ++ (unsigned) sizeof(struct rose_msg_reject)); ++ pri_message(&dummy_ctrl, "sizeof(union rose_msg_invoke_args) = %u\n", ++ (unsigned) sizeof(union rose_msg_invoke_args)); ++ pri_message(&dummy_ctrl, "sizeof(union rose_msg_result_args) = %u\n", ++ (unsigned) sizeof(union rose_msg_result_args)); ++ ++ pri_message(&dummy_ctrl, "\n"); ++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigForwardingList) = %u\n", ++ (unsigned) sizeof(struct roseQsigForwardingList)); ++ ++ pri_message(&dummy_ctrl, "\n"); ++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigCallRerouting_ARG) = %u\n", ++ (unsigned) sizeof(struct roseQsigCallRerouting_ARG)); ++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigAocRateArg_ARG) = %u\n", ++ (unsigned) sizeof(struct roseQsigAocRateArg_ARG)); ++ pri_message(&dummy_ctrl, "sizeof(struct roseQsigMWIInterrogateRes) = %u\n", ++ (unsigned) sizeof(struct roseQsigMWIInterrogateRes)); ++ ++ pri_message(&dummy_ctrl, "\n"); ++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiForwardingList) = %u\n", ++ (unsigned) sizeof(struct roseEtsiForwardingList)); ++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiServedUserNumberList) = %u\n", ++ (unsigned) sizeof(struct roseEtsiServedUserNumberList)); ++ ++ pri_message(&dummy_ctrl, "\n"); ++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiCallRerouting_ARG) = %u\n", ++ (unsigned) sizeof(struct roseEtsiCallRerouting_ARG)); ++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiDiversionInformation_ARG) = %u\n", ++ (unsigned) sizeof(struct roseEtsiDiversionInformation_ARG)); ++ pri_message(&dummy_ctrl, "sizeof(struct roseEtsiAOCSCurrencyInfoList) = %u\n", ++ (unsigned) sizeof(struct roseEtsiAOCSCurrencyInfoList)); ++ ++/* ------------------------------------------------------------------- */ ++ ++ return 0; ++} ++ ++/* ------------------------------------------------------------------- */ ++/* end rosetest.c */ + +Property changes on: rosetest.c +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: rose_internal.h +=================================================================== +--- a/rose_internal.h (.../tags/1.4.10.2) (revision 0) ++++ b/rose_internal.h (.../branches/1.4) (revision 1357) +@@ -0,0 +1,477 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief Internal definitions and prototypes for ROSE. ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++#ifndef _LIBPRI_ROSE_INTERNAL_H ++#define _LIBPRI_ROSE_INTERNAL_H ++ ++#include "rose.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* Embedded-Q931-Types */ ++unsigned char *rose_enc_Q931ie(struct pri *ctrl, unsigned char *pos, unsigned char *end, ++ unsigned tag, const struct roseQ931ie *q931ie); ++ ++const unsigned char *rose_dec_Q931ie(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, struct roseQ931ie *q931ie, ++ size_t contents_size); ++ ++/* Addressing-Data-Elements */ ++unsigned char *rose_enc_PartyNumber(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePartyNumber *party_number); ++unsigned char *rose_enc_PartySubaddress(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePartySubaddress *party_subaddress); ++unsigned char *rose_enc_Address(struct pri *ctrl, unsigned char *pos, unsigned char *end, ++ unsigned tag, const struct roseAddress *address); ++unsigned char *rose_enc_PresentedNumberUnscreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePresentedNumberUnscreened *party); ++unsigned char *rose_enc_NumberScreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, unsigned tag, const struct roseNumberScreened *screened); ++unsigned char *rose_enc_PresentedNumberScreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePresentedNumberScreened *party); ++unsigned char *rose_enc_AddressScreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, unsigned tag, const struct roseAddressScreened *screened); ++unsigned char *rose_enc_PresentedAddressScreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePresentedAddressScreened *party); ++ ++const unsigned char *rose_dec_PartyNumber(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePartyNumber *party_number); ++const unsigned char *rose_dec_PartySubaddress(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePartySubaddress *party_subaddress); ++const unsigned char *rose_dec_Address(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, struct roseAddress *address); ++const unsigned char *rose_dec_PresentedNumberUnscreened(struct pri *ctrl, ++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePresentedNumberUnscreened *party); ++const unsigned char *rose_dec_NumberScreened(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct roseNumberScreened *screened); ++const unsigned char *rose_dec_PresentedNumberScreened(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePresentedNumberScreened *party); ++const unsigned char *rose_dec_AddressScreened(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct roseAddressScreened *screened); ++const unsigned char *rose_dec_PresentedAddressScreened(struct pri *ctrl, ++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePresentedAddressScreened *party); ++ ++/* ETSI Advice-of-Charge (AOC) */ ++unsigned char *rose_enc_etsi_ChargingRequest_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_ChargingRequest_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args); ++unsigned char *rose_enc_etsi_AOCSCurrency_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_AOCSSpecialArr_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_AOCDCurrency_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_AOCDChargingUnit_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_AOCECurrency_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_AOCEChargingUnit_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++ ++const unsigned char *rose_dec_etsi_ChargingRequest_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_ChargingRequest_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++const unsigned char *rose_dec_etsi_AOCSCurrency_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_AOCSSpecialArr_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_AOCDCurrency_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_AOCDChargingUnit_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_AOCECurrency_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_AOCEChargingUnit_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++ ++/* ETSI Call Diversion */ ++unsigned char *rose_enc_etsi_ActivationDiversion_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_DeactivationDiversion_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_ActivationStatusNotificationDiv_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_DeactivationStatusNotificationDiv_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_InterrogationDiversion_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_InterrogationDiversion_RES(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args); ++unsigned char *rose_enc_etsi_DiversionInformation_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_CallDeflection_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_CallRerouting_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_InterrogateServedUserNumbers_RES(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args); ++unsigned char *rose_enc_etsi_DivertingLegInformation1_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_DivertingLegInformation2_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_DivertingLegInformation3_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++ ++const unsigned char *rose_dec_etsi_ActivationDiversion_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_DeactivationDiversion_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_ActivationStatusNotificationDiv_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_DeactivationStatusNotificationDiv_ARG(struct pri ++ *ctrl, unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_InterrogationDiversion_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_InterrogationDiversion_RES(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++const unsigned char *rose_dec_etsi_DiversionInformation_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_CallDeflection_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_CallRerouting_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_InterrogateServedUserNumbers_RES(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++const unsigned char *rose_dec_etsi_DivertingLegInformation1_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_DivertingLegInformation2_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_DivertingLegInformation3_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++ ++/* ETSI Explicit Call Transfer (ECT) */ ++unsigned char *rose_enc_etsi_ExplicitEctExecute_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_SubaddressTransfer_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_EctLinkIdRequest_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args); ++unsigned char *rose_enc_etsi_EctInform_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_EctLoopTest_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_etsi_EctLoopTest_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args); ++ ++const unsigned char *rose_dec_etsi_ExplicitEctExecute_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_SubaddressTransfer_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_EctLinkIdRequest_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++const unsigned char *rose_dec_etsi_EctInform_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_EctLoopTest_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_etsi_EctLoopTest_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++ ++/* Q.SIG Name-Operations */ ++unsigned char *rose_enc_qsig_Name(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct roseQsigName *name); ++ ++const unsigned char *rose_dec_qsig_Name(struct pri *ctrl, const char *fname, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct roseQsigName *name); ++ ++unsigned char *rose_enc_qsig_CallingName_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_CalledName_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_ConnectedName_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_BusyName_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++ ++const unsigned char *rose_dec_qsig_CallingName_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_CalledName_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_ConnectedName_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_BusyName_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++ ++/* ++ * Q.SIG Dummy invoke/result argument used by: ++ * SS-AOC-Operations, ++ * Call-Transfer-Operations, ++ * Call-Diversion-Operations, ++ * and SS-MWI-Operations. ++ */ ++unsigned char *rose_enc_qsig_DummyArg_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_DummyRes_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args); ++ ++const unsigned char *rose_dec_qsig_DummyArg_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_DummyRes_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++ ++/* Q.SIG SS-AOC-Operations */ ++unsigned char *rose_enc_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args); ++unsigned char *rose_enc_qsig_AocFinal_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_AocInterim_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_AocRate_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_AocComplete_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_AocComplete_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args); ++unsigned char *rose_enc_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++ ++const unsigned char *rose_dec_qsig_ChargeRequest_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_ChargeRequest_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++const unsigned char *rose_dec_qsig_AocFinal_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_AocInterim_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_AocRate_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_AocComplete_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_AocComplete_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++const unsigned char *rose_dec_qsig_AocDivChargeReq_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++ ++/* Q.SIG Call-Diversion-Operations */ ++unsigned char *rose_enc_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_InterrogateDiversionQ_RES(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args); ++unsigned char *rose_enc_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_DivertingLegInformation1_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_DivertingLegInformation2_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_DivertingLegInformation3_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++ ++const unsigned char *rose_dec_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_RES(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++const unsigned char *rose_dec_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_DivertingLegInformation1_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_DivertingLegInformation2_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_DivertingLegInformation3_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++ ++/* Q.SIG Call-Transfer-Operations (CT) */ ++unsigned char *rose_enc_qsig_CallTransferIdentify_RES(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args); ++unsigned char *rose_enc_qsig_CallTransferInitiate_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_CallTransferSetup_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_CallTransferActive_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_CallTransferComplete_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_CallTransferUpdate_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_SubaddressTransfer_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++ ++const unsigned char *rose_dec_qsig_CallTransferIdentify_RES(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++const unsigned char *rose_dec_qsig_CallTransferInitiate_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_CallTransferSetup_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_CallTransferActive_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_CallTransferComplete_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_CallTransferUpdate_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_SubaddressTransfer_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++ ++/* Q.SIG SS-MWI-Operations */ ++unsigned char *rose_enc_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args); ++ ++const unsigned char *rose_dec_qsig_MWIActivate_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_MWIDeactivate_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_MWIInterrogate_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_qsig_MWIInterrogate_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++ ++/* Northern Telecom DMS-100 operations */ ++unsigned char *rose_enc_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args); ++unsigned char *rose_enc_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++ ++const unsigned char *rose_dec_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++const unsigned char *rose_dec_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++ ++/* National ISDN 2 (NI2) operations */ ++unsigned char *rose_enc_ni2_InformationFollowing_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args); ++unsigned char *rose_enc_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++ ++const unsigned char *rose_dec_ni2_InformationFollowing_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++const unsigned char *rose_dec_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _LIBPRI_ROSE_INTERNAL_H */ ++/* ------------------------------------------------------------------- */ ++/* end rose_internal.h */ + +Property changes on: rose_internal.h +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: pri_q921.h +=================================================================== +--- a/pri_q921.h (.../tags/1.4.10.2) (revision 1357) ++++ b/pri_q921.h (.../branches/1.4) (revision 1357) +@@ -192,4 +192,10 @@ + + extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr); + ++extern int q921_transmit_uiframe(struct pri *pri, void *buf, int len); ++ ++extern pri_event *q921_dchannel_up(struct pri *pri); ++ ++extern pri_event *q921_dchannel_down(struct pri *pri); ++ + #endif +Index: pri_facility.c +=================================================================== +--- a/pri_facility.c (.../tags/1.4.10.2) (revision 1357) ++++ b/pri_facility.c (.../branches/1.4) (revision 1357) +@@ -33,872 +33,1340 @@ + #include "pri_q921.h" + #include "pri_q931.h" + #include "pri_facility.h" ++#include "rose.h" + + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include <limits.h> + +-static char *asn1id2text(int id) ++static short get_invokeid(struct pri *ctrl) + { +- static char data[32]; +- static char *strings[] = { +- "none", +- "Boolean", +- "Integer", +- "Bit String", +- "Octet String", +- "NULL", +- "Object Identifier", +- "Object Descriptor", +- "External Reference", +- "Real Number", +- "Enumerated", +- "Embedded PDV", +- "UTF-8 String", +- "Relative Object ID", +- "Reserved (0e)", +- "Reserved (0f)", +- "Sequence", +- "Set", +- "Numeric String", +- "Printable String", +- "Tele-Text String", +- "IA-5 String", +- "UTC Time", +- "Generalized Time", +- }; +- if (id > 0 && id <= 0x18) { +- return strings[id]; +- } else { +- sprintf(data, "Unknown (%02x)", id); +- return data; +- } ++ ctrl = PRI_MASTER(ctrl); ++ return ++ctrl->last_invoke; + } + +-static int asn1_dumprecursive(struct pri *pri, void *comp_ptr, int len, int level) ++static int redirectingreason_from_q931(struct pri *ctrl, int redirectingreason) + { +- unsigned char *vdata = (unsigned char *)comp_ptr; +- struct rose_component *comp; +- int i = 0; +- int j, k, l; +- int clen = 0; ++ int value; + +- while (len > 0) { +- GET_COMPONENT(comp, i, vdata, len); +- pri_message(pri, "%*s%02X %04X", 2 * level, "", comp->type, comp->len); +- if ((comp->type == 0) && (comp->len == 0)) +- return clen + 2; +- if ((comp->type & ASN1_PC_MASK) == ASN1_PRIMITIVE) { +- for (j = 0; j < comp->len; ++j) +- pri_message(pri, " %02X", comp->data[j]); ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_QSIG: ++ switch (redirectingreason) { ++ case PRI_REDIR_UNKNOWN: ++ value = QSIG_DIVERT_REASON_UNKNOWN; ++ break; ++ case PRI_REDIR_FORWARD_ON_BUSY: ++ value = QSIG_DIVERT_REASON_CFB; ++ break; ++ case PRI_REDIR_FORWARD_ON_NO_REPLY: ++ value = QSIG_DIVERT_REASON_CFNR; ++ break; ++ case PRI_REDIR_UNCONDITIONAL: ++ value = QSIG_DIVERT_REASON_CFU; ++ break; ++ case PRI_REDIR_DEFLECTION: ++ case PRI_REDIR_DTE_OUT_OF_ORDER: ++ case PRI_REDIR_FORWARDED_BY_DTE: ++ pri_message(ctrl, ++ "!! Don't know how to convert Q.931 redirection reason %d to Q.SIG\n", ++ redirectingreason); ++ /* Fall through */ ++ default: ++ value = QSIG_DIVERT_REASON_UNKNOWN; ++ break; + } +- if ((comp->type & ASN1_CLAN_MASK) == ASN1_UNIVERSAL) { +- switch (comp->type & ASN1_TYPE_MASK) { +- case 0: +- pri_message(pri, " (none)"); +- break; +- case ASN1_BOOLEAN: +- pri_message(pri, " (BOOLEAN: %d)", comp->data[0]); +- break; +- case ASN1_INTEGER: +- for (k = l = 0; k < comp->len; ++k) +- l = (l << 8) | comp->data[k]; +- pri_message(pri, " (INTEGER: %d)", l); +- break; +- case ASN1_BITSTRING: +- pri_message(pri, " (BITSTRING:"); +- for (k = 0; k < comp->len; ++k) +- pri_message(pri, " %02x", comp->data[k]); +- pri_message(pri, ")"); +- break; +- case ASN1_OCTETSTRING: +- pri_message(pri, " (OCTETSTRING:"); +- for (k = 0; k < comp->len; ++k) +- pri_message(pri, " %02x", comp->data[k]); +- pri_message(pri, ")"); +- break; +- case ASN1_NULL: +- pri_message(pri, " (NULL)"); +- break; +- case ASN1_OBJECTIDENTIFIER: +- pri_message(pri, " (OBJECTIDENTIFIER:"); +- for (k = 0; k < comp->len; ++k) +- pri_message(pri, " %02x", comp->data[k]); +- pri_message(pri, ")"); +- break; +- case ASN1_ENUMERATED: +- for (k = l = 0; k < comp->len; ++k) +- l = (l << 8) | comp->data[k]; +- pri_message(pri, " (ENUMERATED: %d)", l); +- break; +- case ASN1_SEQUENCE: +- pri_message(pri, " (SEQUENCE)"); +- break; +- default: +- pri_message(pri, " (component %02x - %s)", comp->type, asn1id2text(comp->type & ASN1_TYPE_MASK)); +- break; +- } ++ break; ++ default: ++ switch (redirectingreason) { ++ case PRI_REDIR_UNKNOWN: ++ value = Q952_DIVERT_REASON_UNKNOWN; ++ break; ++ case PRI_REDIR_FORWARD_ON_BUSY: ++ value = Q952_DIVERT_REASON_CFB; ++ break; ++ case PRI_REDIR_FORWARD_ON_NO_REPLY: ++ value = Q952_DIVERT_REASON_CFNR; ++ break; ++ case PRI_REDIR_DEFLECTION: ++ value = Q952_DIVERT_REASON_CD; ++ break; ++ case PRI_REDIR_UNCONDITIONAL: ++ value = Q952_DIVERT_REASON_CFU; ++ break; ++ case PRI_REDIR_DTE_OUT_OF_ORDER: ++ case PRI_REDIR_FORWARDED_BY_DTE: ++ pri_message(ctrl, ++ "!! Don't know how to convert Q.931 redirection reason %d to Q.952\n", ++ redirectingreason); ++ /* Fall through */ ++ default: ++ value = Q952_DIVERT_REASON_UNKNOWN; ++ break; + } +- else if ((comp->type & ASN1_CLAN_MASK) == ASN1_CONTEXT_SPECIFIC) { +- pri_message(pri, " (CONTEXT SPECIFIC [%d])", comp->type & ASN1_TYPE_MASK); ++ break; ++ } ++ ++ return value; ++} ++ ++static int redirectingreason_for_q931(struct pri *ctrl, int redirectingreason) ++{ ++ int value; ++ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_QSIG: ++ switch (redirectingreason) { ++ case QSIG_DIVERT_REASON_UNKNOWN: ++ value = PRI_REDIR_UNKNOWN; ++ break; ++ case QSIG_DIVERT_REASON_CFU: ++ value = PRI_REDIR_UNCONDITIONAL; ++ break; ++ case QSIG_DIVERT_REASON_CFB: ++ value = PRI_REDIR_FORWARD_ON_BUSY; ++ break; ++ case QSIG_DIVERT_REASON_CFNR: ++ value = PRI_REDIR_FORWARD_ON_NO_REPLY; ++ break; ++ default: ++ pri_message(ctrl, "!! Unknown Q.SIG diversion reason %d\n", ++ redirectingreason); ++ value = PRI_REDIR_UNKNOWN; ++ break; + } +- else { +- pri_message(pri, " (component %02x)", comp->type); ++ break; ++ default: ++ switch (redirectingreason) { ++ case Q952_DIVERT_REASON_UNKNOWN: ++ value = PRI_REDIR_UNKNOWN; ++ break; ++ case Q952_DIVERT_REASON_CFU: ++ value = PRI_REDIR_UNCONDITIONAL; ++ break; ++ case Q952_DIVERT_REASON_CFB: ++ value = PRI_REDIR_FORWARD_ON_BUSY; ++ break; ++ case Q952_DIVERT_REASON_CFNR: ++ value = PRI_REDIR_FORWARD_ON_NO_REPLY; ++ break; ++ case Q952_DIVERT_REASON_CD: ++ value = PRI_REDIR_DEFLECTION; ++ break; ++ case Q952_DIVERT_REASON_IMMEDIATE: ++ pri_message(ctrl, ++ "!! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog\n"); ++ value = PRI_REDIR_UNKNOWN; /* ??? */ ++ break; ++ default: ++ pri_message(ctrl, "!! Unknown Q.952 diversion reason %d\n", ++ redirectingreason); ++ value = PRI_REDIR_UNKNOWN; ++ break; + } +- pri_message(pri, "\n"); +- if ((comp->type & ASN1_PC_MASK) == ASN1_CONSTRUCTOR) +- j = asn1_dumprecursive(pri, comp->data, (comp->len ? comp->len : INT_MAX), level+1); +- else +- j = comp->len; +- j += 2; +- len -= j; +- vdata += j; +- clen += j; ++ break; + } +- return clen; ++ ++ return value; + } + +-int asn1_dump(struct pri *pri, void *comp, int len) ++/*! ++ * \brief Convert the Q.931 type-of-number field to facility. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param ton Q.931 ton/plan octet. ++ * ++ * \return PartyNumber enumeration value. ++ */ ++static int typeofnumber_from_q931(struct pri *ctrl, int ton) + { +- return asn1_dumprecursive(pri, comp, len, 0); ++ int value; ++ ++ switch ((ton >> 4) & 0x03) { ++ default: ++ pri_message(ctrl, "!! Unsupported Q.931 TypeOfNumber value (%d)\n", ton); ++ /* fall through */ ++ case PRI_TON_UNKNOWN: ++ value = Q932_TON_UNKNOWN; ++ break; ++ case PRI_TON_INTERNATIONAL: ++ value = Q932_TON_INTERNATIONAL; ++ break; ++ case PRI_TON_NATIONAL: ++ value = Q932_TON_NATIONAL; ++ break; ++ case PRI_TON_NET_SPECIFIC: ++ value = Q932_TON_NET_SPECIFIC; ++ break; ++ case PRI_TON_SUBSCRIBER: ++ value = Q932_TON_SUBSCRIBER; ++ break; ++ case PRI_TON_ABBREVIATED: ++ value = Q932_TON_ABBREVIATED; ++ break; ++ } ++ ++ return value; + } + +-static unsigned char get_invokeid(struct pri *pri) ++static int typeofnumber_for_q931(struct pri *ctrl, int ton) + { +- return ++pri->last_invoke; ++ int value; ++ ++ switch (ton) { ++ default: ++ pri_message(ctrl, "!! Invalid TypeOfNumber %d\n", ton); ++ /* fall through */ ++ case Q932_TON_UNKNOWN: ++ value = PRI_TON_UNKNOWN; ++ break; ++ case Q932_TON_INTERNATIONAL: ++ value = PRI_TON_INTERNATIONAL; ++ break; ++ case Q932_TON_NATIONAL: ++ value = PRI_TON_NATIONAL; ++ break; ++ case Q932_TON_NET_SPECIFIC: ++ value = PRI_TON_NET_SPECIFIC; ++ break; ++ case Q932_TON_SUBSCRIBER: ++ value = PRI_TON_SUBSCRIBER; ++ break; ++ case Q932_TON_ABBREVIATED: ++ value = PRI_TON_ABBREVIATED; ++ break; ++ } ++ ++ return value << 4; + } + +-struct addressingdataelements_presentednumberunscreened { +- char partyaddress[21]; +- char partysubaddress[21]; +- int npi; /* Numbering Plan Indicator */ +- int ton; /* Type Of Number */ +- int pres; /* Presentation */ +-}; ++/*! ++ * \internal ++ * \brief Convert the Q.931 numbering plan field to facility. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param plan Q.931 ton/plan octet. ++ * ++ * \return PartyNumber enumeration value. ++ */ ++static int numbering_plan_from_q931(struct pri *ctrl, int plan) ++{ ++ int value; + +-struct addressingdataelements_presentednumberscreened { +- char partyaddress[21]; +- char partysubaddress[21]; +- int npi; /* Numbering Plan Indicator */ +- int ton; /* Type Of Number */ +- int pres; /* Presentation */ +- int scrind; /* Screening Indicator */ +-}; ++ switch (plan & 0x0F) { ++ default: ++ pri_message(ctrl, "!! Unsupported Q.931 numbering plan value (%d)\n", plan); ++ /* fall through */ ++ case PRI_NPI_UNKNOWN: ++ value = 0; /* unknown */ ++ break; ++ case PRI_NPI_E163_E164: ++ value = 1; /* public */ ++ break; ++ case PRI_NPI_X121: ++ value = 3; /* data */ ++ break; ++ case PRI_NPI_F69: ++ value = 4; /* telex */ ++ break; ++ case PRI_NPI_NATIONAL: ++ value = 8; /* nationalStandard */ ++ break; ++ case PRI_NPI_PRIVATE: ++ value = 5; /* private */ ++ break; ++ } + +-#define PRI_CHECKOVERFLOW(size) \ +- if (msgptr - message + (size) >= sizeof(message)) { \ +- *msgptr = '\0'; \ +- pri_message(pri, "%s", message); \ +- msgptr = message; \ +- } ++ return value; ++} + +-static void dump_apdu(struct pri *pri, unsigned char *c, int len) ++/*! ++ * \internal ++ * \brief Convert the PartyNumber numbering plan to Q.931 plan field value. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param plan PartyNumber enumeration value. ++ * ++ * \return Q.931 plan field value. ++ */ ++static int numbering_plan_for_q931(struct pri *ctrl, int plan) + { +- #define MAX_APDU_LENGTH 255 +- static char hexs[16] = "0123456789ABCDEF"; +- int i; +- char message[(2 + MAX_APDU_LENGTH * 3 + 6 + MAX_APDU_LENGTH + 3)] = ""; /* please adjust here, if you make changes below! */ +- char *msgptr; +- +- msgptr = message; +- *msgptr++ = ' '; +- *msgptr++ = '['; +- for (i=0; i<len; i++) { +- PRI_CHECKOVERFLOW(3); +- *msgptr++ = ' '; +- *msgptr++ = hexs[(c[i] >> 4) & 0x0f]; +- *msgptr++ = hexs[(c[i]) & 0x0f]; ++ int value; ++ ++ switch (plan) { ++ default: ++ pri_message(ctrl, ++ "!! Unsupported PartyNumber to Q.931 numbering plan value (%d)\n", plan); ++ /* fall through */ ++ case 0: /* unknown */ ++ value = PRI_NPI_UNKNOWN; ++ break; ++ case 1: /* public */ ++ value = PRI_NPI_E163_E164; ++ break; ++ case 3: /* data */ ++ value = PRI_NPI_X121; ++ break; ++ case 4: /* telex */ ++ value = PRI_NPI_F69; ++ break; ++ case 5: /* private */ ++ value = PRI_NPI_PRIVATE; ++ break; ++ case 8: /* nationalStandard */ ++ value = PRI_NPI_NATIONAL; ++ break; + } +- PRI_CHECKOVERFLOW(6); +- strcpy(msgptr, " ] - ["); +- msgptr += strlen(msgptr); +- for (i=0; i<len; i++) { +- PRI_CHECKOVERFLOW(1); +- *msgptr++ = ((c[i] < ' ') || (c[i] > '~')) ? '.' : c[i]; ++ ++ return value; ++} ++ ++/*! ++ * \internal ++ * \brief Convert the Q.931 number presentation field to facility. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param presentation Q.931 presentation/screening octet. ++ * \param number_present Non-zero if the number is available. ++ * ++ * \return Presented<Number/Address><Screened/Unscreened> enumeration value. ++ */ ++static int presentation_from_q931(struct pri *ctrl, int presentation, int number_present) ++{ ++ int value; ++ ++ switch (presentation & PRI_PRES_RESTRICTION) { ++ case PRI_PRES_ALLOWED: ++ value = 0; /* presentationAllowed<Number/Address> */ ++ break; ++ default: ++ pri_message(ctrl, "!! Unsupported Q.931 number presentation value (%d)\n", ++ presentation); ++ /* fall through */ ++ case PRI_PRES_RESTRICTED: ++ if (number_present) { ++ value = 3; /* presentationRestricted<Number/Address> */ ++ } else { ++ value = 1; /* presentationRestricted */ ++ } ++ break; ++ case PRI_PRES_UNAVAILABLE: ++ value = 2; /* numberNotAvailableDueToInterworking */ ++ break; + } +- PRI_CHECKOVERFLOW(2); +- *msgptr++ = ']'; +- *msgptr++ = '\n'; +- *msgptr = '\0'; +- pri_message(pri, "%s", message); ++ ++ return value; + } +-#undef PRI_CHECKOVERFLOW + +-int redirectingreason_from_q931(struct pri *pri, int redirectingreason) ++/*! ++ * \internal ++ * \brief Convert the Presented<Number/Address><Screened/Unscreened> presentation ++ * to Q.931 presentation field value. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param presentation Presented<Number/Address><Screened/Unscreened> value. ++ * ++ * \return Q.931 presentation field value. ++ */ ++static int presentation_for_q931(struct pri *ctrl, int presentation) + { +- switch(pri->switchtype) { +- case PRI_SWITCH_QSIG: +- switch(redirectingreason) { +- case PRI_REDIR_UNKNOWN: +- return QSIG_DIVERT_REASON_UNKNOWN; +- case PRI_REDIR_FORWARD_ON_BUSY: +- return QSIG_DIVERT_REASON_CFB; +- case PRI_REDIR_FORWARD_ON_NO_REPLY: +- return QSIG_DIVERT_REASON_CFNR; +- case PRI_REDIR_UNCONDITIONAL: +- return QSIG_DIVERT_REASON_CFU; +- case PRI_REDIR_DEFLECTION: +- case PRI_REDIR_DTE_OUT_OF_ORDER: +- case PRI_REDIR_FORWARDED_BY_DTE: +- pri_message(pri, "!! Don't know how to convert Q.931 redirection reason %d to Q.SIG\n", redirectingreason); +- /* Fall through */ +- default: +- return QSIG_DIVERT_REASON_UNKNOWN; +- } +- default: +- switch(redirectingreason) { +- case PRI_REDIR_UNKNOWN: +- return Q952_DIVERT_REASON_UNKNOWN; +- case PRI_REDIR_FORWARD_ON_BUSY: +- return Q952_DIVERT_REASON_CFB; +- case PRI_REDIR_FORWARD_ON_NO_REPLY: +- return Q952_DIVERT_REASON_CFNR; +- case PRI_REDIR_DEFLECTION: +- return Q952_DIVERT_REASON_CD; +- case PRI_REDIR_UNCONDITIONAL: +- return Q952_DIVERT_REASON_CFU; +- case PRI_REDIR_DTE_OUT_OF_ORDER: +- case PRI_REDIR_FORWARDED_BY_DTE: +- pri_message(pri, "!! Don't know how to convert Q.931 redirection reason %d to Q.952\n", redirectingreason); +- /* Fall through */ +- default: +- return Q952_DIVERT_REASON_UNKNOWN; +- } ++ int value; ++ ++ switch (presentation) { ++ case 0: /* presentationAllowed<Number/Address> */ ++ value = PRI_PRES_ALLOWED; ++ break; ++ default: ++ pri_message(ctrl, ++ "!! Unsupported Presented<Number/Address><Screened/Unscreened> to Q.931 value (%d)\n", ++ presentation); ++ /* fall through */ ++ case 1: /* presentationRestricted */ ++ case 3: /* presentationRestricted<Number/Address> */ ++ value = PRI_PRES_RESTRICTED; ++ break; ++ case 2: /* numberNotAvailableDueToInterworking */ ++ value = PRI_PRES_UNAVAILABLE; ++ break; + } ++ ++ return value; + } + +-static int redirectingreason_for_q931(struct pri *pri, int redirectingreason) ++/*! ++ * \internal ++ * \brief Convert the Q.931 number presentation field to Q.SIG name presentation. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param presentation Q.931 presentation/screening octet. ++ * \param name_present Non-zero if the name is available. ++ * ++ * \return Name presentation enumeration value. ++ */ ++static int qsig_name_presentation_from_q931(struct pri *ctrl, int presentation, int name_present) + { +- switch(pri->switchtype) { +- case PRI_SWITCH_QSIG: +- switch(redirectingreason) { +- case QSIG_DIVERT_REASON_UNKNOWN: +- return PRI_REDIR_UNKNOWN; +- case QSIG_DIVERT_REASON_CFU: +- return PRI_REDIR_UNCONDITIONAL; +- case QSIG_DIVERT_REASON_CFB: +- return PRI_REDIR_FORWARD_ON_BUSY; +- case QSIG_DIVERT_REASON_CFNR: +- return PRI_REDIR_FORWARD_ON_NO_REPLY; +- default: +- pri_message(pri, "!! Unknown Q.SIG diversion reason %d\n", redirectingreason); +- return PRI_REDIR_UNKNOWN; +- } +- default: +- switch(redirectingreason) { +- case Q952_DIVERT_REASON_UNKNOWN: +- return PRI_REDIR_UNKNOWN; +- case Q952_DIVERT_REASON_CFU: +- return PRI_REDIR_UNCONDITIONAL; +- case Q952_DIVERT_REASON_CFB: +- return PRI_REDIR_FORWARD_ON_BUSY; +- case Q952_DIVERT_REASON_CFNR: +- return PRI_REDIR_FORWARD_ON_NO_REPLY; +- case Q952_DIVERT_REASON_CD: +- return PRI_REDIR_DEFLECTION; +- case Q952_DIVERT_REASON_IMMEDIATE: +- pri_message(pri, "!! Dont' know how to convert Q.952 diversion reason IMMEDIATE to PRI analog\n"); +- return PRI_REDIR_UNKNOWN; /* ??? */ +- default: +- pri_message(pri, "!! Unknown Q.952 diversion reason %d\n", redirectingreason); +- return PRI_REDIR_UNKNOWN; +- } ++ int value; ++ ++ switch (presentation & PRI_PRES_RESTRICTION) { ++ case PRI_PRES_ALLOWED: ++ if (name_present) { ++ value = 1; /* presentation_allowed */ ++ } else { ++ value = 4; /* name_not_available */ ++ } ++ break; ++ default: ++ pri_message(ctrl, "!! Unsupported Q.931 number presentation value (%d)\n", ++ presentation); ++ /* fall through */ ++ case PRI_PRES_RESTRICTED: ++ if (name_present) { ++ value = 2; /* presentation_restricted */ ++ } else { ++ value = 3; /* presentation_restricted_null */ ++ } ++ break; ++ case PRI_PRES_UNAVAILABLE: ++ value = 4; /* name_not_available */ ++ break; + } ++ ++ return value; + } + +-int typeofnumber_from_q931(struct pri *pri, int ton) ++/*! ++ * \internal ++ * \brief Convert the Q.SIG name presentation to Q.931 presentation field value. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param presentation Q.SIG name presentation value. ++ * ++ * \return Q.931 presentation field value. ++ */ ++static int qsig_name_presentation_for_q931(struct pri *ctrl, int presentation) + { +- switch(ton) { +- case PRI_TON_INTERNATIONAL: +- return Q932_TON_INTERNATIONAL; +- case PRI_TON_NATIONAL: +- return Q932_TON_NATIONAL; +- case PRI_TON_NET_SPECIFIC: +- return Q932_TON_NET_SPECIFIC; +- case PRI_TON_SUBSCRIBER: +- return Q932_TON_SUBSCRIBER; +- case PRI_TON_ABBREVIATED: +- return Q932_TON_ABBREVIATED; +- case PRI_TON_RESERVED: +- default: +- pri_message(pri, "!! Unsupported Q.931 TypeOfNumber value (%d)\n", ton); +- /* fall through */ +- case PRI_TON_UNKNOWN: +- return Q932_TON_UNKNOWN; ++ int value; ++ ++ switch (presentation) { ++ case 1: /* presentation_allowed */ ++ value = PRI_PRES_ALLOWED; ++ break; ++ default: ++ pri_message(ctrl, ++ "!! Unsupported Q.SIG name presentation to Q.931 value (%d)\n", ++ presentation); ++ /* fall through */ ++ case 2: /* presentation_restricted */ ++ case 3: /* presentation_restricted_null */ ++ value = PRI_PRES_RESTRICTED; ++ break; ++ case 0: /* optional_name_not_present */ ++ case 4: /* name_not_available */ ++ value = PRI_PRES_UNAVAILABLE; ++ break; + } ++ ++ return value; + } + +-static int typeofnumber_for_q931(struct pri *pri, int ton) ++/*! ++ * \internal ++ * \brief Convert number presentation to Q.SIG diversion subscription notification. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param presentation Number presentation value. ++ * ++ * \return Q.SIG diversion subscription notification value. ++ */ ++static int presentation_to_subscription(struct pri *ctrl, int presentation) + { +- switch (ton) { +- case Q932_TON_UNKNOWN: +- return PRI_TON_UNKNOWN; +- case Q932_TON_INTERNATIONAL: +- return PRI_TON_INTERNATIONAL; +- case Q932_TON_NATIONAL: +- return PRI_TON_NATIONAL; +- case Q932_TON_NET_SPECIFIC: +- return PRI_TON_NET_SPECIFIC; +- case Q932_TON_SUBSCRIBER: +- return PRI_TON_SUBSCRIBER; +- case Q932_TON_ABBREVIATED: +- return PRI_TON_ABBREVIATED; +- default: +- pri_message(pri, "!! Invalid Q.932 TypeOfNumber %d\n", ton); +- return PRI_TON_UNKNOWN; ++ /* derive subscription value from presentation value */ ++ ++ switch (presentation & PRI_PRES_RESTRICTION) { ++ case PRI_PRES_ALLOWED: ++ return QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR; ++ case PRI_PRES_RESTRICTED: ++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR; ++ case PRI_PRES_UNAVAILABLE: /* Number not available due to interworking */ ++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR; /* ?? QSIG_NO_NOTIFICATION */ ++ default: ++ pri_message(ctrl, "!! Unknown Q.SIG presentationIndicator 0x%02x\n", ++ presentation); ++ return QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR; + } + } + +-int asn1_name_decode(void * data, int len, char *namebuf, int buflen) ++/*! ++ * \internal ++ * \brief Copy the given rose party number to the q931_party_number ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param q931_number Q.931 party number structure ++ * \param rose_number ROSE party number structure ++ * ++ * \note It is assumed that the q931_number has been initialized before calling. ++ * ++ * \return Nothing ++ */ ++static void rose_copy_number_to_q931(struct pri *ctrl, ++ struct q931_party_number *q931_number, const struct rosePartyNumber *rose_number) + { +- struct rose_component *comp = (struct rose_component*)data; +- int datalen = 0, res = 0; ++ //q931_party_number_init(q931_number); ++ libpri_copy_string(q931_number->str, (char *) rose_number->str, ++ sizeof(q931_number->str)); ++ q931_number->plan = numbering_plan_for_q931(ctrl, rose_number->plan) ++ | typeofnumber_for_q931(ctrl, rose_number->ton); ++ q931_number->valid = 1; ++} + +- if (comp->len == ASN1_LEN_INDEF) { +- datalen = strlen((char *)comp->data); +- res = datalen + 2; +- } else +- datalen = res = comp->len; ++/*! ++ * \internal ++ * \brief Copy the given rose subaddress to the q931_party_subaddress. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param q931_subaddress Q.931 party subaddress structure ++ * \param rose_subaddress ROSE subaddress structure ++ * ++ * \note It is assumed that the q931_subaddress has been initialized before calling. ++ * ++ * \return Nothing ++ */ ++static void rose_copy_subaddress_to_q931(struct pri *ctrl, ++ struct q931_party_subaddress *q931_subaddress, ++ const struct rosePartySubaddress *rose_subaddress) ++{ ++ //q931_party_subaddress_init(q931_subaddress); ++ if (!rose_subaddress->length) { ++ /* Subaddress is not present. */ ++ return; ++ } + +- if (datalen > buflen) { +- /* Truncate */ +- datalen = buflen; ++ switch (rose_subaddress->type) { ++ case 0:/* UserSpecified */ ++ q931_subaddress->type = 2;/* user_specified */ ++ q931_subaddress->valid = 1; ++ q931_subaddress->length = rose_subaddress->length; ++ if (sizeof(q931_subaddress->data) <= q931_subaddress->length) { ++ q931_subaddress->length = sizeof(q931_subaddress->data) - 1; ++ } ++ memcpy(q931_subaddress->data, rose_subaddress->u.user_specified.information, ++ q931_subaddress->length); ++ q931_subaddress->data[q931_subaddress->length] = '\0'; ++ if (rose_subaddress->u.user_specified.odd_count_present) { ++ q931_subaddress->odd_even_indicator = ++ rose_subaddress->u.user_specified.odd_count; ++ } ++ break; ++ case 1:/* NSAP */ ++ q931_subaddress->type = 0;/* nsap */ ++ q931_subaddress->valid = 1; ++ libpri_copy_string((char *) q931_subaddress->data, ++ (char *) rose_subaddress->u.nsap, sizeof(q931_subaddress->data)); ++ q931_subaddress->length = strlen((char *) q931_subaddress->data); ++ break; ++ default: ++ /* Don't know how to encode so assume it is not present. */ ++ break; + } +- memcpy(namebuf, comp->data, datalen); +- return res + 2; + } + +-int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len) ++/*! ++ * \internal ++ * \brief Copy the given rose address to the q931_party_id address. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param q931_address Q.931 party id structure to fill address ++ * \param rose_address ROSE address structure ++ * ++ * \note It is assumed that the q931_address has been initialized before calling. ++ * ++ * \return Nothing ++ */ ++static void rose_copy_address_to_q931(struct pri *ctrl, ++ struct q931_party_id *q931_address, const struct roseAddress *rose_address) + { +- struct rose_component *comp = NULL; +- +- if (len < 2 + src_len) +- return -1; ++ rose_copy_number_to_q931(ctrl, &q931_address->number, &rose_address->number); ++ rose_copy_subaddress_to_q931(ctrl, &q931_address->subaddress, ++ &rose_address->subaddress); ++} + +- if (max_len && (src_len > max_len)) +- src_len = max_len; ++/*! ++ * \internal ++ * \brief Copy the given rose presented screened party number to the q931_party_number ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param q931_number Q.931 party number structure ++ * \param rose_presented ROSE presented screened party number structure ++ * ++ * \return Nothing ++ */ ++static void rose_copy_presented_number_screened_to_q931(struct pri *ctrl, ++ struct q931_party_number *q931_number, ++ const struct rosePresentedNumberScreened *rose_presented) ++{ ++ q931_party_number_init(q931_number); ++ q931_number->valid = 1; ++ q931_number->presentation = presentation_for_q931(ctrl, rose_presented->presentation); ++ switch (rose_presented->presentation) { ++ case 0: /* presentationAllowedNumber */ ++ case 3: /* presentationRestrictedNumber */ ++ q931_number->presentation |= ++ (rose_presented->screened.screening_indicator & PRI_PRES_NUMBER_TYPE); ++ rose_copy_number_to_q931(ctrl, q931_number, ++ &rose_presented->screened.number); ++ break; ++ default: ++ q931_number->presentation |= PRI_PRES_USER_NUMBER_UNSCREENED; ++ break; ++ } ++} + +- comp = (struct rose_component *)data; +- comp->type = asn1_type; +- comp->len = src_len; +- memcpy(comp->data, src, src_len); +- +- return 2 + src_len; ++/*! ++ * \internal ++ * \brief Copy the given rose presented unscreened party number to the q931_party_number ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param q931_number Q.931 party number structure ++ * \param rose_presented ROSE presented unscreened party number structure ++ * ++ * \return Nothing ++ */ ++static void rose_copy_presented_number_unscreened_to_q931(struct pri *ctrl, ++ struct q931_party_number *q931_number, ++ const struct rosePresentedNumberUnscreened *rose_presented) ++{ ++ q931_party_number_init(q931_number); ++ q931_number->valid = 1; ++ q931_number->presentation = presentation_for_q931(ctrl, ++ rose_presented->presentation) | PRI_PRES_USER_NUMBER_UNSCREENED; ++ switch (rose_presented->presentation) { ++ case 0: /* presentationAllowedNumber */ ++ case 3: /* presentationRestrictedNumber */ ++ rose_copy_number_to_q931(ctrl, q931_number, &rose_presented->number); ++ break; ++ default: ++ break; ++ } + } + +-int asn1_copy_string(char * buf, int buflen, struct rose_component *comp) ++/*! ++ * \internal ++ * \brief Copy the given rose presented screened party address to the q931_party_number ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param q931_address Q.931 party id structure to fill the address ++ * \param rose_presented ROSE presented screened party address structure ++ * ++ * \return Nothing ++ */ ++static void rose_copy_presented_address_screened_to_q931(struct pri *ctrl, ++ struct q931_party_id *q931_address, ++ const struct rosePresentedAddressScreened *rose_presented) + { +- int res; +- int datalen; ++ q931_party_number_init(&q931_address->number); ++ q931_party_subaddress_init(&q931_address->subaddress); ++ q931_address->number.valid = 1; ++ q931_address->number.presentation = presentation_for_q931(ctrl, ++ rose_presented->presentation); ++ switch (rose_presented->presentation) { ++ case 0: /* presentationAllowedAddress */ ++ case 3: /* presentationRestrictedAddress */ ++ q931_address->number.presentation |= ++ (rose_presented->screened.screening_indicator & PRI_PRES_NUMBER_TYPE); ++ rose_copy_number_to_q931(ctrl, &q931_address->number, ++ &rose_presented->screened.number); ++ rose_copy_subaddress_to_q931(ctrl, &q931_address->subaddress, ++ &rose_presented->screened.subaddress); ++ break; ++ default: ++ q931_address->number.presentation |= PRI_PRES_USER_NUMBER_UNSCREENED; ++ break; ++ } ++} + +- if ((comp->len > buflen) && (comp->len != ASN1_LEN_INDEF)) +- return -1; ++/*! ++ * \internal ++ * \brief Copy the given rose party name to the q931_party_name ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param qsig_name Q.SIG party name structure ++ * \param rose_name Q.SIG ROSE party name structure ++ * ++ * \return Nothing ++ */ ++static void rose_copy_name_to_q931(struct pri *ctrl, ++ struct q931_party_name *qsig_name, const struct roseQsigName *rose_name) ++{ ++ //q931_party_name_init(qsig_name); ++ qsig_name->valid = 1; ++ qsig_name->presentation = qsig_name_presentation_for_q931(ctrl, ++ rose_name->presentation); ++ qsig_name->char_set = rose_name->char_set; ++ libpri_copy_string(qsig_name->str, (char *) rose_name->data, sizeof(qsig_name->str)); ++} + +- if (comp->len == ASN1_LEN_INDEF) { +- datalen = strlen((char*)comp->data); +- res = datalen + 2; +- } else +- res = datalen = comp->len; ++/*! ++ * \internal ++ * \brief Copy the given q931_party_number to the rose party number ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param rose_number ROSE party number structure ++ * \param q931_number Q.931 party number structure ++ * ++ * \return Nothing ++ */ ++static void q931_copy_number_to_rose(struct pri *ctrl, ++ struct rosePartyNumber *rose_number, const struct q931_party_number *q931_number) ++{ ++ rose_number->plan = numbering_plan_from_q931(ctrl, q931_number->plan); ++ rose_number->ton = typeofnumber_from_q931(ctrl, q931_number->plan); ++ /* Truncate the q931_number->str if necessary. */ ++ libpri_copy_string((char *) rose_number->str, q931_number->str, ++ sizeof(rose_number->str)); ++ rose_number->length = strlen((char *) rose_number->str); ++} + +- memcpy(buf, comp->data, datalen); +- buf[datalen] = 0; ++/*! ++ * \internal ++ * \brief Copy the given q931_party_subaddress to the rose subaddress. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param rose_subaddress ROSE subaddress structure ++ * \param q931_subaddress Q.931 party subaddress structure ++ * ++ * \return Nothing ++ */ ++static void q931_copy_subaddress_to_rose(struct pri *ctrl, ++ struct rosePartySubaddress *rose_subaddress, ++ const struct q931_party_subaddress *q931_subaddress) ++{ ++ if (!q931_subaddress->valid) { ++ /* Subaddress is not present. */ ++ rose_subaddress->length = 0; ++ return; ++ } + +- return res; ++ switch (q931_subaddress->type) { ++ case 0: /* NSAP */ ++ rose_subaddress->type = 1;/* NSAP */ ++ libpri_copy_string((char *) rose_subaddress->u.nsap, ++ (char *) q931_subaddress->data, sizeof(rose_subaddress->u.nsap)); ++ rose_subaddress->length = strlen((char *) rose_subaddress->u.nsap); ++ break; ++ case 2: /* user_specified */ ++ rose_subaddress->type = 0;/* UserSpecified */ ++ rose_subaddress->length = q931_subaddress->length; ++ if (sizeof(rose_subaddress->u.user_specified.information) ++ <= rose_subaddress->length) { ++ rose_subaddress->length = ++ sizeof(rose_subaddress->u.user_specified.information) - 1; ++ } else { ++ if (q931_subaddress->odd_even_indicator) { ++ rose_subaddress->u.user_specified.odd_count_present = 1; ++ rose_subaddress->u.user_specified.odd_count = 1; ++ } ++ } ++ memcpy(rose_subaddress->u.user_specified.information, q931_subaddress->data, ++ rose_subaddress->length); ++ rose_subaddress->u.user_specified.information[rose_subaddress->length] = '\0'; ++ break; ++ default: ++ /* Don't know how to encode so assume it is not present. */ ++ rose_subaddress->length = 0; ++ break; ++ } + } + +-static int rose_number_digits_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++/*! ++ * \internal ++ * \brief Copy the given q931_party_id address to the rose address. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param rose_address ROSE address structure ++ * \param q931_address Q.931 party id structure to give address ++ * ++ * \return Nothing ++ */ ++static void q931_copy_address_to_rose(struct pri *ctrl, struct roseAddress *rose_address, ++ const struct q931_party_id *q931_address) + { +- int i = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; +- int datalen = 0; +- int res = 0; ++ q931_copy_number_to_rose(ctrl, &rose_address->number, &q931_address->number); ++ q931_copy_subaddress_to_rose(ctrl, &rose_address->subaddress, ++ &q931_address->subaddress); ++} + +- do { +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_NUMERICSTRING, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n"); +- if(comp->len > 20 && comp->len != ASN1_LEN_INDEF) { +- pri_message(pri, "!! Oversized NumberDigits component (%d)\n", comp->len); +- return -1; +- } +- if (comp->len == ASN1_LEN_INDEF) { +- datalen = strlen((char *)comp->data); +- res = datalen + 2; +- } else +- res = datalen = comp->len; +- +- memcpy(value->partyaddress, comp->data, datalen); +- value->partyaddress[datalen] = '\0'; ++/*! ++ * \internal ++ * \brief Copy the given q931_party_number to the rose presented screened party number ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param rose_presented ROSE presented screened party number structure ++ * \param q931_number Q.931 party number structure ++ * ++ * \return Nothing ++ */ ++static void q931_copy_presented_number_screened_to_rose(struct pri *ctrl, ++ struct rosePresentedNumberScreened *rose_presented, ++ const struct q931_party_number *q931_number) ++{ ++ if (q931_number->valid) { ++ rose_presented->presentation = ++ presentation_from_q931(ctrl, q931_number->presentation, q931_number->str[0]); ++ rose_presented->screened.screening_indicator = ++ q931_number->presentation & PRI_PRES_NUMBER_TYPE; ++ q931_copy_number_to_rose(ctrl, &rose_presented->screened.number, q931_number); ++ } else { ++ rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */ ++ } ++} + +- return res + 2; ++/*! ++ * \internal ++ * \brief Copy the given q931_party_number to the rose presented unscreened party number ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param rose_presented ROSE presented unscreened party number structure ++ * \param q931_number Q.931 party number structure ++ * ++ * \return Nothing ++ */ ++static void q931_copy_presented_number_unscreened_to_rose(struct pri *ctrl, ++ struct rosePresentedNumberUnscreened *rose_presented, ++ const struct q931_party_number *q931_number) ++{ ++ if (q931_number->valid) { ++ rose_presented->presentation = ++ presentation_from_q931(ctrl, q931_number->presentation, q931_number->str[0]); ++ q931_copy_number_to_rose(ctrl, &rose_presented->number, q931_number); ++ } else { ++ rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */ + } +- while(0); +- +- return -1; + } + +-static int rose_public_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++#if 0 /* In case it is needed in the future */ ++/*! ++ * \internal ++ * \brief Copy the given q931_party_number to the rose presented screened party address ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param rose_presented ROSE presented screened party address structure ++ * \param q931_address Q.931 party id structure to get the address ++ * ++ * \return Nothing ++ */ ++static void q931_copy_presented_address_screened_to_rose(struct pri *ctrl, ++ struct rosePresentedAddressScreened *rose_presented, ++ const struct q931_party_id *q931_address) + { +- int i = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; +- int ton; +- int res = 0; ++ if (q931_address->number.valid) { ++ rose_presented->presentation = ++ presentation_from_q931(ctrl, q931_address->number.presentation, ++ q931_address->number.str[0]); ++ rose_presented->screened.screening_indicator = ++ q931_address->number.presentation & PRI_PRES_NUMBER_TYPE; ++ q931_copy_number_to_rose(ctrl, &rose_presented->screened.number, ++ &q931_address->number); ++ q931_copy_subaddress_to_rose(ctrl, &rose_presented->screened.subaddress, ++ &q931_address->subaddress); ++ } else { ++ rose_presented->presentation = 2;/* numberNotAvailableDueToInterworking */ ++ } ++} ++#endif /* In case it is needed in the future */ + +- if (len < 2) +- return -1; ++/*! ++ * \internal ++ * \brief Copy the given q931_party_name to the rose party name ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param rose_name Q.SIG ROSE party name structure ++ * \param qsig_name Q.SIG party name structure ++ * ++ * \return Nothing ++ */ ++static void q931_copy_name_to_rose(struct pri *ctrl, ++ struct roseQsigName *rose_name, const struct q931_party_name *qsig_name) ++{ ++ if (qsig_name->valid) { ++ rose_name->presentation = qsig_name_presentation_from_q931(ctrl, ++ qsig_name->presentation, qsig_name->str[0]); ++ rose_name->char_set = qsig_name->char_set; ++ /* Truncate the qsig_name->str if necessary. */ ++ libpri_copy_string((char *) rose_name->data, qsig_name->str, sizeof(rose_name->data)); ++ rose_name->length = strlen((char *) rose_name->data); ++ } else { ++ rose_name->presentation = 4;/* name_not_available */ ++ } ++} + +- do { +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PublicPartyNumber ROSE component type 0x%x\n"); +- ASN1_GET_INTEGER(comp, ton); +- NEXT_COMPONENT(comp, i); +- ton = typeofnumber_for_q931(pri, ton); ++/*! ++ * \internal ++ * \brief Encode the Q.SIG DivertingLegInformation1 invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode diversion leg 1. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_diverting_leg_information1(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, q931_call *call) ++{ ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; + +- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value); +- if (res < 0) +- return -1; +- value->ton = ton; ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } + +- return res + 3; ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_DivertingLegInformation1; ++ msg.invoke_id = get_invokeid(ctrl); ++ msg.args.qsig.DivertingLegInformation1.diversion_reason = ++ redirectingreason_from_q931(ctrl, call->redirecting.reason); + +- } while(0); +- return -1; ++ /* subscriptionOption is the redirecting.to.number.presentation */ ++ msg.args.qsig.DivertingLegInformation1.subscription_option = ++ presentation_to_subscription(ctrl, call->redirecting.to.number.presentation); ++ ++ /* nominatedNr is the redirecting.to.number */ ++ q931_copy_number_to_rose(ctrl, ++ &msg.args.qsig.DivertingLegInformation1.nominated_number, ++ &call->redirecting.to.number); ++ ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; + } + +-static int rose_private_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++/*! ++ * \internal ++ * \brief Encode the ETSI DivertingLegInformation1 invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode diversion leg 1. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_etsi_diverting_leg_information1(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, q931_call *call) + { +- int i = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; +- int ton; +- int res = 0; ++ struct rose_msg_invoke msg; + +- if (len < 2) +- return -1; ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } + +- do { +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with PrivatePartyNumber ROSE component type 0x%x\n"); +- ASN1_GET_INTEGER(comp, ton); +- NEXT_COMPONENT(comp, i); +- ton = typeofnumber_for_q931(pri, ton); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_ETSI_DivertingLegInformation1; ++ msg.invoke_id = get_invokeid(ctrl); ++ msg.args.etsi.DivertingLegInformation1.diversion_reason = ++ redirectingreason_from_q931(ctrl, call->redirecting.reason); + +- res = rose_number_digits_decode(pri, call, &vdata[i], len-i, value); +- if (res < 0) +- return -1; +- value->ton = ton; ++ if (call->redirecting.to.number.valid) { ++ msg.args.etsi.DivertingLegInformation1.subscription_option = 2; + +- return res + 3; ++ /* divertedToNumber is the redirecting.to.number */ ++ msg.args.etsi.DivertingLegInformation1.diverted_to_present = 1; ++ q931_copy_presented_number_unscreened_to_rose(ctrl, ++ &msg.args.etsi.DivertingLegInformation1.diverted_to, ++ &call->redirecting.to.number); ++ } else { ++ msg.args.etsi.DivertingLegInformation1.subscription_option = 1; ++ } ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- } while(0); +- return -1; ++ return pos; + } + +-static int rose_address_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++/*! ++ * \brief Encode and queue the DivertingLegInformation1 invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode diversion leg 1. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int rose_diverting_leg_information1_encode(struct pri *ctrl, q931_call *call) + { +- int i = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; +- int res = 0; ++ unsigned char buffer[256]; ++ unsigned char *end; + +- do { +- GET_COMPONENT(comp, i, vdata, len); ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ end = enc_etsi_diverting_leg_information1(ctrl, buffer, buffer + sizeof(buffer), ++ call); ++ break; ++ case PRI_SWITCH_QSIG: ++ end = enc_qsig_diverting_leg_information1(ctrl, buffer, buffer + sizeof(buffer), ++ call); ++ break; ++ default: ++ return -1; ++ } ++ if (!end) { ++ return -1; ++ } + +- switch(comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] unknownPartyNumber */ +- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); +- if (res < 0) +- return -1; +- value->npi = PRI_NPI_UNKNOWN; +- value->ton = PRI_TON_UNKNOWN; +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): /* [0] unknownPartyNumber */ +- res = asn1_copy_string(value->partyaddress, sizeof(value->partyaddress), comp); +- if (res < 0) +- return -1; +- value->npi = PRI_NPI_UNKNOWN; +- value->ton = PRI_TON_UNKNOWN; +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] publicPartyNumber */ +- res = rose_public_party_number_decode(pri, call, comp->data, comp->len, value); +- if (res < 0) +- return -1; +- value->npi = PRI_NPI_E163_E164; +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* [2] nsapEncodedNumber */ +- pri_message(pri, "!! NsapEncodedNumber isn't handled\n"); +- return -1; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] dataPartyNumber */ +- if(rose_number_digits_decode(pri, call, comp->data, comp->len, value)) +- return -1; +- value->npi = PRI_NPI_X121 /* ??? */; +- value->ton = PRI_TON_UNKNOWN /* ??? */; +- pri_message(pri, "!! dataPartyNumber isn't handled\n"); +- return -1; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] telexPartyNumber */ +- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); +- if (res < 0) +- return -1; +- value->npi = PRI_NPI_F69 /* ??? */; +- value->ton = PRI_TON_UNKNOWN /* ??? */; +- pri_message(pri, "!! telexPartyNumber isn't handled\n"); +- return -1; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] priavePartyNumber */ +- res = rose_private_party_number_decode(pri, call, comp->data, comp->len, value); +- if (res < 0) +- return -1; +- value->npi = PRI_NPI_PRIVATE; +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] nationalStandardPartyNumber */ +- res = rose_number_digits_decode(pri, call, comp->data, comp->len, value); +- if (res < 0) +- return -1; +- value->npi = PRI_NPI_NATIONAL; +- value->ton = PRI_TON_NATIONAL; +- break; +- default: +- pri_message(pri, "!! Unknown Party number component received 0x%X\n", comp->type); +- return -1; ++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL); ++} ++ ++/*! ++ * \internal ++ * \brief Encode the Q.SIG DivertingLegInformation2 invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode diversion leg 2. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_diverting_leg_information2(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, q931_call *call) ++{ ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; ++ ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_DivertingLegInformation2; ++ msg.invoke_id = get_invokeid(ctrl); ++ ++ /* diversionCounter is the redirecting.count */ ++ msg.args.qsig.DivertingLegInformation2.diversion_counter = call->redirecting.count; ++ ++ msg.args.qsig.DivertingLegInformation2.diversion_reason = ++ redirectingreason_from_q931(ctrl, call->redirecting.reason); ++ ++ /* divertingNr is the redirecting.from.number */ ++ msg.args.qsig.DivertingLegInformation2.diverting_present = 1; ++ q931_copy_presented_number_unscreened_to_rose(ctrl, ++ &msg.args.qsig.DivertingLegInformation2.diverting, ++ &call->redirecting.from.number); ++ ++ /* redirectingName is the redirecting.from.name */ ++ if (call->redirecting.from.name.valid) { ++ msg.args.qsig.DivertingLegInformation2.redirecting_name_present = 1; ++ q931_copy_name_to_rose(ctrl, ++ &msg.args.qsig.DivertingLegInformation2.redirecting_name, ++ &call->redirecting.from.name); ++ } ++ ++ if (1 < call->redirecting.count) { ++ /* originalCalledNr is the redirecting.orig_called.number */ ++ msg.args.qsig.DivertingLegInformation2.original_called_present = 1; ++ q931_copy_presented_number_unscreened_to_rose(ctrl, ++ &msg.args.qsig.DivertingLegInformation2.original_called, ++ &call->redirecting.orig_called.number); ++ ++ msg.args.qsig.DivertingLegInformation2.original_diversion_reason_present = 1; ++ if (call->redirecting.orig_called.number.valid) { ++ msg.args.qsig.DivertingLegInformation2.original_diversion_reason = ++ redirectingreason_from_q931(ctrl, call->redirecting.orig_reason); ++ } else { ++ msg.args.qsig.DivertingLegInformation2.original_diversion_reason = ++ QSIG_DIVERT_REASON_UNKNOWN; + } +- ASN1_FIXUP_LEN(comp, res); +- NEXT_COMPONENT(comp, i); +- if(i < len) +- pri_message(pri, "!! not all information is handled from Address component\n"); +- return res + 2; ++ ++ /* originalCalledName is the redirecting.orig_called.name */ ++ if (call->redirecting.orig_called.name.valid) { ++ msg.args.qsig.DivertingLegInformation2.original_called_name_present = 1; ++ q931_copy_name_to_rose(ctrl, ++ &msg.args.qsig.DivertingLegInformation2.original_called_name, ++ &call->redirecting.orig_called.name); ++ } + } +- while (0); + +- return -1; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; + } + +-static int rose_presented_number_unscreened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++/*! ++ * \internal ++ * \brief Encode the ETSI DivertingLegInformation2 invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode diversion leg 2. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_etsi_diverting_leg_information2(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, q931_call *call) + { +- int i = 0; +- int size = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; ++ struct rose_msg_invoke msg; + +- /* Fill in default values */ +- value->ton = PRI_TON_UNKNOWN; +- value->npi = PRI_NPI_E163_E164; +- value->pres = -1; /* Data is not available */ ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } + +- do { +- GET_COMPONENT(comp, i, vdata, len); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_ETSI_DivertingLegInformation2; ++ msg.invoke_id = get_invokeid(ctrl); + +- switch(comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] presentationAllowedNumber */ +- value->pres = PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; +- size = rose_address_decode(pri, call, comp->data, comp->len, value); +- ASN1_FIXUP_LEN(comp, size); +- return size + 2; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */ +- if (comp->len != 0) { /* must be NULL */ +- pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n"); +- return -1; +- } +- value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED; +- return 2; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */ +- if (comp->len != 0) { /* must be NULL */ +- pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n"); +- return -1; +- } +- value->pres = PRES_NUMBER_NOT_AVAILABLE; +- return 2; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] presentationRestrictedNumber */ +- value->pres = PRES_PROHIB_USER_NUMBER_NOT_SCREENED; +- size = rose_address_decode(pri, call, comp->data, comp->len, value) + 2; +- ASN1_FIXUP_LEN(comp, size); +- return size + 2; +- default: +- pri_message(pri, "Invalid PresentedNumberUnscreened component 0x%X\n", comp->type); +- } +- return -1; ++ /* diversionCounter is the redirecting.count */ ++ msg.args.etsi.DivertingLegInformation2.diversion_counter = call->redirecting.count; ++ ++ msg.args.etsi.DivertingLegInformation2.diversion_reason = ++ redirectingreason_from_q931(ctrl, call->redirecting.reason); ++ ++ /* divertingNr is the redirecting.from.number */ ++ msg.args.etsi.DivertingLegInformation2.diverting_present = 1; ++ q931_copy_presented_number_unscreened_to_rose(ctrl, ++ &msg.args.etsi.DivertingLegInformation2.diverting, ++ &call->redirecting.from.number); ++ ++ if (1 < call->redirecting.count) { ++ /* originalCalledNr is the redirecting.orig_called.number */ ++ msg.args.etsi.DivertingLegInformation2.original_called_present = 1; ++ q931_copy_presented_number_unscreened_to_rose(ctrl, ++ &msg.args.etsi.DivertingLegInformation2.original_called, ++ &call->redirecting.orig_called.number); + } +- while (0); + +- return -1; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; + } + +-static int rose_diverting_leg_information2_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++/*! ++ * \internal ++ * \brief Encode and queue the DivertingLegInformation2 invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode diversion leg 2. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int rose_diverting_leg_information2_encode(struct pri *ctrl, q931_call *call) + { +- int i = 0; +- int diversion_counter; +- int diversion_reason; +- char origcalledname[50] = "", redirectingname[50] = ""; +- struct addressingdataelements_presentednumberunscreened divertingnr; +- struct addressingdataelements_presentednumberunscreened originalcallednr; +- struct rose_component *comp = NULL; +- unsigned char *vdata = sequence->data; +- int res = 0; +- memset(&divertingnr, 0, sizeof(divertingnr)); +- memset(&originalcallednr, 0, sizeof(originalcallednr)); ++ unsigned char buffer[256]; ++ unsigned char *end; + +- /* Data checks */ +- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ +- pri_message(pri, "Invalid DivertingLegInformation2Type argument\n"); ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ end = enc_etsi_diverting_leg_information2(ctrl, buffer, buffer + sizeof(buffer), ++ call); ++ break; ++ case PRI_SWITCH_QSIG: ++ end = enc_qsig_diverting_leg_information2(ctrl, buffer, buffer + sizeof(buffer), ++ call); ++ break; ++ default: + return -1; + } ++ if (!end) { ++ return -1; ++ } + +- if (sequence->len == ASN1_LEN_INDEF) { +- len -= 4; /* For the 2 extra characters at the end +- * and two characters of header */ +- } else +- len -= 2; ++ return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL); ++} + +- do { +- /* diversionCounter stuff */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do it diversionCounter is of type 0x%x\n"); +- ASN1_GET_INTEGER(comp, diversion_counter); +- NEXT_COMPONENT(comp, i); ++/*! ++ * \internal ++ * \brief Encode the Q.SIG DivertingLegInformation3 invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode diversion leg 3. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_diverting_leg_information3(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, q931_call *call) ++{ ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; + +- /* diversionReason stuff */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid diversionReason type 0x%X of ROSE divertingLegInformation2 component received\n"); +- ASN1_GET_INTEGER(comp, diversion_reason); +- NEXT_COMPONENT(comp, i); ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } + +- diversion_reason = redirectingreason_for_q931(pri, diversion_reason); +- +- if(pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Redirection reason: %d, total diversions: %d\n", diversion_reason, diversion_counter); +- pri_message(NULL, "Length of message is %d\n", len); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_DivertingLegInformation3; ++ msg.invoke_id = get_invokeid(ctrl); + +- for(; i < len; NEXT_COMPONENT(comp, i)) { +- GET_COMPONENT(comp, i, vdata, len); +- switch(comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0): +- call->origredirectingreason = redirectingreason_for_q931(pri, comp->data[0]); +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received reason for original redirection %d\n", call->origredirectingreason); +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): +- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &divertingnr); +- /* TODO: Fix indefinite length form hacks */ +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- if (res < 0) +- return -1; +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, " Received divertingNr '%s'\n", divertingnr.partyaddress); +- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", divertingnr.ton, divertingnr.pres, divertingnr.npi); +- } +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): +- res = rose_presented_number_unscreened_decode(pri, call, comp->data, comp->len, &originalcallednr); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, " Received originalcallednr '%s'\n", originalcallednr.partyaddress); +- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", originalcallednr.ton, originalcallednr.pres, originalcallednr.npi); +- } +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): +- res = asn1_name_decode(comp->data, comp->len, redirectingname, sizeof(redirectingname)); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received RedirectingName '%s'\n", redirectingname); +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): +- res = asn1_name_decode(comp->data, comp->len, origcalledname, sizeof(origcalledname)); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received Originally Called Name '%s'\n", origcalledname); +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): +- pri_message(pri, "!! Ignoring DivertingLegInformation2 component 0x%X\n", comp->type); +- break; +- default: +- if (comp->type == 0 && comp->len == 0) { +- break; /* Found termination characters */ +- } +- pri_message(pri, "!! Invalid DivertingLegInformation2 component received 0x%X\n", comp->type); +- return -1; +- } +- } ++ /* redirecting.to.number.presentation also indicates if name presentation is allowed */ ++ if ((call->redirecting.to.number.presentation & PRI_PRES_RESTRICTION) == PRI_PRES_ALLOWED) { ++ msg.args.qsig.DivertingLegInformation3.presentation_allowed_indicator = 1; /* TRUE */ + +- if (divertingnr.pres >= 0) { +- call->redirectingplan = divertingnr.npi; +- call->redirectingpres = divertingnr.pres; +- call->redirectingreason = diversion_reason; +- libpri_copy_string(call->redirectingnum, divertingnr.partyaddress, sizeof(call->redirectingnum)); +- pri_message(pri, " Received redirectingnum '%s' (%d)\n", call->redirectingnum, (int)call->redirectingnum[0]); ++ /* redirectionName is the redirecting.to.name */ ++ if (call->redirecting.to.name.valid) { ++ msg.args.qsig.DivertingLegInformation3.redirection_name_present = 1; ++ q931_copy_name_to_rose(ctrl, ++ &msg.args.qsig.DivertingLegInformation3.redirection_name, ++ &call->redirecting.to.name); + } +- if (originalcallednr.pres >= 0) { +- call->origcalledplan = originalcallednr.npi; +- call->origcalledpres = originalcallednr.pres; +- libpri_copy_string(call->origcallednum, originalcallednr.partyaddress, sizeof(call->origcallednum)); +- pri_message(pri, " Received origcallednum '%s' (%d)\n", call->origcallednum, (int)call->origcallednum[0]); +- } +- libpri_copy_string(call->redirectingname, redirectingname, sizeof(call->redirectingname)); +- libpri_copy_string(call->origcalledname, origcalledname, sizeof(call->origcalledname)); +- return 0; + } +- while (0); + +- return -1; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; + } +- +-static int rose_diverting_leg_information2_encode(struct pri *pri, q931_call *call) ++ ++/*! ++ * \internal ++ * \brief Encode the ETSI DivertingLegInformation3 invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode diversion leg 3. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_etsi_diverting_leg_information3(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, q931_call *call) + { +- int i = 0, j, compsp = 0; +- struct rose_component *comp, *compstk[10]; +- unsigned char buffer[256]; +- int len = 253; +- +-#if 0 /* This is not required by specifications */ +- if (!strlen(call->callername)) { +- return -1; ++ struct rose_msg_invoke msg; ++ ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; + } +-#endif + +- buffer[i] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); +- i++; +- /* Interpretation component */ +- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0x00 /* Discard unrecognized invokes */); +- +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- +- ASN1_PUSH(compstk, compsp, comp); +- /* Invoke component contents */ +- /* Invoke ID */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); +- /* Operation Tag */ +- +- /* ROSE operationId component */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_DIVERTING_LEG_INFORMATION2); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_ETSI_DivertingLegInformation3; ++ msg.invoke_id = get_invokeid(ctrl); + +- /* ROSE ARGUMENT component */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- /* ROSE DivertingLegInformation2.diversionCounter component */ +- /* Always is 1 because other isn't available in the current design */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1); +- +- /* ROSE DivertingLegInformation2.diversionReason component */ +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, redirectingreason_from_q931(pri, call->redirectingreason)); +- +- /* ROSE DivertingLegInformation2.divertingNr component */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); +- +- ASN1_PUSH(compstk, compsp, comp); +- /* Redirecting information always not screened */ +- +- switch(call->redirectingpres) { +- case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: +- case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: +- if (call->redirectingnum && strlen(call->redirectingnum)) { +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- /* NPI of redirected number is not supported in the current design */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4)); +- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum)); +- if (j < 0) +- return -1; +- +- i += j; +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- break; +- } +- /* fall through */ +- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: +- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED: +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i); +- break; +- /* Don't know how to handle this */ +- case PRES_ALLOWED_NETWORK_NUMBER: +- case PRES_PROHIB_NETWORK_NUMBER: +- case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: +- case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i); +- break; +- default: +- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres); +- case PRES_NUMBER_NOT_AVAILABLE: +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i); +- break; ++ if ((call->redirecting.to.number.presentation & PRI_PRES_RESTRICTION) == PRI_PRES_ALLOWED) { ++ msg.args.etsi.DivertingLegInformation3.presentation_allowed_indicator = 1; /* TRUE */ + } +- ASN1_FIXUP(compstk, compsp, buffer, i); + +- /* ROSE DivertingLegInformation2.originalCalledNr component */ +- /* This information isn't supported by current design - duplicate divertingNr */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- /* Redirecting information always not screened */ +- switch(call->redirectingpres) { +- case PRES_ALLOWED_USER_NUMBER_NOT_SCREENED: +- case PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN: +- if (call->redirectingnum && strlen(call->redirectingnum)) { +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, typeofnumber_from_q931(pri, call->redirectingplan >> 4)); +- +- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, call->redirectingnum, strlen(call->redirectingnum)); +- if (j < 0) +- return -1; +- +- i += j; +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- break; +- } +- /* fall through */ +- case PRES_PROHIB_USER_NUMBER_PASSED_SCREEN: +- case PRES_PROHIB_USER_NUMBER_NOT_SCREENED: +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i); +- break; +- /* Don't know how to handle this */ +- case PRES_ALLOWED_NETWORK_NUMBER: +- case PRES_PROHIB_NETWORK_NUMBER: +- case PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN: +- case PRES_PROHIB_USER_NUMBER_FAILED_SCREEN: +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i); +- break; +- default: +- pri_message(pri, "!! Undefined presentation value for redirecting number: %d\n", call->redirectingpres); +- case PRES_NUMBER_NOT_AVAILABLE: +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i); +- break; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode and queue the DivertingLegInformation3 invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode diversion leg 3. ++ * \param messagetype Q.931 message type to add facility ie to. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int rose_diverting_leg_information3_encode(struct pri *ctrl, q931_call *call, ++ int messagetype) ++{ ++ unsigned char buffer[256]; ++ unsigned char *end; ++ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ end = enc_etsi_diverting_leg_information3(ctrl, buffer, buffer + sizeof(buffer), ++ call); ++ break; ++ case PRI_SWITCH_QSIG: ++ end = enc_qsig_diverting_leg_information3(ctrl, buffer, buffer + sizeof(buffer), ++ call); ++ break; ++ default: ++ return -1; + } +- ASN1_FIXUP(compstk, compsp, buffer, i); +- +- /* Fix length of stacked components */ +- while(compsp > 0) { +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ if (!end) { ++ return -1; + } +- +- if (pri_call_apdu_queue(call, Q931_SETUP, buffer, i, NULL, NULL)) +- return -1; +- +- return 0; ++ ++ return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL); + } + +-/* Send the rltThirdParty: Invoke */ +-int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2) ++/*! ++ * \internal ++ * \brief Encode the rltThirdParty invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param callwithid Call-ID information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_dms100_rlt_initiate_transfer(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const q931_call *callwithid) + { +- int i = 0; ++ struct rose_msg_invoke msg; ++ ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_DMS100_RLT_ThirdParty; ++ msg.invoke_id = ROSE_DMS100_RLT_THIRD_PARTY; ++ msg.args.dms100.RLT_ThirdParty.call_id = callwithid->rlt_call_id & 0xFFFFFF; ++ msg.args.dms100.RLT_ThirdParty.reason = 0; /* unused, set to 129 */ ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Send the rltThirdParty: Invoke. ++ * ++ * \note For PRI_SWITCH_DMS100 only. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param c1 Q.931 call leg 1 ++ * \param c2 Q.931 call leg 2 ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int rlt_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2) ++{ + unsigned char buffer[256]; +- struct rose_component *comp = NULL, *compstk[10]; +- const unsigned char rlt_3rd_pty = RLT_THIRD_PARTY; +- q931_call *callwithid = NULL, *apdubearer = NULL; +- int compsp = 0; ++ unsigned char *end; ++ q931_call *apdubearer; ++ q931_call *callwithid; + + if (c2->transferable) { + apdubearer = c1; +@@ -906,279 +1374,415 @@ + } else if (c1->transferable) { + apdubearer = c2; + callwithid = c1; +- } else ++ } else { + return -1; ++ } + +- buffer[i++] = (Q932_PROTOCOL_ROSE); +- buffer[i++] = (0x80 | RLT_SERVICE_ID); /* Service Identifier octet */ ++ end = ++ enc_dms100_rlt_initiate_transfer(ctrl, buffer, buffer + sizeof(buffer), ++ callwithid); ++ if (!end) { ++ return -1; ++ } + +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- +- /* Invoke ID is set to the operation ID */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_3rd_pty); +- +- /* Operation Tag */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_3rd_pty); +- +- /* Additional RLT invoke info - Octet 12 */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- +- ASN1_ADD_WORDCOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, callwithid->rlt_call_id & 0xFFFFFF); /* Length is 3 octets */ +- /* Reason for redirect - unused, set to 129 */ +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i, 0); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- +- if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, i, NULL, NULL)) ++ if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, end - buffer, NULL)) { + return -1; ++ } + + if (q931_facility(apdubearer->pri, apdubearer)) { +- pri_message(pri, "Could not schedule facility message for call %d\n", apdubearer->cr); ++ pri_message(ctrl, "Could not schedule facility message for call %d\n", ++ apdubearer->cr); + return -1; + } + return 0; + } + +-static int add_dms100_transfer_ability_apdu(struct pri *pri, q931_call *c) ++/*! ++ * \internal ++ * \brief Encode the rltOperationInd invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_dms100_rlt_transfer_ability(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end) + { +- int i = 0; +- unsigned char buffer[256]; +- struct rose_component *comp = NULL, *compstk[10]; +- const unsigned char rlt_op_ind = RLT_OPERATION_IND; +- int compsp = 0; ++ struct rose_msg_invoke msg; + +- buffer[i++] = (Q932_PROTOCOL_ROSE); /* Note to self: DON'T set the EXT bit */ +- buffer[i++] = (0x80 | RLT_SERVICE_ID); /* Service Identifier octet */ ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } + +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_DMS100_RLT_OperationInd; ++ msg.invoke_id = ROSE_DMS100_RLT_OPERATION_IND; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- /* Invoke ID is set to the operation ID */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_op_ind); +- +- /* Operation Tag - basically the same as the invoke ID tag */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, rlt_op_ind); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- +- if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL)) +- return -1; +- else +- return 0; ++ return pos; + } + +-/* Sending callername information functions */ +-static int add_callername_facility_ies(struct pri *pri, q931_call *c, int cpe) ++/*! ++ * \internal ++ * \brief Send the rltOperationInd: Invoke. ++ * ++ * \note For PRI_SWITCH_DMS100 only. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Q.931 call leg ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int add_dms100_transfer_ability_apdu(struct pri *ctrl, q931_call *call) + { +- int res = 0; +- int i = 0; + unsigned char buffer[256]; +- unsigned char namelen = 0; +- struct rose_component *comp = NULL, *compstk[10]; +- int compsp = 0; +- int mymessage = 0; +- static unsigned char op_tag[] = { +- 0x2a, /* informationFollowing 42 */ +- 0x86, +- 0x48, +- 0xce, +- 0x15, +- 0x00, +- 0x04 +- }; +- +- if (!strlen(c->callername)) { ++ unsigned char *end; ++ ++ end = enc_dms100_rlt_transfer_ability(ctrl, buffer, buffer + sizeof(buffer)); ++ if (!end) { + return -1; + } + +- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); +- /* Interpretation component */ ++ return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL); ++} + +- if (pri->switchtype == PRI_SWITCH_QSIG) { +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++/*! ++ * \internal ++ * \brief Encode the NI2 InformationFollowing invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_ni2_information_following(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end) ++{ ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; ++ ++ memset(&header, 0, sizeof(header)); ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; + } + +- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_NI2_InformationFollowing; ++ msg.invoke_id = get_invokeid(ctrl); ++ msg.args.ni2.InformationFollowing.value = 0; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- /* Invoke ID */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ return pos; ++} + +- /* Operation Tag */ +- res = asn1_string_encode(ASN1_OBJECTIDENTIFIER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag)); +- if (res < 0) +- return -1; +- i += res; ++/*! ++ * \internal ++ * \brief Encode the Q.SIG CallingName invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param name Name data which to encode name. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_calling_name(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct q931_party_name *name) ++{ ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; + +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- +- if (!cpe) { +- if (pri_call_apdu_queue(c, Q931_SETUP, buffer, i, NULL, NULL)) +- return -1; ++ memset(&header, 0, sizeof(header)); ++ if (ctrl->switchtype == PRI_SWITCH_QSIG) { ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ + } ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } + ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_CallingName; ++ msg.invoke_id = get_invokeid(ctrl); + +- /* Now the APDU that contains the information that needs sent. +- * We can reuse the buffer since the queue function doesn't +- * need it. */ ++ /* CallingName */ ++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.CallingName.name, name); + +- i = 0; +- namelen = strlen(c->callername); +- if (namelen > 50) { +- namelen = 50; /* truncate the name */ +- } ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); +- /* Interpretation component */ ++ return pos; ++} + +- if (pri->switchtype == PRI_SWITCH_QSIG) { +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++/*! ++ * \internal ++ * \brief Send caller name information. ++ * ++ * \note For PRI_SWITCH_NI2 and PRI_SWITCH_QSIG. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode name. ++ * \param cpe TRUE if we are the CPE side. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int add_callername_facility_ies(struct pri *ctrl, q931_call *call, int cpe) ++{ ++ unsigned char buffer[256]; ++ unsigned char *end; ++ int mymessage; ++ ++ if (!call->local_id.name.valid) { ++ return 0; + } + +- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); ++ if (ctrl->switchtype == PRI_SWITCH_NI2 && !cpe) { ++ end = enc_ni2_information_following(ctrl, buffer, buffer + sizeof(buffer)); ++ if (!end) { ++ return -1; ++ } + +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ if (pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL)) { ++ return -1; ++ } + +- /* Invoke ID */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ /* ++ * We can reuse the buffer since the queue function doesn't ++ * need it. ++ */ ++ } + +- /* Operation ID: Calling name */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, SS_CNID_CALLINGNAME); +- +- res = asn1_string_encode((ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, 50, c->callername, namelen); +- if (res < 0) ++ /* CallingName is the local_id.name */ ++ end = enc_qsig_calling_name(ctrl, buffer, buffer + sizeof(buffer), ++ &call->local_id.name); ++ if (!end) { + return -1; +- i += res; +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ } + +- if (cpe) ++ if (cpe) { + mymessage = Q931_SETUP; +- else ++ } else { + mymessage = Q931_FACILITY; ++ } + +- if (pri_call_apdu_queue(c, mymessage, buffer, i, NULL, NULL)) +- return -1; +- +- return 0; ++ return pri_call_apdu_queue(call, mymessage, buffer, end - buffer, NULL); + } + /* End Callername */ + + /* MWI related encode and decode functions */ +-static void mwi_activate_encode_cb(void *data) ++ ++/*! ++ * \internal ++ * \brief Encode the Q.SIG MWIActivate invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param req Served user setup request information. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_mwi_activate_message(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, struct pri_sr *req) + { +- return; ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; ++ ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_MWIActivate; ++ msg.invoke_id = get_invokeid(ctrl); ++ ++ /* The called.number is the served user */ ++ q931_copy_number_to_rose(ctrl, &msg.args.qsig.MWIActivate.served_user_number, ++ &req->called.number); ++ /* ++ * For now, we will just force the numbering plan to unknown to preserve ++ * the original behaviour. ++ */ ++ msg.args.qsig.MWIActivate.served_user_number.plan = 0; /* unknown */ ++ ++ msg.args.qsig.MWIActivate.basic_service = 1; /* speech */ ++ ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; + } + +-int mwi_message_send(struct pri* pri, q931_call *call, struct pri_sr *req, int activate) ++/*! ++ * \internal ++ * \brief Encode the Q.SIG MWIDeactivate invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param req Served user setup request information. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_mwi_deactivate_message(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, struct pri_sr *req) + { +- int i = 0; +- unsigned char buffer[255] = ""; +- int destlen = strlen(req->called); +- struct rose_component *comp = NULL, *compstk[10]; +- int compsp = 0; +- int res; ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; + +- if (destlen <= 0) { +- return -1; +- } else if (destlen > 20) +- destlen = 20; /* Destination number cannot be greater then 20 digits */ ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } + +- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); +- /* Interpretation component */ ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_MWIDeactivate; ++ msg.invoke_id = get_invokeid(ctrl); + +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ /* The called.number is the served user */ ++ q931_copy_number_to_rose(ctrl, &msg.args.qsig.MWIDeactivate.served_user_number, ++ &req->called.number); ++ /* ++ * For now, we will just force the numbering plan to unknown to preserve ++ * the original behaviour. ++ */ ++ msg.args.qsig.MWIDeactivate.served_user_number.plan = 0; /* unknown */ + +- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 0); ++ msg.args.qsig.MWIDeactivate.basic_service = 1; /* speech */ + +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ return pos; ++} + +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, (activate) ? SS_MWI_ACTIVATE : SS_MWI_DEACTIVATE); +- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- /* PartyNumber */ +- res = asn1_string_encode((ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), &buffer[i], sizeof(buffer)-i, destlen, req->called, destlen); +- +- if (res < 0) ++/*! ++ * \brief Encode and queue the Q.SIG MWIActivate/MWIDeactivate invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg to queue message. ++ * \param req Served user setup request information. ++ * \param activate Nonzero to do the activate message. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int mwi_message_send(struct pri *ctrl, q931_call *call, struct pri_sr *req, int activate) ++{ ++ unsigned char buffer[255]; ++ unsigned char *end; ++ ++ if (!req->called.number.valid || !req->called.number.str[0]) { + return -1; +- i += res; ++ } + +- /* Enumeration: basicService */ +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1 /* contents: Voice */); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ if (activate) { ++ end = enc_qsig_mwi_activate_message(ctrl, buffer, buffer + sizeof(buffer), req); ++ } else { ++ end = ++ enc_qsig_mwi_deactivate_message(ctrl, buffer, buffer + sizeof(buffer), req); ++ } ++ if (!end) { ++ return -1; ++ } + +- return pri_call_apdu_queue(call, Q931_SETUP, buffer, i, mwi_activate_encode_cb, NULL); ++ return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer, NULL); + } + /* End MWI */ + + /* EECT functions */ +-int eect_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2) ++/*! ++ * \internal ++ * \brief Encode the NI2 InitiateTransfer invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode transfer information. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_ni2_initiate_transfer(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, q931_call *call) + { +- int i = 0; +- int res = 0; +- unsigned char buffer[255] = ""; +- short call_reference = c2->cr ^ 0x8000; /* Let's do the trickery to make sure the flag is correct */ +- struct rose_component *comp = NULL, *compstk[10]; +- int compsp = 0; +- static unsigned char op_tag[] = { +- 0x2A, +- 0x86, +- 0x48, +- 0xCE, +- 0x15, +- 0x00, +- 0x08, +- }; ++ struct rose_msg_invoke msg; + +- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE); ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } + +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_NI2_InitiateTransfer; ++ msg.invoke_id = get_invokeid(ctrl); ++ /* Let's do the trickery to make sure the flag is correct */ ++ msg.args.ni2.InitiateTransfer.call_reference = call->cr ^ 0x8000; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ return pos; ++} + +- res = asn1_string_encode(ASN1_OBJECTIDENTIFIER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag)); +- if (res < 0) ++/*! ++ * \brief Start a 2BCT ++ * ++ * \note Called for PRI_SWITCH_NI2, PRI_SWITCH_LUCENT5E, and PRI_SWITCH_ATT4ESS ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param c1 Q.931 call leg 1 ++ * \param c2 Q.931 call leg 2 ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int eect_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2) ++{ ++ unsigned char buffer[255]; ++ unsigned char *end; ++ ++ end = enc_ni2_initiate_transfer(ctrl, buffer, buffer + sizeof(buffer), c2); ++ if (!end) { + return -1; +- i += res; ++ } + +- ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer, i, call_reference); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- +- res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, i, NULL, NULL); +- if (res) { +- pri_message(pri, "Could not queue APDU in facility message\n"); ++ if (pri_call_apdu_queue(c1, Q931_FACILITY, buffer, end - buffer, NULL)) { ++ pri_message(ctrl, "Could not queue APDU in facility message\n"); + return -1; + } + + /* Remember that if we queue a facility IE for a facility message we + * have to explicitly send the facility message ourselves */ + +- res = q931_facility(c1->pri, c1); +- if (res) { +- pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr); ++ if (q931_facility(c1->pri, c1)) { ++ pri_message(ctrl, "Could not schedule facility message for call %d\n", c1->cr); + return -1; + } + +@@ -1187,1494 +1791,2316 @@ + /* End EECT */ + + /* QSIG CF CallRerouting */ +-int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason) ++/*! ++ * \internal ++ * \brief Encode the Q.SIG CallRerouting invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Q.931 call leg. ++ * \param calling Call rerouting/deflecting updated caller data. ++ * \param deflection Call rerouting/deflecting redirection data. ++ * \param subscription_option Diverting user subscription option to specify if caller is notified. ++ * ++ * \note ++ * deflection->to is the new called number and must always be present. ++ * \note ++ * subscription option: ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2) ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_call_rerouting(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, q931_call *call, const struct q931_party_id *calling, ++ const struct q931_party_redirecting *deflection, int subscription_option) + { +-/*CallRerouting ::= OPERATION +- -- Sent from the Served User PINX to the Rerouting PINX +- ARGUMENT SEQUENCE +- { reroutingReason DiversionReason, +- originalReroutingReason [0] IMPLICIT DiversionReason OPTIONAL, +- calledAddress Address, +- diversionCounter INTEGER (1..15), +- pSS1InfoElement PSS1InformationElement, +- -- The basic call information elements Bearer capability, High layer compatibility, Low +- -- layer compatibity, Progress indicator and Party category can be embedded in the +- -- pSS1InfoElement in accordance with 6.5.3.1.5 +- lastReroutingNr [1] PresentedNumberUnscreened, +- subscriptionOption [2] IMPLICIT SubscriptionOption, ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; ++ unsigned char *q931ie_pos; + +- callingPartySubaddress [3] PartySubaddress OPTIONAL, ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 2; /* rejectAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } + +- callingNumber [4] PresentedNumberScreened, ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_CallRerouting; ++ msg.invoke_id = get_invokeid(ctrl); + +- callingName [5] Name OPTIONAL, +- originalCalledNr [6] PresentedNumberUnscreened OPTIONAL, +- redirectingName [7] Name OPTIONAL, +- originalCalledName [8] Name OPTIONAL, +- extension CHOICE { +- [9] IMPLICIT Extension , +- [10] IMPLICIT SEQUENCE OF Extension } OPTIONAL } +-*/ ++ msg.args.qsig.CallRerouting.rerouting_reason = ++ redirectingreason_from_q931(ctrl, deflection->reason); + +- int i = 0, j; +- int res = 0; +- unsigned char buffer[255] = ""; +- int len = 253; +- struct rose_component *comp = NULL, *compstk[10]; +- int compsp = 0; +- static unsigned char op_tag[] = { +- 0x13, +- }; ++ /* calledAddress is the passed in deflection->to address */ ++ q931_copy_address_to_rose(ctrl, &msg.args.qsig.CallRerouting.called, &deflection->to); + +- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); +- /* Interpretation component */ ++ msg.args.qsig.CallRerouting.diversion_counter = deflection->count; + +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ /* pSS1InfoElement */ ++ q931ie_pos = msg.args.qsig.CallRerouting.q931ie_contents; ++ *q931ie_pos++ = 0x04; /* Bearer Capability IE */ ++ *q931ie_pos++ = 0x03; /* len */ ++ *q931ie_pos++ = 0x80 | call->transcapability; /* Rxed transfer capability. */ ++ *q931ie_pos++ = 0x90; /* circuit mode, 64kbit/s */ ++ *q931ie_pos++ = 0xa3; /* level1 protocol, a-law */ ++ *q931ie_pos++ = 0x95; /* locking shift to codeset 5 (national use) */ ++ *q931ie_pos++ = 0x32; /* Unknown ie */ ++ *q931ie_pos++ = 0x01; /* Unknown ie len */ ++ *q931ie_pos++ = 0x81; /* Unknown ie body */ ++ msg.args.qsig.CallRerouting.q931ie.length = q931ie_pos ++ - msg.args.qsig.CallRerouting.q931ie_contents; + +- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */ ++ /* lastReroutingNr is the passed in deflection->from.number */ ++ q931_copy_presented_number_unscreened_to_rose(ctrl, ++ &msg.args.qsig.CallRerouting.last_rerouting, &deflection->from.number); + +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ msg.args.qsig.CallRerouting.subscription_option = subscription_option; + +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); ++ /* callingNumber is the passed in calling->number */ ++ q931_copy_presented_number_screened_to_rose(ctrl, ++ &msg.args.qsig.CallRerouting.calling, &calling->number); + +- res = asn1_string_encode(ASN1_INTEGER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag)); +- if (res < 0) +- return -1; +- i += res; ++ /* callingPartySubaddress is the passed in calling->subaddress if valid */ ++ q931_copy_subaddress_to_rose(ctrl, &msg.args.qsig.CallRerouting.calling_subaddress, ++ &calling->subaddress); + +- /* call rerouting argument */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ /* callingName is the passed in calling->name if valid */ ++ if (calling->name.valid) { ++ msg.args.qsig.CallRerouting.calling_name_present = 1; ++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.CallRerouting.calling_name, ++ &calling->name); ++ } + +- /* reroutingReason DiversionReason */ ++ if (1 < deflection->count) { ++ /* originalCalledNr is the deflection->orig_called.number */ ++ msg.args.qsig.CallRerouting.original_called_present = 1; ++ q931_copy_presented_number_unscreened_to_rose(ctrl, ++ &msg.args.qsig.CallRerouting.original_called, ++ &deflection->orig_called.number); + +- if (reason) { +- if (!strcasecmp(reason, "cfu")) +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 1); /* cfu */ +- else if (!strcasecmp(reason, "cfb")) +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 2); /* cfb */ +- else if (!strcasecmp(reason, "cfnr")) +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 3); /* cfnr */ +- } else { +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); /* unknown */ ++ msg.args.qsig.CallRerouting.original_rerouting_reason_present = 1; ++ if (deflection->orig_called.number.valid) { ++ msg.args.qsig.CallRerouting.original_rerouting_reason = ++ redirectingreason_from_q931(ctrl, deflection->orig_reason); ++ } else { ++ msg.args.qsig.CallRerouting.original_rerouting_reason = ++ QSIG_DIVERT_REASON_UNKNOWN; ++ } ++ ++ /* originalCalledName is the deflection->orig_called.name */ ++ if (deflection->orig_called.name.valid) { ++ msg.args.qsig.CallRerouting.original_called_name_present = 1; ++ q931_copy_name_to_rose(ctrl, ++ &msg.args.qsig.CallRerouting.original_called_name, ++ &deflection->orig_called.name); ++ } + } + ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- /* calledAddress Address */ +- /* explicit sequence tag for Address */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- /* implicit choice public party number tag */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- /* type of public party number = unknown */ +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); +- /* NumberDigits of public party number */ +- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, (char*)dest, strlen(dest)); +- if (j < 0) +- return -1; ++ return pos; ++} + +- i += j; +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++/*! ++ * \internal ++ * \brief Encode the ETSI CallRerouting invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Q.931 call leg. ++ * \param calling Call rerouting/deflecting updated caller data. ++ * \param deflection Call rerouting/deflecting redirection data. ++ * \param subscription_option Diverting user subscription option to specify if caller is notified. ++ * ++ * \note ++ * deflection->to is the new called number and must always be present. ++ * \note ++ * subscription option: ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2) ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_etsi_call_rerouting(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, q931_call *call, const struct q931_party_id *calling, ++ const struct q931_party_redirecting *deflection, int subscription_option) ++{ ++ struct rose_msg_invoke msg; ++ unsigned char *q931ie_pos; + +- /* diversionCounter INTEGER (1..15) */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, 1); ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } + +- /* pSS1InfoElement */ +- ASN1_ADD_SIMPLE(comp, (ASN1_APPLICATION | ASN1_TAG_0 ), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- buffer[i++] = (0x04); /* Bearer Capability IE */ +- buffer[i++] = (0x03); /* len */ +- buffer[i++] = (0x80); /* ETSI Standard, Speech */ +- buffer[i++] = (0x90); /* circuit mode, 64kbit/s */ +- buffer[i++] = (0xa3); /* level1 protocol, a-law */ +- buffer[i++] = (0x95); /* locking shift to codeset 5 (national use) */ +- buffer[i++] = (0x32); /* Unknown ie */ +- buffer[i++] = (0x01); /* Unknown ie len */ +- buffer[i++] = (0x81); /* Unknown ie body */ +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_ETSI_CallRerouting; ++ msg.invoke_id = get_invokeid(ctrl); + +- /* lastReroutingNr [1]*/ +- /* implicit optional lastReroutingNr tag */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ msg.args.etsi.CallRerouting.rerouting_reason = ++ redirectingreason_from_q931(ctrl, deflection->reason); + +- /* implicit choice presented number unscreened tag */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ /* calledAddress is the passed in deflection->to address */ ++ q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallRerouting.called_address, ++ &deflection->to); + +- /* implicit choice public party number tag */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- /* type of public party number = unknown */ +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 0); +- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, original?(char*)original:c->callednum, original?strlen(original):strlen(c->callednum)); +- if (j < 0) +- return -1; ++ msg.args.etsi.CallRerouting.rerouting_counter = deflection->count; + +- i += j; +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ /* q931InfoElement */ ++ q931ie_pos = msg.args.etsi.CallRerouting.q931ie_contents; ++ *q931ie_pos++ = 0x04; /* Bearer Capability IE */ ++ *q931ie_pos++ = 0x03; /* len */ ++ *q931ie_pos++ = 0x80 | call->transcapability; /* Rxed transfer capability. */ ++ *q931ie_pos++ = 0x90; /* circuit mode, 64kbit/s */ ++ *q931ie_pos++ = 0xa3; /* level1 protocol, a-law */ ++ msg.args.etsi.CallRerouting.q931ie.length = q931ie_pos ++ - msg.args.etsi.CallRerouting.q931ie_contents; + +- /* subscriptionOption [2]*/ +- /* implicit optional lastReroutingNr tag */ +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); /* noNotification */ ++ /* lastReroutingNr is the passed in deflection->from.number */ ++ q931_copy_presented_number_unscreened_to_rose(ctrl, ++ &msg.args.etsi.CallRerouting.last_rerouting, &deflection->from.number); + +- /* callingNumber [4]*/ +- /* implicit optional callingNumber tag */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ msg.args.etsi.CallRerouting.subscription_option = subscription_option; + +- /* implicit choice presented number screened tag */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ /* callingPartySubaddress is the passed in calling->subaddress if valid */ ++ q931_copy_subaddress_to_rose(ctrl, &msg.args.etsi.CallRerouting.calling_subaddress, ++ &calling->subaddress); + +- /* implicit choice presentationAllowedAddress tag */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- /* type of public party number = subscriber number */ +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 4); +- j = asn1_string_encode(ASN1_NUMERICSTRING, &buffer[i], len - i, 20, c->callernum, strlen(c->callernum)); +- if (j < 0) +- return -1; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- i += j; +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ return pos; ++} + +- /* Screeening Indicator network provided */ +- ASN1_ADD_BYTECOMP(comp, ASN1_ENUMERATED, buffer, i, 3); ++/*! ++ * \internal ++ * \brief Encode the ETSI CallDeflection invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Q.931 call leg. ++ * \param deflection Call deflection address. ++ * ++ * \note ++ * deflection is the new called number and must always be present. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_etsi_call_deflection(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, q931_call *call, const struct q931_party_id *deflection) ++{ ++ struct rose_msg_invoke msg; + +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } + +- /**/ ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_ETSI_CallDeflection; ++ msg.invoke_id = get_invokeid(ctrl); + +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); ++ /* deflectionAddress is the passed in deflection->to address */ ++ q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallDeflection.deflection, ++ deflection); + +- res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL); +- if (res) { +- pri_message(pri, "Could not queue ADPU in facility message\n"); ++ msg.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present = 1; ++ switch (deflection->number.presentation & PRI_PRES_RESTRICTION) { ++ case PRI_PRES_ALLOWED: ++ msg.args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user = 1; ++ break; ++ default: ++ case PRI_PRES_UNAVAILABLE: ++ case PRI_PRES_RESTRICTED: ++ break; ++ } ++ ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode and queue the CallRerouting/CallDeflection message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. ++ * \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.) ++ * \param deflection Call rerouting/deflecting redirection data. ++ * \param subscription_option Diverting user subscription option to specify if caller is notified. ++ * ++ * \note ++ * deflection->to is the new called number and must always be present. ++ * \note ++ * subscription option: ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2) ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int rose_reroute_request_encode(struct pri *ctrl, q931_call *call, ++ const struct q931_party_id *caller, const struct q931_party_redirecting *deflection, ++ int subscription_option) ++{ ++ unsigned char buffer[256]; ++ unsigned char *end; ++ ++ if (!caller) { ++ /* ++ * We are deflecting an incoming call back to the network. ++ * Therefore, the Caller-ID is the remote party. ++ */ ++ caller = &call->remote_id; ++ } ++ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ if (q931_is_ptmp(ctrl)) { ++ end = ++ enc_etsi_call_deflection(ctrl, buffer, buffer + sizeof(buffer), call, ++ &deflection->to); ++ } else { ++ end = ++ enc_etsi_call_rerouting(ctrl, buffer, buffer + sizeof(buffer), call, ++ caller, deflection, subscription_option); ++ } ++ break; ++ case PRI_SWITCH_QSIG: ++ end = ++ enc_qsig_call_rerouting(ctrl, buffer, buffer + sizeof(buffer), call, caller, ++ deflection, subscription_option); ++ break; ++ default: + return -1; + } ++ if (!end) { ++ return -1; ++ } + +- /* Remember that if we queue a facility IE for a facility message we +- * have to explicitly send the facility message ourselves */ ++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL); ++} + +- res = q931_facility(c->pri, c); +- if (res) { +- pri_message(pri, "Could not schedule facility message for call %d\n", c->cr); ++/*! ++ * \brief Send the CallRerouting/CallDeflection message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. ++ * \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.) ++ * \param deflection Call rerouting/deflecting redirection data. ++ * \param subscription_option Diverting user subscription option to specify if caller is notified. ++ * ++ * \note ++ * deflection->to is the new called number and must always be present. ++ * \note ++ * subscription option: ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2) ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int send_reroute_request(struct pri *ctrl, q931_call *call, ++ const struct q931_party_id *caller, const struct q931_party_redirecting *deflection, ++ int subscription_option) ++{ ++ if (!deflection->to.number.str[0]) { ++ /* Must have a deflect to number. That is the point of deflection. */ + return -1; + } ++ if (rose_reroute_request_encode(ctrl, call, caller, deflection, subscription_option) ++ || q931_facility(ctrl, call)) { ++ pri_message(ctrl, ++ "Could not schedule facility message for CallRerouting/CallDeflection message.\n"); ++ return -1; ++ } + + return 0; + } ++ ++/*! ++ * \brief Send the Q.SIG CallRerouting invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Q.931 call leg. ++ * \param dest Destination number. ++ * \param original Original called number. ++ * \param reason Rerouting reason: cfu, cfb, cfnr ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int qsig_cf_callrerouting(struct pri *ctrl, q931_call *call, const char *dest, ++ const char *original, const char *reason) ++{ ++ struct q931_party_redirecting reroute; ++ ++ q931_party_redirecting_init(&reroute); ++ ++ /* Rerouting to the dest number. */ ++ reroute.to.number.valid = 1; ++ reroute.to.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164; ++ reroute.to.number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ libpri_copy_string(reroute.to.number.str, dest, sizeof(reroute.to.number.str)); ++ ++ /* Rerouting from the original number. */ ++ if (original) { ++ reroute.from.number.valid = 1; ++ reroute.from.number.plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164; ++ libpri_copy_string(reroute.from.number.str, original, sizeof(reroute.from.number.str)); ++ } else { ++ q931_party_address_to_id(&reroute.from, &call->called); ++ } ++ reroute.from.number.presentation = PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ ++ /* Decode the rerouting reason. */ ++ reroute.reason = PRI_REDIR_UNKNOWN; ++ if (!reason) { ++ /* No reason for rerouting given. */ ++ } else if (!strcasecmp(reason, "cfu")) { ++ reroute.reason = PRI_REDIR_UNCONDITIONAL; ++ } else if (!strcasecmp(reason, "cfb")) { ++ reroute.reason = PRI_REDIR_FORWARD_ON_BUSY; ++ } else if (!strcasecmp(reason, "cfnr")) { ++ reroute.reason = PRI_REDIR_FORWARD_ON_NO_REPLY; ++ } ++ ++ reroute.count = (call->redirecting.count < PRI_MAX_REDIRECTS) ++ ? call->redirecting.count + 1 : PRI_MAX_REDIRECTS; ++ ++ if (!call->redirecting.orig_called.number.valid) { ++ /* ++ * Since we do not already have an originally called party, we ++ * must either be the first redirected to party or this call ++ * has not been redirected before. ++ * ++ * Preserve who redirected to us as the originally called party. ++ */ ++ reroute.orig_called = call->redirecting.from; ++ reroute.orig_reason = call->redirecting.reason; ++ } else { ++ reroute.orig_called = call->redirecting.orig_called; ++ reroute.orig_reason = call->redirecting.orig_reason; ++ } ++ ++ return send_reroute_request(ctrl, call, NULL, &reroute, 0 /* noNotification */); ++} + /* End QSIG CC-CallRerouting */ + +-static int anfpr_pathreplacement_respond(struct pri *pri, q931_call *call, q931_ie *ie) ++/* ++ * From Mantis issue 7778 description: (ETS 300 258, ISO 13863) ++ * After both legs of the call are setup and Asterisk has a successful "tromboned" or bridged call ... ++ * Asterisk sees both 'B' channels (from trombone) are on same PRI/technology and initiates "Path Replacement" events ++ * a. Asterisk sends "Transfer Complete" messages to both call legs ++ * b. QSIG Switch sends "PathReplacement" message on one of the legs (random 1-10sec timer expires - 1st leg to send is it!) ++ * c. Asterisk rebroadcasts "PathReplacement" message to other call leg ++ * d. QSIG Switch sends "Disconnect" message on one of the legs (same random timer sequence as above) ++ * e. Asterisk rebroadcasts "Disconnect" message to other call leg ++ * f. QSIG Switch disconnects Asterisk call legs - callers are now within QSIG switch ++ * ++ * Just need to resend the message to the other tromboned leg of the call. ++ */ ++static int anfpr_pathreplacement_respond(struct pri *ctrl, q931_call *call, q931_ie *ie) + { + int res; +- +- res = pri_call_apdu_queue_cleanup(call->bridged_call); +- if (res) { +- pri_message(pri, "Could not Clear queue ADPU\n"); +- return -1; +- } +- ++ ++ pri_call_apdu_queue_cleanup(call->bridged_call); ++ + /* Send message */ +- res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len, NULL, NULL); ++ res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len, NULL); + if (res) { +- pri_message(pri, "Could not queue ADPU in facility message\n"); +- return -1; ++ pri_message(ctrl, "Could not queue ADPU in facility message\n"); ++ return -1; + } +- ++ + /* Remember that if we queue a facility IE for a facility message we + * have to explicitly send the facility message ourselves */ +- ++ + res = q931_facility(call->bridged_call->pri, call->bridged_call); + if (res) { +- pri_message(pri, "Could not schedule facility message for call %d\n", call->bridged_call->cr); ++ pri_message(ctrl, "Could not schedule facility message for call %d\n", ++ call->bridged_call->cr); + return -1; + } + + return 0; + } ++ + /* AFN-PR */ +-int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2) ++/*! ++ * \brief Start a Q.SIG path replacement. ++ * ++ * \note Called for PRI_SWITCH_QSIG ++ * ++ * \note Did all the tests to see if we're on the same PRI and ++ * are on a compatible switchtype. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param c1 Q.931 call leg 1 ++ * \param c2 Q.931 call leg 2 ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int anfpr_initiate_transfer(struct pri *ctrl, q931_call *c1, q931_call *c2) + { +- /* Did all the tests to see if we're on the same PRI and +- * are on a compatible switchtype */ +- /* TODO */ +- int i = 0; +- int res = 0; +- unsigned char buffer[255] = ""; +- unsigned short call_reference = c2->cr; +- struct rose_component *comp = NULL, *compstk[10]; +- unsigned char buffer2[255] = ""; +- int compsp = 0; +- static unsigned char op_tag[] = { +- 0x0C, +- }; +- +- /* Channel 1 */ +- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); +- +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer, i, 0); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer, i, 0); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- +- /* Interpretation component */ +- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer, i, 2); /* reject - to get feedback from QSIG switch */ +- +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, get_invokeid(pri)); +- +- res = asn1_string_encode(ASN1_INTEGER, &buffer[i], sizeof(buffer)-i, sizeof(op_tag), op_tag, sizeof(op_tag)); +- if (res < 0) ++ unsigned char buffer[255]; ++ unsigned char *pos; ++ unsigned char *end; ++ int res; ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; ++ ++ end = buffer + sizeof(buffer); ++ ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 2; /* rejectAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, buffer, end, &header); ++ if (!pos) { + return -1; +- i += res; +- +- ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- buffer[i++] = (0x0a);/* Enumeration endDesignation */ +- buffer[i++] = (0x01);/* Len */ +- buffer[i++] = (0x00);/* primaryEnd */ +- buffer[i++] = (0x81);/* redirectionNumber = presentationRestricted */ +- buffer[i++] = (0x00);/* Len */ +- buffer[i++] = (0x0a);/* Enumeration callStatus */ +- buffer[i++] = (0x01);/* Len */ +- buffer[i++] = (0x01);/* alerting */ ++ } + +- /* +- * Where does this element come from? It is not in Q.SIG ECMA-178. +- * We send this but we will not accept it. +- * This seems to be a cut and paste error from eect_initiate_transfer(). +- */ +- ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer, i, call_reference); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_CallTransferComplete; ++ msg.invoke_id = get_invokeid(ctrl); ++ msg.args.qsig.CallTransferComplete.end_designation = 0; /* primaryEnd */ ++ msg.args.qsig.CallTransferComplete.redirection.presentation = 1; /* presentationRestricted */ ++ msg.args.qsig.CallTransferComplete.call_status = 1; /* alerting */ ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ if (!pos) { ++ return -1; ++ } + +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- +- res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, i, NULL, NULL); ++ res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, pos - buffer, NULL); + if (res) { +- pri_message(pri, "Could not queue ADPU in facility message\n"); ++ pri_message(ctrl, "Could not queue ADPU in facility message\n"); + return -1; + } +- ++ + /* Remember that if we queue a facility IE for a facility message we + * have to explicitly send the facility message ourselves */ +- ++ + res = q931_facility(c1->pri, c1); + if (res) { +- pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr); ++ pri_message(ctrl, "Could not schedule facility message for call %d\n", c1->cr); + return -1; + } +- +- /* Channel 2 */ +- i = 0; +- res = 0; +- compsp = 0; +- +- buffer2[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_EXTENSIONS); +- +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_NFE, buffer2, i); +- ASN1_PUSH(compstk, compsp, comp); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_0), buffer2, i, 0); +- ASN1_ADD_BYTECOMP(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2), buffer2, i, 0); +- ASN1_FIXUP(compstk, compsp, buffer2, i); +- +- /* Interpretation component */ +- ASN1_ADD_BYTECOMP(comp, COMP_TYPE_INTERPRETATION, buffer2, i, 2); /* reject */ +- +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer2, i); +- ASN1_PUSH(compstk, compsp, comp); +- +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer2, i, get_invokeid(pri)); +- +- res = asn1_string_encode(ASN1_INTEGER, &buffer2[i], sizeof(buffer2)-i, sizeof(op_tag), op_tag, sizeof(op_tag)); +- if (res < 0) ++ ++ /* Reuse the previous message header */ ++ pos = facility_encode_header(ctrl, buffer, end, &header); ++ if (!pos) { + return -1; +- i += res; +- +- ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_CONSTRUCTOR), buffer2, i); +- ASN1_PUSH(compstk, compsp, comp); +- buffer2[i++] = (0x0a);/* Enumeration endDesignation */ +- buffer2[i++] = (0x01);/* Len */ +- buffer2[i++] = (0x01);/* secondaryEnd */ +- buffer2[i++] = (0x81);/* redirectionNumber = presentationRestricted */ +- buffer2[i++] = (0x00);/* Len */ +- buffer2[i++] = (0x0a);/* Enumeration callStatus */ +- buffer2[i++] = (0x01);/* Len */ +- buffer2[i++] = (0x01);/* alerting */ ++ } + +- /* +- * Where does this element come from? It is not in Q.SIG ECMA-178. +- * We send this but we will not accept it. +- * This seems to be a cut and paste error from eect_initiate_transfer(). +- */ +- ASN1_ADD_WORDCOMP(comp, ASN1_INTEGER, buffer2, i, call_reference); ++ /* Update the previous message */ ++ msg.invoke_id = get_invokeid(ctrl); ++ msg.args.qsig.CallTransferComplete.end_designation = 1; /* secondaryEnd */ ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ if (!pos) { ++ return -1; ++ } + +- ASN1_FIXUP(compstk, compsp, buffer2, i); +- ASN1_FIXUP(compstk, compsp, buffer2, i); +- +- +- res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer2, i, NULL, NULL); ++ res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer, pos - buffer, NULL); + if (res) { +- pri_message(pri, "Could not queue ADPU in facility message\n"); ++ pri_message(ctrl, "Could not queue ADPU in facility message\n"); + return -1; + } +- ++ + /* Remember that if we queue a facility IE for a facility message we + * have to explicitly send the facility message ourselves */ +- ++ + res = q931_facility(c2->pri, c2); + if (res) { +- pri_message(pri, "Could not schedule facility message for call %d\n", c1->cr); ++ pri_message(ctrl, "Could not schedule facility message for call %d\n", c2->cr); + return -1; + } +- ++ + return 0; + } + /* End AFN-PR */ + + /* AOC */ +-static int aoc_aoce_charging_request_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) ++/*! ++ * \internal ++ * \brief Encode the ETSI AOCEChargingUnit invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param chargedunits Number of units charged to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_etsi_aoce_charging_unit(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, long chargedunits) + { +- int chargingcase = -1; +- unsigned char *vdata = data; +- struct rose_component *comp = NULL; +- int pos1 = 0; ++ struct rose_msg_invoke msg; + +- if (pri->debug & PRI_DEBUG_AOC) +- dump_apdu (pri, data, len); ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } + +- do { +- GET_COMPONENT(comp, pos1, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "!! Invalid AOC Charging Request argument. Expected Enumerated (0x0A) but Received 0x%02X\n"); +- ASN1_GET_INTEGER(comp, chargingcase); +- if (chargingcase >= 0 && chargingcase <= 2) { +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "Channel %d/%d, Call %d - received AOC charging request - charging case: %i\n", +- call->ds1no, call->channelno, call->cr, chargingcase); +- } else { +- pri_message(pri, "!! unkown AOC ChargingCase: 0x%02X", chargingcase); +- chargingcase = -1; +- } +- NEXT_COMPONENT(comp, pos1); +- } while (pos1 < len); +- if (pos1 < len) { +- pri_message(pri, "!! Only reached position %i in %i bytes long AOC-E structure:", pos1, len ); +- dump_apdu (pri, data, len); +- return -1; /* Aborted before */ ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_ETSI_AOCEChargingUnit; ++ msg.invoke_id = get_invokeid(ctrl); ++ msg.args.etsi.AOCEChargingUnit.type = 1; /* charging_unit */ ++ if (chargedunits <= 0) { ++ msg.args.etsi.AOCEChargingUnit.charging_unit.free_of_charge = 1; ++ } else { ++ msg.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.num_records = 1; ++ msg.args.etsi.AOCEChargingUnit.charging_unit.specific.recorded.list[0]. ++ number_of_units = chargedunits; + } +- return 0; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; + } +- + +-static int aoc_aoce_charging_unit_decode(struct pri *pri, q931_call *call, unsigned char *data, int len) ++/*! ++ * \internal ++ * \brief Send the ETSI AOCEChargingUnit invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode AOC. ++ * \param chargedunits Number of units charged to encode. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int aoc_aoce_charging_unit_encode(struct pri *ctrl, q931_call *call, ++ long chargedunits) + { +- long chargingunits = 0, chargetype = -1, temp, chargeIdentifier = -1; +- unsigned char *vdata = data; +- struct rose_component *comp1 = NULL, *comp2 = NULL, *comp3 = NULL; +- int pos1 = 0, pos2, pos3, sublen2, sublen3; +- struct addressingdataelements_presentednumberunscreened chargednr; ++ unsigned char buffer[255]; ++ unsigned char *end; + +- if (pri->debug & PRI_DEBUG_AOC) +- dump_apdu (pri, data, len); ++ /* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */ + +- do { +- GET_COMPONENT(comp1, pos1, vdata, len); /* AOCEChargingUnitInfo */ +- CHECK_COMPONENT(comp1, ASN1_SEQUENCE, "!! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but Received 0x%02X\n"); +- SUB_COMPONENT(comp1, pos1); +- GET_COMPONENT(comp1, pos1, vdata, len); +- switch (comp1->type) { +- case (ASN1_SEQUENCE | ASN1_CONSTRUCTOR): /* specificChargingUnits */ +- sublen2 = comp1->len; +- pos2 = pos1; +- comp2 = comp1; +- SUB_COMPONENT(comp2, pos2); +- do { +- GET_COMPONENT(comp2, pos2, vdata, len); +- switch (comp2->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* RecordedUnitsList (0xA1) */ +- SUB_COMPONENT(comp2, pos2); +- GET_COMPONENT(comp2, pos2, vdata, len); +- CHECK_COMPONENT(comp2, ASN1_SEQUENCE, "!! Invalid AOC-E Charging Unit argument. Expected Sequence (0x30) but received 0x02%X\n"); /* RecordedUnits */ +- sublen3 = pos2 + comp2->len; +- pos3 = pos2; +- comp3 = comp2; +- SUB_COMPONENT(comp3, pos3); +- do { +- GET_COMPONENT(comp3, pos3, vdata, len); +- switch (comp3->type) { +- case ASN1_INTEGER: /* numberOfUnits */ +- ASN1_GET_INTEGER(comp3, temp); +- chargingunits += temp; +- case ASN1_NULL: /* notAvailable */ +- break; +- default: +- pri_message(pri, "!! Don't know how to handle 0x%02X in AOC-E RecordedUnits\n", comp3->type); +- } +- NEXT_COMPONENT(comp3, pos3); +- } while (pos3 < sublen3); +- if (pri->debug & PRI_DEBUG_AOC) +- pri_message(pri, "Channel %d/%d, Call %d - received AOC-E charging: %i unit%s\n", +- call->ds1no, call->channelno, call->cr, chargingunits, (chargingunits == 1) ? "" : "s"); +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_2): /* AOCEBillingID (0xA2) */ +- SUB_COMPONENT(comp2, pos2); +- GET_COMPONENT(comp2, pos2, vdata, len); +- ASN1_GET_INTEGER(comp2, chargetype); +- pri_message(pri, "!! not handled: Channel %d/%d, Call %d - received AOC-E billing ID: %i\n", +- call->ds1no, call->channelno, call->cr, chargetype); +- break; +- default: +- pri_message(pri, "!! Don't know how to handle 0x%02X in AOC-E RecordedUnitsList\n", comp2->type); +- } +- NEXT_COMPONENT(comp2, pos2); +- } while (pos2 < sublen2); +- break; +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* freeOfCharge (0x81) */ +- if (pri->debug & PRI_DEBUG_AOC) +- pri_message(pri, "Channel %d/%d, Call %d - received AOC-E free of charge\n", call->ds1no, call->channelno, call->cr); +- chargingunits = 0; +- break; +- default: +- pri_message(pri, "!! Invalid AOC-E specificChargingUnits. Expected Sequence (0x30) or Object Identifier (0x81/0x01) but received 0x%02X\n", comp1->type); +- } +- NEXT_COMPONENT(comp1, pos1); +- GET_COMPONENT(comp1, pos1, vdata, len); /* get optional chargingAssociation. will 'break' when reached end of structure */ +- switch (comp1->type) { +- /* TODO: charged number is untested - please report! */ +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* chargedNumber (0xA0) */ +- if(rose_presented_number_unscreened_decode(pri, call, comp1->data, comp1->len, &chargednr) != 0) +- return -1; +- pri_message(pri, "!! not handled: Received ChargedNr '%s' \n", chargednr.partyaddress); +- pri_message(pri, " ton = %d, pres = %d, npi = %d\n", chargednr.ton, chargednr.pres, chargednr.npi); +- break; +- case ASN1_INTEGER: +- ASN1_GET_INTEGER(comp1, chargeIdentifier); +- break; +- default: +- pri_message(pri, "!! Invalid AOC-E chargingAssociation. Expected Object Identifier (0xA0) or Integer (0x02) but received 0x%02X\n", comp1->type); +- } +- NEXT_COMPONENT(comp1, pos1); +- } while (pos1 < len); ++ end = ++ enc_etsi_aoce_charging_unit(ctrl, buffer, buffer + sizeof(buffer), chargedunits); ++ if (!end) { ++ return -1; ++ } + +- if (pos1 < len) { +- pri_message(pri, "!! Only reached position %i in %i bytes long AOC-E structure:", pos1, len ); +- dump_apdu (pri, data, len); +- return -1; /* oops - aborted before */ ++ /* Remember that if we queue a facility IE for a facility message we ++ * have to explicitly send the facility message ourselves */ ++ if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL) ++ || q931_facility(call->pri, call)) { ++ pri_message(ctrl, "Could not schedule facility message for call %d\n", call->cr); ++ return -1; + } +- call->aoc_units = chargingunits; +- ++ + return 0; + } ++/* End AOC */ + +-static int aoc_aoce_charging_unit_encode(struct pri *pri, q931_call *c, long chargedunits) ++/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */ ++ ++/*! ++ * \internal ++ * \brief Encode the Q.SIG CallTransferComplete invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode call transfer. ++ * \param call_status TRUE if call is alerting. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_call_transfer_complete(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, q931_call *call, int call_status) + { +- /* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */ +- int i = 0, res = 0, compsp = 0; +- unsigned char buffer[255] = ""; +- struct rose_component *comp = NULL, *compstk[10]; ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; + +- /* ROSE protocol (0x91)*/ +- buffer[i++] = (ASN1_CONTEXT_SPECIFIC | Q932_PROTOCOL_ROSE); ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } + +- /* ROSE Component (0xA1,len)*/ +- ASN1_ADD_SIMPLE(comp, COMP_TYPE_INVOKE, buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_CallTransferComplete; ++ msg.invoke_id = get_invokeid(ctrl); ++ msg.args.qsig.CallTransferComplete.end_designation = 0; /* primaryEnd */ + +- /* ROSE invokeId component (0x02,len,id)*/ +- ASN1_ADD_WORDCOMP(comp, INVOKE_IDENTIFIER, buffer, i, ++pri->last_invoke); ++ /* redirectionNumber is the local_id.number */ ++ q931_copy_presented_number_screened_to_rose(ctrl, ++ &msg.args.qsig.CallTransferComplete.redirection, &call->local_id.number); + +- /* ROSE operationId component (0x02,0x01,0x24)*/ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, ROSE_AOC_AOCE_CHARGING_UNIT); ++ /* redirectionName is the local_id.name */ ++ if (call->local_id.name.valid) { ++ msg.args.qsig.CallTransferComplete.redirection_name_present = 1; ++ q931_copy_name_to_rose(ctrl, ++ &msg.args.qsig.CallTransferComplete.redirection_name, ++ &call->local_id.name); ++ } + +- /* AOCEChargingUnitInfo (0x30,len) */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ if (call_status) { ++ msg.args.qsig.CallTransferComplete.call_status = 1; /* alerting */ ++ } ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- if (chargedunits > 0) { +- /* SpecificChargingUnits (0x30,len) */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); ++ return pos; ++} + +- /* RecordedUnitsList (0xA1,len) */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- +- /* RecordedUnits (0x30,len) */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONSTRUCTOR | ASN1_SEQUENCE), buffer, i); +- ASN1_PUSH(compstk, compsp, comp); +- +- /* NumberOfUnits (0x02,len,charge) */ +- ASN1_ADD_BYTECOMP(comp, ASN1_INTEGER, buffer, i, chargedunits); ++/*! ++ * \internal ++ * \brief Encode the ETSI EctInform invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode inform message. ++ * \param call_status TRUE if call is alerting. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_etsi_ect_inform(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, q931_call *call, int call_status) ++{ ++ struct rose_msg_invoke msg; + +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- } else { +- /* freeOfCharge (0x81,0) */ +- ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1), buffer, i); ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; + } +- ASN1_FIXUP(compstk, compsp, buffer, i); +- ASN1_FIXUP(compstk, compsp, buffer, i); +- +- if (pri->debug & PRI_DEBUG_AOC) +- dump_apdu (pri, buffer, i); +- +- /* code below is untested */ +- res = pri_call_apdu_queue(c, Q931_FACILITY, buffer, i, NULL, NULL); +- if (res) { +- pri_message(pri, "Could not queue APDU in facility message\n"); +- return -1; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_ETSI_EctInform; ++ msg.invoke_id = get_invokeid(ctrl); ++ ++ if (!call_status) { ++ msg.args.etsi.EctInform.status = 1;/* active */ ++ ++ /* ++ * EctInform(active) contains the redirectionNumber ++ * redirectionNumber is the local_id.number ++ */ ++ msg.args.etsi.EctInform.redirection_present = 1; ++ q931_copy_presented_number_unscreened_to_rose(ctrl, ++ &msg.args.etsi.EctInform.redirection, &call->local_id.number); + } + +- /* Remember that if we queue a facility IE for a facility message we +- * have to explicitly send the facility message ourselves */ +- res = q931_facility(c->pri, c); +- if (res) { +- pri_message(pri, "Could not schedule facility message for call %d\n", c->cr); ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode and queue the CallTransferComplete/EctInform invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode call transfer. ++ * \param call_status TRUE if call is alerting. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int rose_call_transfer_complete_encode(struct pri *ctrl, q931_call *call, ++ int call_status) ++{ ++ unsigned char buffer[256]; ++ unsigned char *end; ++ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ end = ++ enc_etsi_ect_inform(ctrl, buffer, buffer + sizeof(buffer), call, call_status); ++ break; ++ case PRI_SWITCH_QSIG: ++ end = ++ enc_qsig_call_transfer_complete(ctrl, buffer, buffer + sizeof(buffer), call, ++ call_status); ++ break; ++ default: + return -1; + } ++ if (!end) { ++ return -1; ++ } + +- return 0; ++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL); + } +-/* End AOC */ + +-static int rose_calling_name_decode(struct pri *pri, q931_call *call, struct rose_component *choice, int len) ++/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */ ++ ++/*! ++ * \internal ++ * \brief Encode the Q.SIG CalledName invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param name Name data which to encode name. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_called_name(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct q931_party_name *name) + { +- int i = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = choice->data; +- int characterSet = 1; +- switch (choice->type) { +- case ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE: +- memcpy(call->callername, choice->data, choice->len); +- call->callername[choice->len] = 0; +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received simple calling name '%s'\n", call->callername); +- return 0; ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; + +- case ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED: +- do { +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_OCTETSTRING, "Don't know what to do if nameData is of type 0x%x\n"); +- memcpy(call->callername, comp->data, comp->len); +- call->callername[comp->len] = 0; +- NEXT_COMPONENT(comp, i); ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } + +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if CharacterSet is of type 0x%x\n"); +- ASN1_GET_INTEGER(comp, characterSet); +- } +- while (0); ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_CalledName; ++ msg.invoke_id = get_invokeid(ctrl); + +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Received extended calling name '%s', characterset %d\n", call->callername, characterSet); +- return 0; +- case ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE: +- case ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED: +- case ROSE_NAME_PRESENTATION_RESTRICTED_NULL: +- case ROSE_NAME_NOT_AVAIL: +- default: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "Do not handle argument of type 0x%X\n", choice->type); +- return -1; +- } ++ /* CalledName */ ++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.CalledName.name, name); ++ ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); ++ ++ return pos; + } +-/* ===== Call Transfer Supplementary Service (ECMA-178) ===== */ + +-static int rose_party_number_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberunscreened *value) ++/*! ++ * \internal ++ * \brief Encode and queue the Q.SIG CalledName invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode name. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int rose_called_name_encode(struct pri *ctrl, q931_call *call, int messagetype) + { +- int i = 0; +- int size = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; ++ unsigned char buffer[256]; ++ unsigned char *end; + ++ /* CalledName is the local_id.name */ ++ end = enc_qsig_called_name(ctrl, buffer, buffer + sizeof(buffer), ++ &call->local_id.name); ++ if (!end) { ++ return -1; ++ } + +- do { +- GET_COMPONENT(comp, i, vdata, len); ++ return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL); ++} + +- switch(comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT NumberDigits -- default: unknownPartyNumber */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PartyNumber: UnknownPartyNumber len=%d\n", len); +- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_UNKNOWN; +- value->ton = PRI_TON_UNKNOWN; +- break; ++/*! ++ * \internal ++ * \brief Encode the Q.SIG ConnectedName invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param name Name data which to encode name. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_connected_name(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct q931_party_name *name) ++{ ++ struct fac_extension_header header; ++ struct rose_msg_invoke msg; + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1): /* [1] IMPLICIT PublicPartyNumber */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PartyNumber: PublicPartyNumber len=%d\n", len); +- size = rose_public_party_number_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_E163_E164; +- break; ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT NumberDigits -- not used: dataPartyNumber */ +- pri_message(pri, "!! PartyNumber: dataPartyNumber is reserved!\n"); +- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_X121 /* ??? */; +- value->ton = PRI_TON_UNKNOWN /* ??? */; +- break; ++ memset(&msg, 0, sizeof(msg)); ++ msg.operation = ROSE_QSIG_ConnectedName; ++ msg.invoke_id = get_invokeid(ctrl); + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_4): /* [4] IMPLICIT NumberDigits -- not used: telexPartyNumber */ +- pri_message(pri, "!! PartyNumber: telexPartyNumber is reserved!\n"); +- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_F69 /* ??? */; +- value->ton = PRI_TON_UNKNOWN /* ??? */; +- break; ++ /* ConnectedName */ ++ q931_copy_name_to_rose(ctrl, &msg.args.qsig.ConnectedName.name, name); + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_5): /* [5] IMPLICIT PrivatePartyNumber */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PartyNumber: PrivatePartyNumber len=%d\n", len); +- size = rose_private_party_number_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_PRIVATE; +- break; ++ pos = rose_encode_invoke(ctrl, pos, end, &msg); + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_8): /* [8] IMPLICIT NumberDigits -- not used: nationalStandatdPartyNumber */ +- pri_message(pri, "!! PartyNumber: nationalStandardPartyNumber is reserved!\n"); +- size = rose_number_digits_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- value->npi = PRI_NPI_NATIONAL; +- value->ton = PRI_TON_NATIONAL; +- break; ++ return pos; ++} + +- default: +- pri_message(pri, "Invalid PartyNumber component 0x%X\n", comp->type); +- return -1; +- } +- ASN1_FIXUP_LEN(comp, size); +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PartyNumber: '%s' size=%d len=%d\n", value->partyaddress, size, len); +- return size; ++/*! ++ * \internal ++ * \brief Encode and queue the Q.SIG ConnectedName invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode name. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int rose_connected_name_encode(struct pri *ctrl, q931_call *call, int messagetype) ++{ ++ unsigned char buffer[256]; ++ unsigned char *end; ++ ++ /* ConnectedName is the local_id.name */ ++ end = enc_qsig_connected_name(ctrl, buffer, buffer + sizeof(buffer), ++ &call->local_id.name); ++ if (!end) { ++ return -1; + } +- while (0); + +- return -1; ++ return pri_call_apdu_queue(call, messagetype, buffer, end - buffer, NULL); + } + +- +-static int rose_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value) ++/*! ++ * \brief Put the APDU on the call queue. ++ * ++ * \param call Call to enqueue message. ++ * \param messagetype Q.931 message type. ++ * \param apdu Facility ie contents buffer. ++ * \param apdu_len Length of the contents buffer. ++ * \param response Sender supplied information to handle APDU response messages. ++ * NULL if don't care about responses. ++ * ++ * \note ++ * Only APDU messages with an invoke component can supply a response pointer. ++ * If any other APDU messages supply a response pointer then aliasing of the ++ * invoke_id can occur. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response) + { +- int i = 0; +- int size = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; ++ struct apdu_event *cur = NULL; ++ struct apdu_event *new_event = NULL; + +- int scrind = -1; +- +- do { +- /* Party Number */ +- GET_COMPONENT(comp, i, vdata, len); +- size = rose_party_number_decode(pri, call, (u_int8_t *)comp, comp->len + 2, (struct addressingdataelements_presentednumberunscreened*) value); +- if (size < 0) ++ if (!call || !messagetype || !apdu ++ || apdu_len < 1 || sizeof(new_event->apdu) < apdu_len) { ++ return -1; ++ } ++ switch (messagetype) { ++ case Q931_FACILITY: ++ break; ++ default: ++ if (q931_is_dummy_call(call)) { ++ pri_error(call->pri, "!! Cannot send %s message on dummy call reference.\n", ++ msg2str(messagetype)); + return -1; +- comp->len = size; +- NEXT_COMPONENT(comp, i); ++ } ++ break; ++ } + +- /* Screening Indicator */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Don't know what to do with NumberScreened ROSE component type 0x%x\n"); +- ASN1_GET_INTEGER(comp, scrind); +- // Todo: scrind = screeningindicator_for_q931(pri, scrind); +- NEXT_COMPONENT(comp, i); ++ new_event = calloc(1, sizeof(*new_event)); ++ if (!new_event) { ++ pri_error(call->pri, "!! Malloc failed!\n"); ++ return -1; ++ } + +- value->scrind = scrind; ++ /* Fill in the APDU event */ ++ new_event->message = messagetype; ++ if (response) { ++ new_event->response = *response; ++ } ++ new_event->call = call; ++ new_event->apdu_len = apdu_len; ++ memcpy(new_event->apdu, apdu, apdu_len); + +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " NumberScreened: '%s' ScreeningIndicator=%d i=%d len=%d\n", value->partyaddress, scrind, i, len); +- +- return i-2; // We do not have a sequence header here. ++ /* Append APDU event to the end of the list. */ ++ if (call->apdus) { ++ for (cur = call->apdus; cur->next; cur = cur->next) { ++ } ++ cur->next = new_event; ++ } else { ++ call->apdus = new_event; + } +- while (0); + +- return -1; ++ return 0; + } + +- +-static int rose_presented_number_screened_decode(struct pri *pri, q931_call *call, unsigned char *data, int len, struct addressingdataelements_presentednumberscreened *value) ++/* Used by q931.c to cleanup the apdu queue upon destruction of a call */ ++void pri_call_apdu_queue_cleanup(q931_call *call) + { +- int i = 0; +- int size = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = data; ++ struct apdu_event *cur_event; ++ struct apdu_event *free_event; + +- /* Fill in default values */ +- value->ton = PRI_TON_UNKNOWN; +- value->npi = PRI_NPI_UNKNOWN; +- value->pres = -1; /* Data is not available */ ++ if (call) { ++ cur_event = call->apdus; ++ call->apdus = NULL; ++ while (cur_event) { ++ if (cur_event->response.callback) { ++ /* Indicate to callback that the APDU is being cleaned up. */ ++ cur_event->response.callback(APDU_CALLBACK_REASON_CLEANUP, call->pri, ++ call, cur_event, NULL); + +- do { +- GET_COMPONENT(comp, i, vdata, len); ++ /* Stop any response timeout. */ ++ pri_schedule_del(call->pri, cur_event->timer); ++ } ++ free_event = cur_event; ++ cur_event = cur_event->next; ++ free(free_event); ++ } ++ } ++} + +- switch(comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_0): /* [0] IMPLICIT presentationAllowedNumber */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: presentationAllowedNumber comp->len=%d\n", comp->len); +- value->pres = PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN; +- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, size); +- return size + 2; ++/*! ++ * \internal ++ * \brief Find an outstanding APDU with the given invoke id. ++ * ++ * \param call Call to find APDU. ++ * \param invoke_id Invoke id to match outstanding APDUs in queue. ++ * ++ * \retval apdu_event if found. ++ * \retval NULL if not found. ++ */ ++static struct apdu_event *pri_call_apdu_find(struct q931_call *call, int invoke_id) ++{ ++ struct apdu_event *apdu; + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_1): /* [1] IMPLICIT presentationRestricted */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: presentationRestricted comp->len=%d\n", comp->len); +- if (comp->len != 0) { /* must be NULL */ +- pri_error(pri, "!! Invalid PresentationRestricted component received (len != 0)\n"); +- return -1; +- } +- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; +- return 2; ++ for (apdu = call->apdus; apdu; apdu = apdu->next) { ++ /* ++ * Note: The APDU cannot be sent and still in the queue without a ++ * callback and timeout timer active. Therefore, an invoke_id of ++ * zero is valid and not just the result of a memset(). ++ */ ++ if (apdu->response.invoke_id == invoke_id && apdu->sent) { ++ break; ++ } ++ } ++ return apdu; ++} + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_2): /* [2] IMPLICIT numberNotAvailableDueToInterworking */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: NumberNotAvailableDueToInterworking comp->len=%d\n", comp->len); +- if (comp->len != 0) { /* must be NULL */ +- pri_error(pri, "!! Invalid NumberNotAvailableDueToInterworking component received (len != 0)\n"); +- return -1; +- } +- value->pres = PRES_NUMBER_NOT_AVAILABLE; +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: numberNotAvailableDueToInterworking Type=0x%X i=%d len=%d size=%d\n", comp->type, i, len); +- return 2; ++/*! ++ * \brief Delete the given APDU event from the given call. ++ * ++ * \param call Call to remove the APDU. ++ * \param doomed APDU event to delete. ++ * ++ * \return Nothing ++ */ ++void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed) ++{ ++ struct apdu_event **prev; ++ struct apdu_event *cur; + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_3): /* [3] IMPLICIT presentationRestrictedNumber */ +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " PresentedNumberScreened: presentationRestrictedNumber comp->len=%d\n", comp->len); +- value->pres = PRES_PROHIB_USER_NUMBER_PASSED_SCREEN; +- size = rose_number_screened_decode(pri, call, comp->data, comp->len, value); +- if (size < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, size); +- return size + 2; ++ /* Find APDU in list. */ ++ for (prev = &call->apdus, cur = call->apdus; ++ cur; ++ prev = &cur->next, cur = cur->next) { ++ if (cur == doomed) { ++ /* Stop any response timeout. */ ++ pri_schedule_del(call->pri, cur->timer); + +- default: +- pri_message(pri, "Invalid PresentedNumberScreened component 0x%X\n", comp->type); ++ /* Remove APDU from list. */ ++ *prev = cur->next; ++ free(cur); ++ break; + } +- return -1; + } +- while (0); +- +- return -1; + } + +- +-static int rose_call_transfer_complete_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++/*! \note Only called when sending the SETUP message. */ ++int pri_call_add_standard_apdus(struct pri *ctrl, q931_call *call) + { +- int i = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = sequence->data; +- int res = 0; ++ if (!ctrl->sendfacility) { ++ return 0; ++ } + +- int end_designation = 0; +- struct addressingdataelements_presentednumberscreened redirection_number; +- char redirection_name[50] = ""; +- int call_status = 0; +- redirection_number.partyaddress[0] = 0; +- redirection_number.partysubaddress[0] = 0; +- call->callername[0] = 0; +- call->callernum[0] = 0; ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ if (q931_is_ptmp(ctrl)) { ++ /* PTMP mode */ ++ break; ++ } ++ /* PTP mode */ ++ if (call->redirecting.count) { ++ rose_diverting_leg_information2_encode(ctrl, call); + ++ /* ++ * Expect a DivertingLegInformation3 to update the COLR of the ++ * redirecting-to party we are attempting to call now. ++ */ ++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3; ++ } ++ break; ++ case PRI_SWITCH_QSIG: ++ /* For Q.SIG it does network and cpe operations */ ++ if (call->redirecting.count) { ++ rose_diverting_leg_information2_encode(ctrl, call); + +- /* Data checks */ +- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ +- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n"); +- return -1; ++ /* ++ * Expect a DivertingLegInformation3 to update the COLR of the ++ * redirecting-to party we are attempting to call now. ++ */ ++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3; ++ } ++ add_callername_facility_ies(ctrl, call, 1); ++ break; ++ case PRI_SWITCH_NI2: ++ add_callername_facility_ies(ctrl, call, (ctrl->localtype == PRI_CPE)); ++ break; ++ case PRI_SWITCH_DMS100: ++ if (ctrl->localtype == PRI_CPE) { ++ add_dms100_transfer_ability_apdu(ctrl, call); ++ } ++ break; ++ default: ++ break; + } + +- if (sequence->len == ASN1_LEN_INDEF) { +- len -= 4; /* For the 2 extra characters at the end +- * and two characters of header */ +- } else +- len -= 2; ++ return 0; ++} + +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: len=%d\n", len); ++/*! ++ * \brief Send the CallTransferComplete/EctInform invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode call transfer. ++ * \param call_status TRUE if call is alerting. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int send_call_transfer_complete(struct pri *ctrl, q931_call *call, int call_status) ++{ ++ if (rose_call_transfer_complete_encode(ctrl, call, call_status) ++ || q931_facility(ctrl, call)) { ++ pri_message(ctrl, ++ "Could not schedule facility message for call transfer completed.\n"); ++ return -1; ++ } + +- do { +- /* End Designation */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid endDesignation type 0x%X of ROSE callTransferComplete component received\n"); +- ASN1_GET_INTEGER(comp, end_designation); +- NEXT_COMPONENT(comp, i); +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received endDesignation=%d\n", end_designation); ++ return 0; ++} + ++/*! ++ * \internal ++ * \brief Encode a plain facility ETSI error code. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode error message response. ++ * \param invoke_id Invoke id to put in error message response. ++ * \param code Error code to put in error message response. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_etsi_error(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, q931_call *call, int invoke_id, enum rose_error_code code) ++{ ++ struct rose_msg_error msg; + +- /* Redirection Number */ +- GET_COMPONENT(comp, i, vdata, len); +- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number); +- if (res < 0) +- return -1; +- comp->len = res; +- if (res > 2) { +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress); +- strncpy(call->callernum, redirection_number.partyaddress, 20); +- call->callernum[20] = 0; +- } +- NEXT_COMPONENT(comp, i); ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } + ++ memset(&msg, 0, sizeof(msg)); ++ msg.invoke_id = invoke_id; ++ msg.code = code; + +-#if 0 /* This one is optional. How do we check if it is there? */ +- /* Basic Call Info Elements */ +- GET_COMPONENT(comp, i, vdata, len); +- NEXT_COMPONENT(comp, i); +-#endif ++ pos = rose_encode_error(ctrl, pos, end, &msg); + ++ return pos; ++} + +- /* Redirection Name */ +- GET_COMPONENT(comp, i, vdata, len); +- res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name)); +- if (res < 0) +- return -1; +- memcpy(call->callername, comp->data, comp->len); +- call->callername[comp->len] = 0; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- NEXT_COMPONENT(comp, i); +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name); ++/*! ++ * \internal ++ * \brief Encode a plain facility Q.SIG error code. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode error message response. ++ * \param invoke_id Invoke id to put in error message response. ++ * \param code Error code to put in error message response. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_error(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, q931_call *call, int invoke_id, enum rose_error_code code) ++{ ++ struct fac_extension_header header; ++ struct rose_msg_error msg; + ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; ++ } + +- /* Call Status */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_ENUMERATED, "Invalid callStatus type 0x%X of ROSE callTransferComplete component received\n"); +- ASN1_GET_INTEGER(comp, call_status); +- NEXT_COMPONENT(comp, i); +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received callStatus=%d\n", call_status); ++ memset(&msg, 0, sizeof(msg)); ++ msg.invoke_id = invoke_id; ++ msg.code = code; + ++ pos = rose_encode_error(ctrl, pos, end, &msg); + +- /* Argument Extension */ +-#if 0 /* Not supported */ +- GET_COMPONENT(comp, i, vdata, len); +- switch (comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */ +- res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; ++ return pos; ++} + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */ +- res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; ++/*! ++ * \internal ++ * \brief Encode and queue a plain facility error code. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode error message response. ++ * \param invoke_id Invoke id to put in error message response. ++ * \param code Error code to put in error message response. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int rose_facility_error_encode(struct pri *ctrl, q931_call *call, int invoke_id, ++ enum rose_error_code code) ++{ ++ unsigned char buffer[256]; ++ unsigned char *end; + +- default: +- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type); +- return -1; +- } +-#else +- GET_COMPONENT(comp, i, vdata, len); +- ASN1_FIXUP_LEN(comp, res); +- NEXT_COMPONENT(comp, i); +-#endif ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ end = ++ enc_etsi_error(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id, code); ++ break; ++ case PRI_SWITCH_QSIG: ++ end = ++ enc_qsig_error(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id, code); ++ break; ++ default: ++ return -1; ++ } ++ if (!end) { ++ return -1; ++ } + +- if(i < len) +- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len); ++ return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer, NULL); ++} + +- return 0; ++/*! ++ * \brief Encode and send a plain facility error code. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode error message response. ++ * \param invoke_id Invoke id to put in error message response. ++ * \param code Error code to put in error message response. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int send_facility_error(struct pri *ctrl, q931_call *call, int invoke_id, ++ enum rose_error_code code) ++{ ++ if (rose_facility_error_encode(ctrl, call, invoke_id, code) ++ || q931_facility(ctrl, call)) { ++ pri_message(ctrl, ++ "Could not schedule facility message for error message.\n"); ++ return -1; + } +- while (0); + +- return -1; ++ return 0; + } + +- +-static int rose_call_transfer_update_decode(struct pri *pri, q931_call *call, struct rose_component *sequence, int len) ++/*! ++ * \internal ++ * \brief Encode a plain facility ETSI result ok. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode result ok message response. ++ * \param invoke_id Invoke id to put in result ok message response. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_etsi_result_ok(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, q931_call *call, int invoke_id) + { +- int i = 0; +- struct rose_component *comp = NULL; +- unsigned char *vdata = sequence->data; +- int res = 0; ++ struct rose_msg_result msg; + +- struct addressingdataelements_presentednumberscreened redirection_number; +- redirection_number.partyaddress[0] = 0; +- redirection_number.partysubaddress[0] = 0; +- char redirection_name[50] = ""; +- call->callername[0] = 0; +- call->callernum[0] = 0; ++ pos = facility_encode_header(ctrl, pos, end, NULL); ++ if (!pos) { ++ return NULL; ++ } + ++ memset(&msg, 0, sizeof(msg)); ++ msg.invoke_id = invoke_id; ++ msg.operation = ROSE_None; + +- /* Data checks */ +- if (sequence->type != (ASN1_CONSTRUCTOR | ASN1_SEQUENCE)) { /* Constructed Sequence */ +- pri_message(pri, "Invalid callTransferComplete argument. (Not a sequence)\n"); +- return -1; ++ pos = rose_encode_result(ctrl, pos, end, &msg); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode a plain facility Q.SIG result ok. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param call Call leg from which to encode result ok message response. ++ * \param invoke_id Invoke id to put in result ok message response. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *enc_qsig_result_ok(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, q931_call *call, int invoke_id) ++{ ++ struct fac_extension_header header; ++ struct rose_msg_result msg; ++ ++ memset(&header, 0, sizeof(header)); ++ header.nfe_present = 1; ++ header.nfe.source_entity = 0; /* endPINX */ ++ header.nfe.destination_entity = 0; /* endPINX */ ++ header.interpretation_present = 1; ++ header.interpretation = 0; /* discardAnyUnrecognisedInvokePdu */ ++ pos = facility_encode_header(ctrl, pos, end, &header); ++ if (!pos) { ++ return NULL; + } + +- if (sequence->len == ASN1_LEN_INDEF) { +- len -= 4; /* For the 2 extra characters at the end +- * and two characters of header */ +- } else +- len -= 2; ++ memset(&msg, 0, sizeof(msg)); ++ msg.invoke_id = invoke_id; ++ msg.operation = ROSE_None; + +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: len=%d\n", len); ++ pos = rose_encode_result(ctrl, pos, end, &msg); + +- do { +- /* Redirection Number */ +- GET_COMPONENT(comp, i, vdata, len); +- res = rose_presented_number_screened_decode(pri, call, (u_int8_t *)comp, comp->len + 2, &redirection_number); +- if (res < 0) +- return -1; +- comp->len = res; +- if (res > 2) { +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received redirectionNumber=%s\n", redirection_number.partyaddress); +- strncpy(call->callernum, redirection_number.partyaddress, 20); +- call->callernum[20] = 0; +- } +- NEXT_COMPONENT(comp, i); ++ return pos; ++} + +- /* Redirection Name */ +- GET_COMPONENT(comp, i, vdata, len); +- res = asn1_name_decode((u_int8_t *)comp, comp->len + 2, redirection_name, sizeof(redirection_name)); +- if (res < 0) +- return -1; +- memcpy(call->callername, comp->data, comp->len); +- call->callername[comp->len] = 0; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; +- NEXT_COMPONENT(comp, i); +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " CT-Complete: Received redirectionName '%s'\n", redirection_name); ++/*! ++ * \internal ++ * \brief Encode and queue a plain ROSE result ok. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode result ok message response. ++ * \param msgtype Q.931 message type to put facility ie in. ++ * \param invoke_id Invoke id to put in result ok message response. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int rose_result_ok_encode(struct pri *ctrl, q931_call *call, int msgtype, int invoke_id) ++{ ++ unsigned char buffer[256]; ++ unsigned char *end; + ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ end = ++ enc_etsi_result_ok(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id); ++ break; ++ case PRI_SWITCH_QSIG: ++ end = ++ enc_qsig_result_ok(ctrl, buffer, buffer + sizeof(buffer), call, invoke_id); ++ break; ++ default: ++ return -1; ++ } ++ if (!end) { ++ return -1; ++ } + +-#if 0 /* This one is optional. How do we check if it is there? */ +- /* Basic Call Info Elements */ +- GET_COMPONENT(comp, i, vdata, len); +- NEXT_COMPONENT(comp, i); +-#endif ++ return pri_call_apdu_queue(call, msgtype, buffer, end - buffer, NULL); ++} + ++/*! ++ * \brief Encode and send a FACILITY message with a plain ROSE result ok. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which to encode result ok message response. ++ * \param invoke_id Invoke id to put in result ok message response. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int send_facility_result_ok(struct pri *ctrl, q931_call *call, int invoke_id) ++{ ++ if (rose_result_ok_encode(ctrl, call, Q931_FACILITY, invoke_id) ++ || q931_facility(ctrl, call)) { ++ pri_message(ctrl, ++ "Could not schedule facility message for result OK message.\n"); ++ return -1; ++ } + +- /* Argument Extension */ +-#if 0 /* Not supported */ +- GET_COMPONENT(comp, i, vdata, len); +- switch (comp->type) { +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_9): /* [9] IMPLICIT Extension */ +- res = rose_extension_decode(pri, call, comp->data, comp->len, &redirection_number); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; ++ return 0; ++} + +- case (ASN1_CONTEXT_SPECIFIC | ASN1_TAG_10): /* [10] IMPLICIT SEQUENCE OF Extension */ +- res = rose_sequence_of_extension_decode(pri, call, comp->data, comp->len, &redirection_number); +- if (res < 0) +- return -1; +- ASN1_FIXUP_LEN(comp, res); +- comp->len = res; ++int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI_REROUTING_RSP_CODE code) ++{ ++ enum rose_error_code rose_err; + +- default: +- pri_message(pri, " CT-Complete: !! Unknown argumentExtension received 0x%X\n", comp->type); +- return -1; +- } +-#else +- GET_COMPONENT(comp, i, vdata, len); +- ASN1_FIXUP_LEN(comp, res); +- NEXT_COMPONENT(comp, i); +-#endif ++ if (!ctrl || !call) { ++ return -1; ++ } + +- if(i < len) +- pri_message(pri, " CT-Complete: !! not all information is handled !! i=%d / len=%d\n", i, len); ++ /* Convert the public rerouting response code to an error code or result ok. */ ++ rose_err = ROSE_ERROR_Gen_ResourceUnavailable; ++ switch (code) { ++ case PRI_REROUTING_RSP_OK_CLEAR: ++ return rose_result_ok_encode(ctrl, call, Q931_DISCONNECT, invoke_id); ++ case PRI_REROUTING_RSP_OK_RETAIN: ++ return send_facility_result_ok(ctrl, call, invoke_id); ++ case PRI_REROUTING_RSP_NOT_SUBSCRIBED: ++ rose_err = ROSE_ERROR_Gen_NotSubscribed; ++ break; ++ case PRI_REROUTING_RSP_NOT_AVAILABLE: ++ rose_err = ROSE_ERROR_Gen_NotAvailable; ++ break; ++ case PRI_REROUTING_RSP_NOT_ALLOWED: ++ rose_err = ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed; ++ break; ++ case PRI_REROUTING_RSP_INVALID_NUMBER: ++ rose_err = ROSE_ERROR_Div_InvalidDivertedToNr; ++ break; ++ case PRI_REROUTING_RSP_SPECIAL_SERVICE_NUMBER: ++ rose_err = ROSE_ERROR_Div_SpecialServiceNr; ++ break; ++ case PRI_REROUTING_RSP_DIVERSION_TO_SELF: ++ rose_err = ROSE_ERROR_Div_DiversionToServedUserNr; ++ break; ++ case PRI_REROUTING_RSP_MAX_DIVERSIONS_EXCEEDED: ++ rose_err = ROSE_ERROR_Div_NumberOfDiversionsExceeded; ++ break; ++ case PRI_REROUTING_RSP_RESOURCE_UNAVAILABLE: ++ rose_err = ROSE_ERROR_Gen_ResourceUnavailable; ++ break; ++ } ++ return send_facility_error(ctrl, call, invoke_id, rose_err); ++} + +- return 0; ++/*! ++ * \brief Handle the ROSE reject message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which the message came. ++ * \param msgtype Q.931 message type ie is in. ++ * \param ie Raw ie contents. ++ * \param header Decoded facility header before ROSE. ++ * \param reject Decoded ROSE reject message contents. ++ * ++ * \return Nothing ++ */ ++void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, ++ const struct fac_extension_header *header, const struct rose_msg_reject *reject) ++{ ++ struct apdu_event *apdu; ++ union apdu_msg_data msg; ++ ++ /* Gripe to the user about getting rejected. */ ++ pri_error(ctrl, "ROSE REJECT:\n"); ++ if (reject->invoke_id_present) { ++ pri_error(ctrl, "\tINVOKE ID: %d\n", reject->invoke_id); + } +- while (0); ++ pri_error(ctrl, "\tPROBLEM: %s\n", rose_reject2str(reject->code)); + +- return -1; ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_DMS100: ++ /* The DMS-100 switch apparently handles invoke_id as an invoke operation. */ ++ return; ++ default: ++ break; ++ } ++ ++ if (!reject->invoke_id_present) { ++ /* ++ * No invoke id to look up so we cannot match it to any outstanding APDUs. ++ * This REJECT is apparently meant for someone monitoring the link. ++ */ ++ return; ++ } ++ apdu = pri_call_apdu_find(call, reject->invoke_id); ++ if (!apdu) { ++ return; ++ } ++ msg.reject = reject; ++ if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_REJECT, ctrl, call, apdu, &msg)) { ++ pri_call_apdu_delete(call, apdu); ++ } + } + ++/*! ++ * \brief Handle the ROSE error message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which the message came. ++ * \param msgtype Q.931 message type ie is in. ++ * \param ie Raw ie contents. ++ * \param header Decoded facility header before ROSE. ++ * \param error Decoded ROSE error message contents. ++ * ++ * \return Nothing ++ */ ++void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, ++ const struct fac_extension_header *header, const struct rose_msg_error *error) ++{ ++ const char *dms100_operation; ++ struct apdu_event *apdu; ++ union apdu_msg_data msg; + +-/* ===== End Call Transfer Supplementary Service (ECMA-178) ===== */ ++ /* Gripe to the user about getting an error. */ ++ pri_error(ctrl, "ROSE RETURN ERROR:\n"); ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_DMS100: ++ switch (error->invoke_id) { ++ case ROSE_DMS100_RLT_OPERATION_IND: ++ dms100_operation = "RLT_OPERATION_IND"; ++ break; ++ case ROSE_DMS100_RLT_THIRD_PARTY: ++ dms100_operation = "RLT_THIRD_PARTY"; ++ break; ++ default: ++ dms100_operation = NULL; ++ break; ++ } ++ if (dms100_operation) { ++ pri_error(ctrl, "\tOPERATION: %s\n", dms100_operation); ++ break; ++ } ++ /* fall through */ ++ default: ++ pri_error(ctrl, "\tINVOKE ID: %d\n", error->invoke_id); ++ break; ++ } ++ pri_error(ctrl, "\tERROR: %s\n", rose_error2str(error->code)); + ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_DMS100: ++ /* The DMS-100 switch apparently handles invoke_id as an invoke operation. */ ++ return; ++ default: ++ break; ++ } + ++ apdu = pri_call_apdu_find(call, error->invoke_id); ++ if (!apdu) { ++ return; ++ } ++ msg.error = error; ++ if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_ERROR, ctrl, call, apdu, &msg)) { ++ pri_call_apdu_delete(call, apdu); ++ } ++} + +-int rose_reject_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len) ++/*! ++ * \brief Handle the ROSE result message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which the message came. ++ * \param msgtype Q.931 message type ie is in. ++ * \param ie Raw ie contents. ++ * \param header Decoded facility header before ROSE. ++ * \param result Decoded ROSE result message contents. ++ * ++ * \return Nothing ++ */ ++void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, ++ const struct fac_extension_header *header, const struct rose_msg_result *result) + { +- int i = 0; +- int problemtag = -1; +- int problem = -1; +- int invokeidvalue = -1; +- unsigned char *vdata = data; +- struct rose_component *comp = NULL; +- char *problemtagstr, *problemstr; +- +- do { +- /* Invoke ID stuff */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n"); +- ASN1_GET_INTEGER(comp, invokeidvalue); +- NEXT_COMPONENT(comp, i); ++ struct apdu_event *apdu; ++ union apdu_msg_data msg; + +- GET_COMPONENT(comp, i, vdata, len); +- problemtag = comp->type; +- problem = comp->data[0]; +- +- if (pri->switchtype == PRI_SWITCH_DMS100) { +- switch (problemtag) { +- case 0x80: +- problemtagstr = "General problem"; ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_DMS100: ++ /* The DMS-100 switch apparently handles invoke_id as an invoke operation. */ ++ switch (result->invoke_id) { ++ case ROSE_DMS100_RLT_OPERATION_IND: ++ if (result->operation != ROSE_DMS100_RLT_OperationInd) { ++ pri_message(ctrl, "Invalid Operation value in return result! %s\n", ++ rose_operation2str(result->operation)); + break; +- case 0x81: +- problemtagstr = "Invoke problem"; +- break; +- case 0x82: +- problemtagstr = "Return result problem"; +- break; +- case 0x83: +- problemtagstr = "Return error problem"; +- break; +- default: +- problemtagstr = "Unknown"; + } + +- switch (problem) { +- case 0x00: +- problemstr = "Unrecognized component"; +- break; +- case 0x01: +- problemstr = "Mistyped component"; +- break; +- case 0x02: +- problemstr = "Badly structured component"; +- break; +- default: +- problemstr = "Unknown"; ++ /* We have enough data to transfer the call */ ++ call->rlt_call_id = result->args.dms100.RLT_OperationInd.call_id; ++ call->transferable = 1; ++ break; ++ case ROSE_DMS100_RLT_THIRD_PARTY: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "Successfully completed RLT transfer!\n"); + } +- +- pri_error(pri, "ROSE REJECT:\n"); +- pri_error(pri, "\tINVOKE ID: 0x%X\n", invokeidvalue); +- pri_error(pri, "\tPROBLEM TYPE: %s (0x%x)\n", problemtagstr, problemtag); +- pri_error(pri, "\tPROBLEM: %s (0x%x)\n", problemstr, problem); +- +- return 0; +- } else { +- pri_message(pri, "Unable to handle reject on switchtype %d!\n", pri->switchtype); +- return -1; ++ break; ++ default: ++ pri_message(ctrl, "Could not parse invoke of type %d!\n", result->invoke_id); ++ break; + } ++ return; ++ default: ++ break; ++ } + +- } while(0); +- +- return -1; ++ apdu = pri_call_apdu_find(call, result->invoke_id); ++ if (!apdu) { ++ return; ++ } ++ msg.result = result; ++ if (apdu->response.callback(APDU_CALLBACK_REASON_MSG_RESULT, ctrl, call, apdu, &msg)) { ++ pri_call_apdu_delete(call, apdu); ++ } + } +-int rose_return_error_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len) ++ ++/*! ++ * \brief Handle the ROSE invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param call Call leg from which the message came. ++ * \param msgtype Q.931 message type ie is in. ++ * \param ie Raw ie contents. ++ * \param header Decoded facility header before ROSE. ++ * \param invoke Decoded ROSE invoke message contents. ++ * ++ * \return Nothing ++ */ ++void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, ++ const struct fac_extension_header *header, const struct rose_msg_invoke *invoke) + { +- int i = 0; +- int errorvalue = -1; +- int invokeidvalue = -1; +- unsigned char *vdata = data; +- struct rose_component *comp = NULL; +- char *invokeidstr, *errorstr; +- +- do { +- /* Invoke ID stuff */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n"); +- ASN1_GET_INTEGER(comp, invokeidvalue); +- NEXT_COMPONENT(comp, i); ++ struct pri_subcommand *subcmd; ++ struct q931_party_id party_id; ++ struct q931_party_redirecting deflection; + +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if second component in return error is 0x%x\n"); +- ASN1_GET_INTEGER(comp, errorvalue); ++ switch (invoke->operation) { ++#if 0 /* Not handled yet */ ++ case ROSE_ETSI_ActivationDiversion: ++ break; ++ case ROSE_ETSI_DeactivationDiversion: ++ break; ++ case ROSE_ETSI_ActivationStatusNotificationDiv: ++ break; ++ case ROSE_ETSI_DeactivationStatusNotificationDiv: ++ break; ++ case ROSE_ETSI_InterrogationDiversion: ++ break; ++ case ROSE_ETSI_DiversionInformation: ++ break; ++#endif /* Not handled yet */ ++ case ROSE_ETSI_CallDeflection: ++ if (!PRI_MASTER(ctrl)->deflection_support) { ++ send_facility_error(ctrl, call, invoke->invoke_id, ++ ROSE_ERROR_Gen_NotSubscribed); ++ break; ++ } ++ if (!q931_master_pass_event(ctrl, call, msgtype)) { ++ /* Some other user is further along to connecting than this call. */ ++ send_facility_error(ctrl, call, invoke->invoke_id, ++ ROSE_ERROR_Div_IncomingCallAccepted); ++ break; ++ } ++ if (call->master_call->deflection_in_progress) { ++ /* Someone else is already doing a call deflection. */ ++ send_facility_error(ctrl, call, invoke->invoke_id, ++ ROSE_ERROR_Div_RequestAlreadyAccepted); ++ break; ++ } ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (!subcmd) { ++ /* ++ * ROSE_ERROR_Gen_ResourceUnavailable was not in the list of allowed codes, ++ * but we will send it anyway. ++ */ ++ send_facility_error(ctrl, call, invoke->invoke_id, ++ ROSE_ERROR_Gen_ResourceUnavailable); ++ pri_error(ctrl, "ERROR: Too many facility subcommands\n"); ++ break; ++ } + +- if (pri->switchtype == PRI_SWITCH_DMS100) { +- switch (invokeidvalue) { +- case RLT_OPERATION_IND: +- invokeidstr = "RLT_OPERATION_IND"; +- break; +- case RLT_THIRD_PARTY: +- invokeidstr = "RLT_THIRD_PARTY"; +- break; +- default: +- invokeidstr = "Unknown"; +- } ++ call->master_call->deflection_in_progress = 1; + +- switch (errorvalue) { +- case 0x10: +- errorstr = "RLT Bridge Fail"; +- break; +- case 0x11: +- errorstr = "RLT Call ID Not Found"; +- break; +- case 0x12: +- errorstr = "RLT Not Allowed"; +- break; +- case 0x13: +- errorstr = "RLT Switch Equip Congs"; +- break; +- default: +- errorstr = "Unknown"; +- } ++ q931_party_redirecting_init(&deflection); + +- pri_error(pri, "ROSE RETURN ERROR:\n"); +- pri_error(pri, "\tOPERATION: %s\n", invokeidstr); +- pri_error(pri, "\tERROR: %s\n", errorstr); ++ /* Deflecting from the called address. */ ++ q931_party_address_to_id(&deflection.from, &call->called); ++ if (invoke->args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user_present) { ++ deflection.from.number.presentation = ++ invoke->args.etsi.CallDeflection.presentation_allowed_to_diverted_to_user ++ ? PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED ++ : PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ } else { ++ deflection.from.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ } + +- return 0; ++ /* Deflecting to the new address. */ ++ rose_copy_address_to_q931(ctrl, &deflection.to, ++ &invoke->args.etsi.CallDeflection.deflection); ++ deflection.to.number.presentation = deflection.from.number.presentation; ++ ++ deflection.count = (call->redirecting.count < PRI_MAX_REDIRECTS) ++ ? call->redirecting.count + 1 : PRI_MAX_REDIRECTS; ++ deflection.reason = PRI_REDIR_DEFLECTION; ++ if (deflection.count == 1) { ++ deflection.orig_called = deflection.from; ++ deflection.orig_reason = deflection.reason; + } else { +- pri_message(pri, "Unable to handle return error on switchtype %d!\n", pri->switchtype); ++ deflection.orig_called = call->redirecting.orig_called; ++ deflection.orig_reason = call->redirecting.orig_reason; + } + +- } while(0); +- +- return -1; +-} ++ subcmd->cmd = PRI_SUBCMD_REROUTING; ++ subcmd->u.rerouting.invoke_id = invoke->invoke_id; ++ subcmd->u.rerouting.subscription_option = 3;/* notApplicable */ ++ q931_party_id_copy_to_pri(&subcmd->u.rerouting.caller, &call->local_id); ++ q931_party_redirecting_copy_to_pri(&subcmd->u.rerouting.deflection, ++ &deflection); ++ break; ++ case ROSE_ETSI_CallRerouting: ++ if (!PRI_MASTER(ctrl)->deflection_support) { ++ send_facility_error(ctrl, call, invoke->invoke_id, ++ ROSE_ERROR_Gen_NotSubscribed); ++ break; ++ } ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (!subcmd) { ++ send_facility_error(ctrl, call, invoke->invoke_id, ++ ROSE_ERROR_Gen_ResourceUnavailable); ++ pri_error(ctrl, "ERROR: Too many facility subcommands\n"); ++ break; ++ } + +-int rose_return_result_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len) +-{ +- int i = 0; +- int operationidvalue = -1; +- int invokeidvalue = -1; +- unsigned char *vdata = data; +- struct rose_component *comp = NULL; +- +- do { +- /* Invoke ID stuff */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n"); +- ASN1_GET_INTEGER(comp, invokeidvalue); +- NEXT_COMPONENT(comp, i); ++ q931_party_redirecting_init(&deflection); + +- if (pri->switchtype == PRI_SWITCH_DMS100) { +- switch (invokeidvalue) { +- case RLT_THIRD_PARTY: +- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed RLT transfer!\n"); +- return 0; +- case RLT_OPERATION_IND: +- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Received RLT_OPERATION_IND\n"); +- /* Have to take out the rlt_call_id */ +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_SEQUENCE, "Protocol error detected in parsing RLT_OPERATION_IND return result!\n"); ++ /* Rerouting from the last address. */ ++ rose_copy_presented_number_unscreened_to_q931(ctrl, &deflection.from.number, ++ &invoke->args.etsi.CallRerouting.last_rerouting); + +- /* Traverse the contents of this sequence */ +- /* First is the Operation Value */ +- SUB_COMPONENT(comp, i); +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_INTEGER, "RLT_OPERATION_IND should be of type ASN1_INTEGER!\n"); +- ASN1_GET_INTEGER(comp, operationidvalue); ++ /* Rerouting to the new address. */ ++ rose_copy_address_to_q931(ctrl, &deflection.to, ++ &invoke->args.etsi.CallRerouting.called_address); ++ switch (invoke->args.etsi.CallRerouting.subscription_option) { ++ default: ++ case 0: /* noNotification */ ++ case 1: /* notificationWithoutDivertedToNr */ ++ deflection.to.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ break; ++ case 2: /* notificationWithDivertedToNr */ ++ deflection.to.number.presentation = ++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ break; ++ } + +- if (operationidvalue != RLT_OPERATION_IND) { +- pri_message(pri, "Invalid Operation ID value (0x%x) in return result!\n", operationidvalue); +- return -1; +- } ++ /* Calling party subaddress update. */ ++ party_id = call->local_id; + +- /* Next is the Call ID */ +- NEXT_COMPONENT(comp, i); +- GET_COMPONENT(comp, i, vdata, len); +- CHECK_COMPONENT(comp, ASN1_TAG_0, "Error check failed on Call ID!\n"); +- ASN1_GET_INTEGER(comp, call->rlt_call_id); +- /* We have enough data to transfer the call */ +- call->transferable = 1; ++ deflection.count = invoke->args.etsi.CallRerouting.rerouting_counter; ++ deflection.reason = redirectingreason_for_q931(ctrl, ++ invoke->args.etsi.CallRerouting.rerouting_reason); ++ if (deflection.count == 1) { ++ deflection.orig_called = deflection.from; ++ deflection.orig_reason = deflection.reason; ++ } else { ++ deflection.orig_called = call->redirecting.orig_called; ++ deflection.orig_reason = call->redirecting.orig_reason; ++ } + +- return 0; +- +- default: +- pri_message(pri, "Could not parse invoke of type 0x%x!\n", invokeidvalue); +- return -1; ++ subcmd->cmd = PRI_SUBCMD_REROUTING; ++ subcmd->u.rerouting.invoke_id = invoke->invoke_id; ++ subcmd->u.rerouting.subscription_option = ++ invoke->args.etsi.CallRerouting.subscription_option; ++ q931_party_id_copy_to_pri(&subcmd->u.rerouting.caller, &party_id); ++ q931_party_redirecting_copy_to_pri(&subcmd->u.rerouting.deflection, ++ &deflection); ++ break; ++#if 0 /* Not handled yet */ ++ case ROSE_ETSI_InterrogateServedUserNumbers: ++ break; ++#endif /* Not handled yet */ ++ case ROSE_ETSI_DivertingLegInformation1: ++ if (invoke->args.etsi.DivertingLegInformation1.diverted_to_present) { ++ rose_copy_presented_number_unscreened_to_q931(ctrl, &party_id.number, ++ &invoke->args.etsi.DivertingLegInformation1.diverted_to); ++ /* ++ * We set the presentation value since the sender cannot know the ++ * presentation value preference of the destination party. ++ */ ++ if (party_id.number.str[0]) { ++ party_id.number.presentation = ++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ } else { ++ party_id.number.presentation = ++ PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED; + } +- } else if (pri->switchtype == PRI_SWITCH_QSIG) { +- switch (invokeidvalue) { +- case 0x13: +- if (pri->debug & PRI_DEBUG_APDU) pri_message(pri, "Successfully completed QSIG CF callRerouting!\n"); +- return 0; +- } + } else { +- pri_message(pri, "Unable to handle return result on switchtype %d!\n", pri->switchtype); +- return -1; ++ q931_party_number_init(&party_id.number); ++ party_id.number.valid = 1; + } + +- } while(0); +- +- return -1; +-} ++ /* ++ * Unless otherwise indicated by CONNECT, the divertedToNumber will be ++ * the remote_id.number. ++ */ ++ if (!call->connected_number_in_message) { ++ call->remote_id.number = party_id.number; ++ } + +-int rose_invoke_decode(struct pri *pri, q931_call *call, q931_ie *ie, unsigned char *data, int len) +-{ +- int i = 0; +- int res = 0; +- int operation_tag; +- unsigned char *vdata = data; +- struct rose_component *comp = NULL, *invokeid = NULL, *operationid = NULL; +- +- do { +- /* Invoke ID stuff */ +- GET_COMPONENT(comp, i, vdata, len); +-#if 0 +- CHECK_COMPONENT(comp, INVOKE_IDENTIFIER, "Don't know what to do if first ROSE component is of type 0x%x\n"); +-#endif +- invokeid = comp; +- NEXT_COMPONENT(comp, i); ++ /* divertedToNumber is put in redirecting.to.number */ ++ switch (invoke->args.etsi.DivertingLegInformation1.subscription_option) { ++ default: ++ case 0: /* noNotification */ ++ case 1: /* notificationWithoutDivertedToNr */ ++ q931_party_number_init(&call->redirecting.to.number); ++ call->redirecting.to.number.valid = 1; ++ call->redirecting.to.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ break; ++ case 2: /* notificationWithDivertedToNr */ ++ call->redirecting.to.number = party_id.number; ++ break; ++ } + +- /* Operation Tag */ +- GET_COMPONENT(comp, i, vdata, len); +-#if 0 +- CHECK_COMPONENT(comp, ASN1_INTEGER, "Don't know what to do if second ROSE component is of type 0x%x\n"); +-#endif +- operationid = comp; +- ASN1_GET_INTEGER(comp, operation_tag); +- NEXT_COMPONENT(comp, i); ++ call->redirecting.reason = redirectingreason_for_q931(ctrl, ++ invoke->args.etsi.DivertingLegInformation1.diversion_reason); ++ if (call->redirecting.count < PRI_MAX_REDIRECTS) { ++ ++call->redirecting.count; ++ } ++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3; ++ break; ++ case ROSE_ETSI_DivertingLegInformation2: ++ call->redirecting.state = Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3; ++ call->redirecting.count = ++ invoke->args.etsi.DivertingLegInformation2.diversion_counter; ++ if (!call->redirecting.count) { ++ /* To be safe, make sure that the count is non-zero. */ ++ call->redirecting.count = 1; ++ } ++ call->redirecting.reason = redirectingreason_for_q931(ctrl, ++ invoke->args.etsi.DivertingLegInformation2.diversion_reason); + +- /* No argument - return with error */ +- if (i >= len) +- return -1; ++ /* divertingNr is put in redirecting.from.number */ ++ if (invoke->args.etsi.DivertingLegInformation2.diverting_present) { ++ rose_copy_presented_number_unscreened_to_q931(ctrl, ++ &call->redirecting.from.number, ++ &invoke->args.etsi.DivertingLegInformation2.diverting); ++ } else if (!call->redirecting_number_in_message) { ++ q931_party_number_init(&call->redirecting.from.number); ++ call->redirecting.from.number.valid = 1; ++ } + +- /* Arguement Tag */ +- GET_COMPONENT(comp, i, vdata, len); +- if (!comp->type) +- return -1; ++ call->redirecting.orig_reason = PRI_REDIR_UNKNOWN; + +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " [ Handling operation %d ]\n", operation_tag); +- switch (operation_tag) { +- case SS_CNID_CALLINGNAME: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, " Handle Name display operation\n"); +- return rose_calling_name_decode(pri, call, comp, len-i); +- case ROSE_CALL_TRANSFER_IDENTIFY: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferIdentify - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_ABANDON: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferAbandon - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_INITIATE: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferInitiate - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_SETUP: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferSetup - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_ACTIVE: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: CallTransferActive - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_CALL_TRANSFER_COMPLETE: +- if (pri->debug & PRI_DEBUG_APDU) +- { +- pri_message(pri, "ROSE %i: Handle CallTransferComplete\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ /* originalCalledNr is put in redirecting.orig_called.number */ ++ if (invoke->args.etsi.DivertingLegInformation2.original_called_present) { ++ rose_copy_presented_number_unscreened_to_q931(ctrl, ++ &call->redirecting.orig_called.number, ++ &invoke->args.etsi.DivertingLegInformation2.original_called); ++ } else { ++ q931_party_number_init(&call->redirecting.orig_called.number); ++ } ++ break; ++ case ROSE_ETSI_DivertingLegInformation3: ++ /* ++ * Unless otherwise indicated by CONNECT, this will be the ++ * remote_id.number.presentation. ++ */ ++ if (!invoke->args.etsi.DivertingLegInformation3.presentation_allowed_indicator) { ++ call->redirecting.to.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ if (!call->connected_number_in_message) { ++ call->remote_id.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; + } +- return rose_call_transfer_complete_decode(pri, call, comp, len-i); +- case ROSE_CALL_TRANSFER_UPDATE: +- if (pri->debug & PRI_DEBUG_APDU) +- { +- pri_message(pri, "ROSE %i: Handle CallTransferUpdate\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ } ++ ++ switch (call->redirecting.state) { ++ case Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3: ++ call->redirecting.state = Q931_REDIRECTING_STATE_IDLE; ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (!subcmd) { ++ pri_error(ctrl, "ERROR: Too many facility subcommands\n"); ++ break; + } +- return rose_call_transfer_update_decode(pri, call, comp, len-i); +- case ROSE_SUBADDRESS_TRANSFER: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "ROSE %i: SubaddressTransfer - not handled!\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- return -1; +- case ROSE_DIVERTING_LEG_INFORMATION2: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: Handle CallingName\n", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return rose_diverting_leg_information2_decode(pri, call, comp, len-i); +- case ROSE_AOC_NO_CHARGING_INFO_AVAILABLE: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC No Charging Info Available - not handled!", operation_tag); +- dump_apdu (pri, comp->data, comp->len); +- } +- return -1; +- case ROSE_AOC_CHARGING_REQUEST: +- return aoc_aoce_charging_request_decode(pri, call, (u_int8_t *)comp, comp->len + 2); +- case ROSE_AOC_AOCS_CURRENCY: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC-S Currency - not handled!", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case ROSE_AOC_AOCS_SPECIAL_ARR: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC-S Special Array - not handled!", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case ROSE_AOC_AOCD_CURRENCY: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC-D Currency - not handled!", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case ROSE_AOC_AOCD_CHARGING_UNIT: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC-D Charging Unit - not handled!", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case ROSE_AOC_AOCE_CURRENCY: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC-E Currency - not handled!", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case ROSE_AOC_AOCE_CHARGING_UNIT: +- return aoc_aoce_charging_unit_decode(pri, call, (u_int8_t *)comp, comp->len + 2); +- if (0) { /* the following function is currently not used - just to make the compiler happy */ +- aoc_aoce_charging_unit_encode(pri, call, call->aoc_units); /* use this function to forward the aoc-e on a bridged channel */ +- return 0; +- } +- case ROSE_AOC_IDENTIFICATION_OF_CHARGE: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "ROSE %i: AOC Identification Of Charge - not handled!", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); +- } +- return -1; +- case SS_ANFPR_PATHREPLACEMENT: +- /* Clear Queue */ +- res = pri_call_apdu_queue_cleanup(call->bridged_call); +- if (res) { +- pri_message(pri, "Could not Clear queue ADPU\n"); +- return -1; +- } +- anfpr_pathreplacement_respond(pri, call, ie); +- break; ++ /* Setup redirecting subcommand */ ++ subcmd->cmd = PRI_SUBCMD_REDIRECTING; ++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting, ++ &call->redirecting); ++ break; + default: +- if (pri->debug & PRI_DEBUG_APDU) { +- pri_message(pri, "!! Unable to handle ROSE operation %d", operation_tag); +- dump_apdu (pri, (u_int8_t *)comp, comp->len + 2); ++ break; ++ } ++ break; ++ case ROSE_ETSI_ChargingRequest: ++ /* Ignore messsage */ ++ break; ++#if 0 /* Not handled yet */ ++ case ROSE_ETSI_AOCSCurrency: ++ break; ++ case ROSE_ETSI_AOCSSpecialArr: ++ break; ++ case ROSE_ETSI_AOCDCurrency: ++ break; ++ case ROSE_ETSI_AOCDChargingUnit: ++ break; ++ case ROSE_ETSI_AOCECurrency: ++ break; ++#endif /* Not handled yet */ ++ case ROSE_ETSI_AOCEChargingUnit: ++ call->aoc_units = 0; ++ if (invoke->args.etsi.AOCEChargingUnit.type == 1 ++ && !invoke->args.etsi.AOCEChargingUnit.charging_unit.free_of_charge) { ++ unsigned index; ++ ++ for (index = ++ invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded. ++ num_records; index--;) { ++ if (!invoke->args.etsi.AOCEChargingUnit.charging_unit.specific.recorded. ++ list[index].not_available) { ++ call->aoc_units += ++ invoke->args.etsi.AOCEChargingUnit.charging_unit.specific. ++ recorded.list[index].number_of_units; ++ } + } +- return -1; + } +- } while(0); +- +- return -1; +-} ++ /* the following function is currently not used - just to make the compiler happy */ ++ if (0) { ++ /* use this function to forward the aoc-e on a bridged channel */ ++ aoc_aoce_charging_unit_encode(ctrl, call, call->aoc_units); ++ } ++ break; ++#if 0 /* Not handled yet */ ++ case ROSE_ITU_IdentificationOfCharge: ++ break; ++#endif /* Not handled yet */ ++#if 0 /* Not handled yet */ ++ case ROSE_ETSI_EctExecute: ++ break; ++ case ROSE_ETSI_ExplicitEctExecute: ++ break; ++#endif /* Not handled yet */ ++ case ROSE_ETSI_RequestSubaddress: ++ /* Ignore since we are not handling subaddresses yet. */ ++ break; ++#if 0 /* Not handled yet */ ++ case ROSE_ETSI_SubaddressTransfer: ++ break; ++ case ROSE_ETSI_EctLinkIdRequest: ++ break; ++#endif /* Not handled yet */ ++ case ROSE_ETSI_EctInform: ++ /* redirectionNumber is put in remote_id.number */ ++ if (invoke->args.etsi.EctInform.redirection_present) { ++ rose_copy_presented_number_unscreened_to_q931(ctrl, ++ &call->remote_id.number, &invoke->args.etsi.EctInform.redirection); ++ } ++ if (!invoke->args.etsi.EctInform.status) { ++ /* The remote party for the transfer has not answered yet. */ ++ call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE; ++ } else { ++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE; ++ } ++ break; ++#if 0 /* Not handled yet */ ++ case ROSE_ETSI_EctLoopTest: ++ break; ++#endif /* Not handled yet */ ++ case ROSE_QSIG_CallingName: ++ /* CallingName is put in remote_id.name */ ++ rose_copy_name_to_q931(ctrl, &call->remote_id.name, ++ &invoke->args.qsig.CallingName.name); ++ break; ++ case ROSE_QSIG_CalledName: ++ /* CalledName is put in remote_id.name */ ++ rose_copy_name_to_q931(ctrl, &call->remote_id.name, ++ &invoke->args.qsig.CalledName.name); + +-int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_len, void (*function)(void *data), void *data) +-{ +- struct apdu_event *cur = NULL; +- struct apdu_event *new_event = NULL; ++ /* Setup connected line subcommand */ ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (!subcmd) { ++ pri_error(ctrl, "ERROR: Too many facility subcommands\n"); ++ break; ++ } ++ subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE; ++ q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &call->remote_id); ++ break; ++ case ROSE_QSIG_ConnectedName: ++ /* ConnectedName is put in remote_id.name */ ++ rose_copy_name_to_q931(ctrl, &call->remote_id.name, ++ &invoke->args.qsig.ConnectedName.name); ++ break; ++#if 0 /* Not handled yet */ ++ case ROSE_QSIG_BusyName: ++ break; ++#endif /* Not handled yet */ ++#if 0 /* Not handled yet */ ++ case ROSE_QSIG_ChargeRequest: ++ break; ++ case ROSE_QSIG_GetFinalCharge: ++ break; ++ case ROSE_QSIG_AocFinal: ++ break; ++ case ROSE_QSIG_AocInterim: ++ break; ++ case ROSE_QSIG_AocRate: ++ break; ++ case ROSE_QSIG_AocComplete: ++ break; ++ case ROSE_QSIG_AocDivChargeReq: ++ break; ++#endif /* Not handled yet */ ++#if 0 /* Not handled yet */ ++ case ROSE_QSIG_CallTransferIdentify: ++ break; ++ case ROSE_QSIG_CallTransferAbandon: ++ break; ++ case ROSE_QSIG_CallTransferInitiate: ++ break; ++ case ROSE_QSIG_CallTransferSetup: ++ break; ++#endif /* Not handled yet */ ++ case ROSE_QSIG_CallTransferActive: ++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE; + +- if (!call || !messagetype || !apdu || (apdu_len < 1) || (apdu_len > 255)) +- return -1; ++ /* connectedAddress is put in remote_id */ ++ rose_copy_presented_address_screened_to_q931(ctrl, &call->remote_id, ++ &invoke->args.qsig.CallTransferActive.connected); + +- if (!(new_event = calloc(1, sizeof(*new_event)))) { +- pri_error(call->pri, "!! Malloc failed!\n"); +- return -1; +- } ++ /* connectedName is put in remote_id.name */ ++ if (invoke->args.qsig.CallTransferActive.connected_name_present) { ++ rose_copy_name_to_q931(ctrl, &call->remote_id.name, ++ &invoke->args.qsig.CallTransferActive.connected_name); ++ } ++ break; ++ case ROSE_QSIG_CallTransferComplete: ++ /* redirectionNumber is put in remote_id.number */ ++ rose_copy_presented_number_screened_to_q931(ctrl, &call->remote_id.number, ++ &invoke->args.qsig.CallTransferComplete.redirection); + +- new_event->message = messagetype; +- new_event->callback = function; +- new_event->data = data; +- memcpy(new_event->apdu, apdu, apdu_len); +- new_event->apdu_len = apdu_len; +- +- if (call->apdus) { +- cur = call->apdus; +- while (cur->next) { +- cur = cur->next; ++ /* redirectionName is put in remote_id.name */ ++ if (invoke->args.qsig.CallTransferComplete.redirection_name_present) { ++ rose_copy_name_to_q931(ctrl, &call->remote_id.name, ++ &invoke->args.qsig.CallTransferComplete.redirection_name); + } +- cur->next = new_event; +- } else +- call->apdus = new_event; + +- return 0; +-} ++ if (invoke->args.qsig.CallTransferComplete.call_status == 1) { ++ /* The remote party for the transfer has not answered yet. */ ++ call->incoming_ct_state = INCOMING_CT_STATE_EXPECT_CT_ACTIVE; ++ } else { ++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE; ++ } ++ break; ++ case ROSE_QSIG_CallTransferUpdate: ++ party_id = call->remote_id; + +-int pri_call_apdu_queue_cleanup(q931_call *call) +-{ +- struct apdu_event *cur_event = NULL, *free_event = NULL; ++ /* redirectionNumber is put in party_id.number */ ++ rose_copy_presented_number_screened_to_q931(ctrl, &party_id.number, ++ &invoke->args.qsig.CallTransferUpdate.redirection); + +- if (call && call->apdus) { +- cur_event = call->apdus; +- while (cur_event) { +- /* TODO: callbacks, some way of giving return res on status of apdu */ +- free_event = cur_event; +- cur_event = cur_event->next; +- free(free_event); ++ /* redirectionName is put in party_id.name */ ++ if (invoke->args.qsig.CallTransferUpdate.redirection_name_present) { ++ rose_copy_name_to_q931(ctrl, &party_id.name, ++ &invoke->args.qsig.CallTransferUpdate.redirection_name); + } +- call->apdus = NULL; +- } + +- return 0; +-} +- +-int pri_call_add_standard_apdus(struct pri *pri, q931_call *call) +-{ +- if (!pri->sendfacility) +- return 0; +- +- if (pri->switchtype == PRI_SWITCH_QSIG) { /* For Q.SIG it does network and cpe operations */ +- if (call->redirectingnum[0]) +- rose_diverting_leg_information2_encode(pri, call); +- add_callername_facility_ies(pri, call, 1); +- return 0; +- } +- +-#if 0 +- if (pri->localtype == PRI_NETWORK) { +- switch (pri->switchtype) { +- case PRI_SWITCH_NI2: +- add_callername_facility_ies(pri, call, 0); ++ if (q931_party_id_cmp(&party_id, &call->remote_id)) { ++ /* The remote_id data has changed. */ ++ call->remote_id = party_id; ++ switch (call->incoming_ct_state) { ++ case INCOMING_CT_STATE_IDLE: ++ call->incoming_ct_state = INCOMING_CT_STATE_POST_CONNECTED_LINE; + break; + default: + break; ++ } + } +- return 0; +- } else if (pri->localtype == PRI_CPE) { +- switch (pri->switchtype) { +- case PRI_SWITCH_NI2: +- add_callername_facility_ies(pri, call, 1); +- break; +- default: +- break; ++ break; ++#if 0 /* Not handled yet */ ++ case ROSE_QSIG_SubaddressTransfer: ++ break; ++#endif /* Not handled yet */ ++ case ROSE_QSIG_PathReplacement: ++ anfpr_pathreplacement_respond(ctrl, call, ie); ++ break; ++#if 0 /* Not handled yet */ ++ case ROSE_QSIG_ActivateDiversionQ: ++ break; ++ case ROSE_QSIG_DeactivateDiversionQ: ++ break; ++ case ROSE_QSIG_InterrogateDiversionQ: ++ break; ++ case ROSE_QSIG_CheckRestriction: ++ break; ++#endif /* Not handled yet */ ++ case ROSE_QSIG_CallRerouting: ++ if (!PRI_MASTER(ctrl)->deflection_support) { ++ send_facility_error(ctrl, call, invoke->invoke_id, ++ ROSE_ERROR_Gen_NotSubscribed); ++ break; + } +- return 0; +- } +-#else +- if (pri->switchtype == PRI_SWITCH_NI2) +- add_callername_facility_ies(pri, call, (pri->localtype == PRI_CPE)); +-#endif ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (!subcmd) { ++ send_facility_error(ctrl, call, invoke->invoke_id, ++ ROSE_ERROR_Gen_ResourceUnavailable); ++ pri_error(ctrl, "ERROR: Too many facility subcommands\n"); ++ break; ++ } + +- if ((pri->switchtype == PRI_SWITCH_DMS100) && (pri->localtype == PRI_CPE)) { +- add_dms100_transfer_ability_apdu(pri, call); +- } ++ q931_party_redirecting_init(&deflection); + ++ /* Rerouting from the last address. */ ++ rose_copy_presented_number_unscreened_to_q931(ctrl, &deflection.from.number, ++ &invoke->args.qsig.CallRerouting.last_rerouting); ++ if (invoke->args.qsig.CallRerouting.redirecting_name_present) { ++ rose_copy_name_to_q931(ctrl, &deflection.from.name, ++ &invoke->args.qsig.CallRerouting.redirecting_name); ++ } + ++ /* Rerouting to the new address. */ ++ rose_copy_address_to_q931(ctrl, &deflection.to, ++ &invoke->args.qsig.CallRerouting.called); ++ switch (invoke->args.qsig.CallRerouting.subscription_option) { ++ default: ++ case 0: /* noNotification */ ++ case 1: /* notificationWithoutDivertedToNr */ ++ deflection.to.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ break; ++ case 2: /* notificationWithDivertedToNr */ ++ deflection.to.number.presentation = ++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ break; ++ } + +- return 0; ++ /* Calling party update. */ ++ party_id = call->local_id; ++ rose_copy_presented_number_screened_to_q931(ctrl, &party_id.number, ++ &invoke->args.qsig.CallRerouting.calling); ++ if (invoke->args.qsig.CallRerouting.calling_name_present) { ++ rose_copy_name_to_q931(ctrl, &party_id.name, ++ &invoke->args.qsig.CallRerouting.calling_name); ++ } ++ ++ deflection.count = invoke->args.qsig.CallRerouting.diversion_counter; ++ deflection.reason = redirectingreason_for_q931(ctrl, ++ invoke->args.qsig.CallRerouting.rerouting_reason); ++ ++ /* Original called party update. */ ++ if (deflection.count == 1) { ++ deflection.orig_called = deflection.from; ++ deflection.orig_reason = deflection.reason; ++ } else { ++ deflection.orig_called = call->redirecting.orig_called; ++ deflection.orig_reason = call->redirecting.orig_reason; ++ } ++ if (invoke->args.qsig.CallRerouting.original_called_present) { ++ rose_copy_presented_number_unscreened_to_q931(ctrl, ++ &deflection.orig_called.number, ++ &invoke->args.qsig.CallRerouting.original_called); ++ } ++ if (invoke->args.qsig.CallRerouting.original_called_name_present) { ++ rose_copy_name_to_q931(ctrl, &deflection.orig_called.name, ++ &invoke->args.qsig.CallRerouting.original_called_name); ++ } ++ if (invoke->args.qsig.CallRerouting.original_rerouting_reason_present) { ++ deflection.orig_reason = redirectingreason_for_q931(ctrl, ++ invoke->args.qsig.CallRerouting.original_rerouting_reason); ++ } ++ ++ subcmd->cmd = PRI_SUBCMD_REROUTING; ++ subcmd->u.rerouting.invoke_id = invoke->invoke_id; ++ subcmd->u.rerouting.subscription_option = ++ invoke->args.qsig.CallRerouting.subscription_option; ++ q931_party_id_copy_to_pri(&subcmd->u.rerouting.caller, &party_id); ++ q931_party_redirecting_copy_to_pri(&subcmd->u.rerouting.deflection, ++ &deflection); ++ break; ++ case ROSE_QSIG_DivertingLegInformation1: ++ q931_party_number_init(&party_id.number); ++ rose_copy_number_to_q931(ctrl, &party_id.number, ++ &invoke->args.qsig.DivertingLegInformation1.nominated_number); ++ if (party_id.number.str[0]) { ++ party_id.number.presentation = ++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ } ++ ++ /* ++ * Unless otherwise indicated by CONNECT, the nominatedNr will be ++ * the remote_id.number. ++ */ ++ if (!call->connected_number_in_message) { ++ call->remote_id.number = party_id.number; ++ } ++ ++ /* nominatedNr is put in redirecting.to.number */ ++ switch (invoke->args.qsig.DivertingLegInformation1.subscription_option) { ++ default: ++ case QSIG_NO_NOTIFICATION: ++ case QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR: ++ q931_party_number_init(&call->redirecting.to.number); ++ call->redirecting.to.number.valid = 1; ++ call->redirecting.to.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ break; ++ case QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR: ++ call->redirecting.to.number = party_id.number; ++ break; ++ } ++ ++ call->redirecting.reason = redirectingreason_for_q931(ctrl, ++ invoke->args.qsig.DivertingLegInformation1.diversion_reason); ++ if (call->redirecting.count < PRI_MAX_REDIRECTS) { ++ ++call->redirecting.count; ++ } ++ call->redirecting.state = Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3; ++ break; ++ case ROSE_QSIG_DivertingLegInformation2: ++ call->redirecting.state = Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3; ++ call->redirecting.count = ++ invoke->args.qsig.DivertingLegInformation2.diversion_counter; ++ if (!call->redirecting.count) { ++ /* To be safe, make sure that the count is non-zero. */ ++ call->redirecting.count = 1; ++ } ++ call->redirecting.reason = redirectingreason_for_q931(ctrl, ++ invoke->args.qsig.DivertingLegInformation2.diversion_reason); ++ ++ /* divertingNr is put in redirecting.from.number */ ++ if (invoke->args.qsig.DivertingLegInformation2.diverting_present) { ++ rose_copy_presented_number_unscreened_to_q931(ctrl, ++ &call->redirecting.from.number, ++ &invoke->args.qsig.DivertingLegInformation2.diverting); ++ } else if (!call->redirecting_number_in_message) { ++ q931_party_number_init(&call->redirecting.from.number); ++ call->redirecting.from.number.valid = 1; ++ } ++ ++ /* redirectingName is put in redirecting.from.name */ ++ if (invoke->args.qsig.DivertingLegInformation2.redirecting_name_present) { ++ rose_copy_name_to_q931(ctrl, &call->redirecting.from.name, ++ &invoke->args.qsig.DivertingLegInformation2.redirecting_name); ++ } else { ++ q931_party_name_init(&call->redirecting.from.name); ++ } ++ ++ call->redirecting.orig_reason = PRI_REDIR_UNKNOWN; ++ if (invoke->args.qsig.DivertingLegInformation2.original_diversion_reason_present) { ++ call->redirecting.orig_reason = redirectingreason_for_q931(ctrl, ++ invoke->args.qsig.DivertingLegInformation2.original_diversion_reason); ++ } ++ ++ /* originalCalledNr is put in redirecting.orig_called.number */ ++ if (invoke->args.qsig.DivertingLegInformation2.original_called_present) { ++ rose_copy_presented_number_unscreened_to_q931(ctrl, ++ &call->redirecting.orig_called.number, ++ &invoke->args.qsig.DivertingLegInformation2.original_called); ++ } else { ++ q931_party_number_init(&call->redirecting.orig_called.number); ++ } ++ ++ /* originalCalledName is put in redirecting.orig_called.name */ ++ if (invoke->args.qsig.DivertingLegInformation2.original_called_name_present) { ++ rose_copy_name_to_q931(ctrl, &call->redirecting.orig_called.name, ++ &invoke->args.qsig.DivertingLegInformation2.original_called_name); ++ } else { ++ q931_party_name_init(&call->redirecting.orig_called.name); ++ } ++ break; ++ case ROSE_QSIG_DivertingLegInformation3: ++ /* ++ * Unless otherwise indicated by CONNECT, this will be the ++ * remote_id.number.presentation. ++ */ ++ if (!invoke->args.qsig.DivertingLegInformation3.presentation_allowed_indicator) { ++ call->redirecting.to.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ if (!call->connected_number_in_message) { ++ call->remote_id.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ } ++ } ++ ++ /* redirectionName is put in redirecting.to.name */ ++ if (invoke->args.qsig.DivertingLegInformation3.redirection_name_present) { ++ rose_copy_name_to_q931(ctrl, &call->redirecting.to.name, ++ &invoke->args.qsig.DivertingLegInformation3.redirection_name); ++ if (!invoke->args.qsig.DivertingLegInformation3.presentation_allowed_indicator) { ++ call->redirecting.to.name.presentation = PRI_PRES_RESTRICTED; ++ } ++ } else { ++ q931_party_name_init(&call->redirecting.to.name); ++ } ++ ++ switch (call->redirecting.state) { ++ case Q931_REDIRECTING_STATE_EXPECTING_RX_DIV_LEG_3: ++ call->redirecting.state = Q931_REDIRECTING_STATE_IDLE; ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (!subcmd) { ++ pri_error(ctrl, "ERROR: Too many facility subcommands\n"); ++ break; ++ } ++ /* Setup redirecting subcommand */ ++ subcmd->cmd = PRI_SUBCMD_REDIRECTING; ++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting, ++ &call->redirecting); ++ break; ++ default: ++ break; ++ } ++ break; ++#if 0 /* Not handled yet */ ++ case ROSE_QSIG_CfnrDivertedLegFailed: ++ break; ++#endif /* Not handled yet */ ++#if 0 /* Not handled yet */ ++ case ROSE_QSIG_MWIActivate: ++ break; ++ case ROSE_QSIG_MWIDeactivate: ++ break; ++ case ROSE_QSIG_MWIInterrogate: ++ break; ++#endif /* Not handled yet */ ++ default: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "!! ROSE invoke operation not handled! %s\n", ++ rose_operation2str(invoke->operation)); ++ } ++ break; ++ } + } +- +Index: pri_facility.h +=================================================================== +--- a/pri_facility.h (.../tags/1.4.10.2) (revision 1357) ++++ b/pri_facility.h (.../branches/1.4) (revision 1357) +@@ -31,123 +31,21 @@ + #define _PRI_FACILITY_H + #include "pri_q931.h" + ++/* Forward declare some structs */ ++struct fac_extension_header; ++struct rose_msg_invoke; ++struct rose_msg_result; ++struct rose_msg_error; ++struct rose_msg_reject; ++ + /* Protocol Profile field */ ++#define Q932_PROTOCOL_MASK 0x1F + #define Q932_PROTOCOL_ROSE 0x11 /* X.219 & X.229 */ + #define Q932_PROTOCOL_CMIP 0x12 /* Q.941 */ + #define Q932_PROTOCOL_ACSE 0x13 /* X.217 & X.227 */ + #define Q932_PROTOCOL_GAT 0x16 + #define Q932_PROTOCOL_EXTENSIONS 0x1F + +-/* Argument values */ +-#define ROSE_NAME_PRESENTATION_ALLOWED_SIMPLE 0x80 +-#define ROSE_NAME_PRESENTATION_RESTRICTED_NULL 0x87 +-#define ROSE_NAME_PRESENTATION_ALLOWED_EXTENDED 0xA1 +-#define ROSE_NAME_PRESENTATION_RESTRICTED_SIMPLE 0xA2 +-#define ROSE_NAME_PRESENTATION_RESTRICTED_EXTENDED 0xA3 +-#define ROSE_NAME_NOT_AVAIL 0x84 +- +-/* Component types */ +-#define COMP_TYPE_INTERPRETATION 0x8B +-#define COMP_TYPE_NETWORK_PROTOCOL_PROFILE 0x92 +-#define COMP_TYPE_INVOKE 0xA1 +-#define COMP_TYPE_RETURN_RESULT 0xA2 +-#define COMP_TYPE_RETURN_ERROR 0xA3 +-#define COMP_TYPE_REJECT 0xA4 +-#define COMP_TYPE_NFE 0xAA +- +-/* Operation ID values */ +-/* Q.952.7 (ECMA-178) ROSE operations (Transfer) */ +-#define ROSE_CALL_TRANSFER_IDENTIFY 7 +-#define ROSE_CALL_TRANSFER_ABANDON 8 +-#define ROSE_CALL_TRANSFER_INITIATE 9 +-#define ROSE_CALL_TRANSFER_SETUP 10 +-#define ROSE_CALL_TRANSFER_ACTIVE 11 +-#define ROSE_CALL_TRANSFER_COMPLETE 12 +-#define ROSE_CALL_TRANSFER_UPDATE 13 +-#define ROSE_SUBADDRESS_TRANSFER 14 +-/* Q.952 ROSE operations (Diverting) */ +-#define ROSE_DIVERTING_LEG_INFORMATION1 18 +-#define ROSE_DIVERTING_LEG_INFORMATION2 0x15 +-#define ROSE_DIVERTING_LEG_INFORMATION3 19 +-/* Q.956 ROSE operations (Advice Of Charge) */ +-#define ROSE_AOC_NO_CHARGING_INFO_AVAILABLE 26 +-#define ROSE_AOC_CHARGING_REQUEST 30 +-#define ROSE_AOC_AOCS_CURRENCY 31 +-#define ROSE_AOC_AOCS_SPECIAL_ARR 32 +-#define ROSE_AOC_AOCD_CURRENCY 33 +-#define ROSE_AOC_AOCD_CHARGING_UNIT 34 +-#define ROSE_AOC_AOCE_CURRENCY 35 +-#define ROSE_AOC_AOCE_CHARGING_UNIT 36 +-#define ROSE_AOC_IDENTIFICATION_OF_CHARGE 37 +-/* Q.SIG operations */ +-#define SS_CNID_CALLINGNAME 0 +-#define SS_ANFPR_PATHREPLACEMENT 4 +-#define SS_DIVERTING_LEG_INFORMATION2 21 +-#define SS_MWI_ACTIVATE 80 +-#define SS_MWI_DEACTIVATE 81 +-#define SS_MWI_INTERROGATE 82 +- +-/* ROSE definitions and data structures */ +-#define INVOKE_IDENTIFIER 0x02 +-#define INVOKE_LINKED_IDENTIFIER 0x80 +-#define INVOKE_NULL_IDENTIFIER __USE_ASN1_NULL +- +-/* ASN.1 Identifier Octet - Data types */ +-#define ASN1_TYPE_MASK 0x1f +-#define ASN1_BOOLEAN 0x01 +-#define ASN1_INTEGER 0x02 +-#define ASN1_BITSTRING 0x03 +-#define ASN1_OCTETSTRING 0x04 +-#define ASN1_NULL 0x05 +-#define ASN1_OBJECTIDENTIFIER 0x06 +-#define ASN1_OBJECTDESCRIPTOR 0x07 +-#define ASN1_EXTERN 0x08 +-#define ASN1_REAL 0x09 +-#define ASN1_ENUMERATED 0x0a +-#define ASN1_EMBEDDEDPDV 0x0b +-#define ASN1_UTF8STRING 0x0c +-#define ASN1_RELATIVEOBJECTID 0x0d +-/* 0x0e & 0x0f are reserved for future ASN.1 editions */ +-#define ASN1_SEQUENCE 0x10 +-#define ASN1_SET 0x11 +-#define ASN1_NUMERICSTRING 0x12 +-#define ASN1_PRINTABLESTRING 0x13 +-#define ASN1_TELETEXSTRING 0x14 +-#define ASN1_IA5STRING 0x16 +-#define ASN1_UTCTIME 0x17 +-#define ASN1_GENERALIZEDTIME 0x18 +- +-/* ASN.1 Identifier Octet - Tags */ +-#define ASN1_TAG_0 0x00 +-#define ASN1_TAG_1 0x01 +-#define ASN1_TAG_2 0x02 +-#define ASN1_TAG_3 0x03 +-#define ASN1_TAG_4 0x04 +-#define ASN1_TAG_5 0x05 +-#define ASN1_TAG_6 0x06 +-#define ASN1_TAG_7 0x07 +-#define ASN1_TAG_8 0x08 +-#define ASN1_TAG_9 0x09 +- +-/* ASN.1 Identifier Octet - Primitive/Constructor Bit */ +-#define ASN1_PC_MASK 0x20 +-#define ASN1_PRIMITIVE 0x00 +-#define ASN1_CONSTRUCTOR 0x20 +- +-/* ASN.1 Identifier Octet - Clan Bits */ +-#define ASN1_CLAN_MASK 0xc0 +-#define ASN1_UNIVERSAL 0x00 +-#define ASN1_APPLICATION 0x40 +-#define ASN1_CONTEXT_SPECIFIC 0x80 +-#define ASN1_PRIVATE 0xc0 +- +-/* ASN.1 Length masks */ +-#define ASN1_LEN_INDEF 0x80 +- +- +-#define INVOKE_OPERATION_INT __USE_ASN1_INTEGER +-#define INVOKE_OBJECT_ID __USE_ASN1_OBJECTIDENTIFIER +- + /* Q.952 Divert cause */ + #define Q952_DIVERT_REASON_UNKNOWN 0x00 + #define Q952_DIVERT_REASON_CFU 0x01 +@@ -169,138 +67,112 @@ + #define Q932_TON_SUBSCRIBER 0x04 + #define Q932_TON_ABBREVIATED 0x06 + +-/* RLT related Operations */ +-#define RLT_SERVICE_ID 0x3e +-#define RLT_OPERATION_IND 0x01 +-#define RLT_THIRD_PARTY 0x02 ++/* Q.SIG Subscription Option. Listed in ECMA-174 */ ++#define QSIG_NO_NOTIFICATION 0x00 ++#define QSIG_NOTIFICATION_WITHOUT_DIVERTED_TO_NR 0x01 ++#define QSIG_NOTIFICATION_WITH_DIVERTED_TO_NR 0x02 + +-struct rose_component { +- u_int8_t type; +- u_int8_t len; +- u_int8_t data[0]; ++/*! Reasons an APDU callback is called. */ ++enum APDU_CALLBACK_REASON { ++ /*! ++ * \brief Send setup error. Abort and cleanup. ++ * \note The message may or may not actually get sent. ++ * \note The callback cannot generate an event subcmd. ++ * \note The callback should not send messages. Out of order messages will result. ++ */ ++ APDU_CALLBACK_REASON_ERROR, ++ /*! ++ * \brief Abort and cleanup. ++ * \note The APDU queue is being destroyed. ++ * \note The callback cannot generate an event subcmd. ++ * \note The callback cannot send messages as the call is likely being destroyed. ++ */ ++ APDU_CALLBACK_REASON_CLEANUP, ++ /*! ++ * \brief Timeout waiting for responses to the message. ++ * \note The callback can generate an event subcmd. ++ * \note The callback can send messages. ++ */ ++ APDU_CALLBACK_REASON_TIMEOUT, ++ /*! ++ * \brief Received a facility response message. ++ * \note The callback can generate an event subcmd. ++ * \note The callback can send messages. ++ */ ++ APDU_CALLBACK_REASON_MSG_RESULT, ++ /*! ++ * \brief Received a facility error message. ++ * \note The callback can generate an event subcmd. ++ * \note The callback can send messages. ++ */ ++ APDU_CALLBACK_REASON_MSG_ERROR, ++ /*! ++ * \brief Received a facility reject message. ++ * \note The callback can generate an event subcmd. ++ * \note The callback can send messages. ++ */ ++ APDU_CALLBACK_REASON_MSG_REJECT, + }; + +-#if 1 +- #define GET_COMPONENT(component, idx, ptr, length) \ +- if ((idx)+2 > (length)) \ +- break; \ +- (component) = (struct rose_component*)&((ptr)[idx]); \ +- if ((idx)+(component)->len+2 > (length)) { \ +- if ((component)->len != ASN1_LEN_INDEF) \ +- pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \ +- } +-#else /* Debugging */ +- #define GET_COMPONENT(component, idx, ptr, length) \ +- if ((idx)+2 > (length)) \ +- break; \ +- (component) = (struct rose_component*)&((ptr)[idx]); \ +- if ((idx)+(component)->len+2 > (length)) { \ +- if ((component)->len != 128) \ +- pri_message(pri, "Length (%d) of 0x%X component is too long\n", (component)->len, (component)->type); \ +- } \ +- pri_message(pri, "XX %s:%d Got component %d (0x%02X), length %d\n", __FUNCTION__, __LINE__, (component)->type, (component)->type, (component)->len); \ +- if ((component)->len > 0) { \ +- int zzz; \ +- pri_message(pri, "XX Data:"); \ +- for (zzz = 0; zzz < (component)->len; ++zzz) \ +- pri_message(pri, " %02X", (component)->data[zzz]); \ +- pri_message(pri, "\n"); \ +- } +-#endif ++union apdu_msg_data { ++ const struct rose_msg_result *result; ++ const struct rose_msg_error *error; ++ const struct rose_msg_reject *reject; ++}; + +-#define NEXT_COMPONENT(component, idx) \ +- (idx) += (component)->len + 2 ++union apdu_callback_param { ++ void *ptr; ++ long value; ++ char pad[8]; ++}; + +-#define SUB_COMPONENT(component, idx) \ +- (idx) += 2 ++struct apdu_callback_data { ++ /*! APDU invoke id to match with any response messages. (Result/Error/Reject) */ ++ int invoke_id; ++ /*! ++ * \brief Time to wait for responses to APDU in ms. ++ * \note Set to 0 if send the message only. ++ * \note Set to less than 0 for PRI_TIMER_T_RESPONSE time. ++ */ ++ int timeout_time; ++ /*! ++ * \brief APDU callback function. ++ * ++ * \param reason Reason callback is called. ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. ++ * \param apdu APDU queued entry. Do not change! ++ * \param msg APDU response message data. (NULL if was not the reason called.) ++ * ++ * \note ++ * A callback must be supplied if the sender cares about any APDU_CALLBACK_REASON. ++ * ++ * \return TRUE if no more responses are expected. ++ */ ++ int (*callback)(enum APDU_CALLBACK_REASON reason, struct pri *ctrl, struct q931_call *call, struct apdu_event *apdu, const union apdu_msg_data *msg); ++ /*! \brief Sender data for the callback function to identify the particular APDU. */ ++ union apdu_callback_param user; ++}; + +-#define CHECK_COMPONENT(component, comptype, message) \ +- if ((component)->type && ((component)->type & ASN1_TYPE_MASK) != (comptype)) { \ +- pri_message(pri, (message), (component)->type); \ +- asn1_dump(pri, (component), (component)->len+2); \ +- break; \ +- } +- +-#define ASN1_GET_INTEGER(component, variable) \ +- do { \ +- int comp_idx; \ +- (variable) = 0; \ +- for (comp_idx = 0; comp_idx < (component)->len; ++comp_idx) \ +- (variable) = ((variable) << 8) | (component)->data[comp_idx]; \ +- } while (0) ++struct apdu_event { ++ /*! Linked list pointer */ ++ struct apdu_event *next; ++ /*! TRUE if this APDU has been sent. */ ++ int sent; ++ /*! What message to send the ADPU in */ ++ int message; ++ /*! Sender supplied information to handle APDU response messages. */ ++ struct apdu_callback_data response; ++ /*! Q.931 call leg. (Needed for the APDU timeout.) */ ++ struct q931_call *call; ++ /*! Response timeout timer. */ ++ int timer; ++ /*! Length of ADPU */ ++ int apdu_len; ++ /*! ADPU to send */ ++ unsigned char apdu[255]; ++}; + +-#define ASN1_FIXUP_LEN(component, size) \ +- do { \ +- if ((component)->len == ASN1_LEN_INDEF) \ +- size += 2; \ +- } while (0) +- +-#define ASN1_ADD_SIMPLE(component, comptype, ptr, idx) \ +- do { \ +- (component) = (struct rose_component *)&((ptr)[(idx)]); \ +- (component)->type = (comptype); \ +- (component)->len = 0; \ +- (idx) += 2; \ +- } while (0) +- +-#define ASN1_ADD_BYTECOMP(component, comptype, ptr, idx, value) \ +- do { \ +- (component) = (struct rose_component *)&((ptr)[(idx)]); \ +- (component)->type = (comptype); \ +- (component)->len = 1; \ +- (component)->data[0] = (value); \ +- (idx) += 3; \ +- } while (0) +- +-#define ASN1_ADD_WORDCOMP(component, comptype, ptr, idx, value) \ +- do { \ +- int __val = (value); \ +- int __i = 0; \ +- (component) = (struct rose_component *)&((ptr)[(idx)]); \ +- (component)->type = (comptype); \ +- if ((__val >> 24)) \ +- (component)->data[__i++] = (__val >> 24) & 0xff; \ +- if ((__val >> 16)) \ +- (component)->data[__i++] = (__val >> 16) & 0xff; \ +- if ((__val >> 8)) \ +- (component)->data[__i++] = (__val >> 8) & 0xff; \ +- (component)->data[__i++] = __val & 0xff; \ +- (component)->len = __i; \ +- (idx) += 2 + __i; \ +- } while (0) +- +-#define ASN1_PUSH(stack, stackpointer, component) \ +- (stack)[(stackpointer)++] = (component) +- +-#define ASN1_FIXUP(stack, stackpointer, data, idx) \ +- do { \ +- --(stackpointer); \ +- (stack)[(stackpointer)]->len = (unsigned char *)&((data)[(idx)]) - (unsigned char *)(stack)[(stackpointer)] - 2; \ +- } while (0) +- +-/* Decoder for the invoke ROSE component */ +-int rose_invoke_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len); +- +-/* Decoder for the return result ROSE component */ +-int rose_return_result_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len); +- +-/* Decoder for the return error ROSE component */ +-int rose_return_error_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len); +- +-/* Decoder for the reject ROSE component */ +-int rose_reject_decode(struct pri *pri, struct q931_call *call, q931_ie *ie, unsigned char *data, int len); +- +-int asn1_copy_string(char * buf, int buflen, struct rose_component *comp); +- +-int asn1_string_encode(unsigned char asn1_type, void *data, int len, int max_len, void *src, int src_len); +- +-/* Get Name types from ASN.1 */ +-int asn1_name_decode(void * data, int len, char *namebuf, int buflen); +- +-int typeofnumber_from_q931(struct pri *pri, int ton); +- +-int redirectingreason_from_q931(struct pri *pri, int redirectingreason); +- + /* Queues an MWI apdu on a the given call */ + int mwi_message_send(struct pri *pri, q931_call *call, struct pri_sr *req, int activate); + +@@ -310,21 +182,31 @@ + int rlt_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2); + + int qsig_cf_callrerouting(struct pri *pri, q931_call *c, const char* dest, const char* original, const char* reason); ++int send_reroute_request(struct pri *ctrl, q931_call *call, const struct q931_party_id *caller, const struct q931_party_redirecting *deflection, int subscription_option); + + /* starts a QSIG Path Replacement */ + int anfpr_initiate_transfer(struct pri *pri, q931_call *c1, q931_call *c2); + +-/* Use this function to queue a facility-IE born APDU onto a call +- * call is the call to use, messagetype is any one of the Q931 messages, +- * apdu is the apdu data, apdu_len is the length of the apdu data */ +-int pri_call_apdu_queue(q931_call *call, int messagetype, void *apdu, int apdu_len, void (*function)(void *data), void *data); ++int send_call_transfer_complete(struct pri *pri, q931_call *call, int call_status); + +-/* Used by q931.c to cleanup the apdu queue upon destruction of a call */ +-int pri_call_apdu_queue_cleanup(q931_call *call); ++int rose_diverting_leg_information1_encode(struct pri *pri, q931_call *call); ++int rose_diverting_leg_information3_encode(struct pri *pri, q931_call *call, int messagetype); + ++int rose_connected_name_encode(struct pri *pri, q931_call *call, int messagetype); ++int rose_called_name_encode(struct pri *pri, q931_call *call, int messagetype); ++ ++int pri_call_apdu_queue(q931_call *call, int messagetype, const unsigned char *apdu, int apdu_len, struct apdu_callback_data *response); ++void pri_call_apdu_queue_cleanup(q931_call *call); ++void pri_call_apdu_delete(struct q931_call *call, struct apdu_event *doomed); ++ + /* Adds the "standard" APDUs to a call */ + int pri_call_add_standard_apdus(struct pri *pri, q931_call *call); + +-int asn1_dump(struct pri *pri, void *comp, int len); ++void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1, const unsigned char *end); + ++void rose_handle_invoke(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_invoke *invoke); ++void rose_handle_result(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_result *result); ++void rose_handle_error(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_error *error); ++void rose_handle_reject(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, const struct fac_extension_header *header, const struct rose_msg_reject *reject); ++ + #endif /* _PRI_FACILITY_H */ +Index: libpri.h +=================================================================== +--- a/libpri.h (.../tags/1.4.10.2) (revision 1357) ++++ b/libpri.h (.../branches/1.4) (revision 1357) +@@ -26,7 +26,14 @@ + * provided with that copy of Asterisk, instead of the license + * terms granted here. + */ +- ++ ++/* ++ * NOTE: ++ * All new global identifiers that are added to this file MUST be ++ * prefixed with PRI_ or pri_ to indicate that they are part of this ++ * library and to reduce potential naming conflicts. ++ */ ++ + #ifndef _LIBPRI_H + #define _LIBPRI_H + +@@ -73,7 +80,8 @@ + #define PRI_EVENT_ANSWER 8 /* Call has been answered (CONNECT) */ + #define PRI_EVENT_HANGUP_ACK 9 /* Call hangup has been acknowledged */ + #define PRI_EVENT_RESTART_ACK 10 /* Restart complete on a given channel (RESTART_ACKNOWLEDGE) */ +-#define PRI_EVENT_FACNAME 11 /* Caller*ID Name received on Facility */ ++#define PRI_EVENT_FACNAME 11 /* Caller*ID Name received on Facility (DEPRECATED) */ ++#define PRI_EVENT_FACILITY 11 /* Facility received (FACILITY) */ + #define PRI_EVENT_INFO_RECEIVED 12 /* Additional info (digits) received (INFORMATION) */ + #define PRI_EVENT_PROCEEDING 13 /* When we get CALL_PROCEEDING */ + #define PRI_EVENT_SETUP_ACK 14 /* When we get SETUP_ACKNOWLEDGE */ +@@ -81,6 +89,14 @@ + #define PRI_EVENT_NOTIFY 16 /* Notification received (NOTIFY) */ + #define PRI_EVENT_PROGRESS 17 /* When we get PROGRESS */ + #define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state (INFORMATION) */ ++#define PRI_EVENT_SERVICE 19 /* SERVICE maintenance message */ ++#define PRI_EVENT_SERVICE_ACK 20 /* SERVICE maintenance acknowledgement message */ ++#define PRI_EVENT_HOLD 21 /* HOLD request received */ ++#define PRI_EVENT_HOLD_ACK 22 /* HOLD_ACKNOWLEDGE received */ ++#define PRI_EVENT_HOLD_REJ 23 /* HOLD_REJECT received */ ++#define PRI_EVENT_RETRIEVE 24 /* RETRIEVE request received */ ++#define PRI_EVENT_RETRIEVE_ACK 25 /* RETRIEVE_ACKNOWLEDGE received */ ++#define PRI_EVENT_RETRIEVE_REJ 26 /* RETRIEVE_REJECT received */ + + /* Simple states */ + #define PRI_STATE_DOWN 0 +@@ -101,13 +117,13 @@ + #define PRI_PROG_CALLER_RETURNED_TO_ISDN (1 << 9) + + /* Numbering plan identifier */ +-#define PRI_NPI_UNKNOWN 0x0 +-#define PRI_NPI_E163_E164 0x1 +-#define PRI_NPI_X121 0x3 +-#define PRI_NPI_F69 0x4 +-#define PRI_NPI_NATIONAL 0x8 +-#define PRI_NPI_PRIVATE 0x9 +-#define PRI_NPI_RESERVED 0xF ++#define PRI_NPI_UNKNOWN 0x0 /*!< Unknown numbering plan */ ++#define PRI_NPI_E163_E164 0x1 /*!< ISDN/telephony numbering plan (public) */ ++#define PRI_NPI_X121 0x3 /*!< Data numbering plan */ ++#define PRI_NPI_F69 0x4 /*!< Telex numbering plan */ ++#define PRI_NPI_NATIONAL 0x8 /*!< National standard numbering plan */ ++#define PRI_NPI_PRIVATE 0x9 /*!< Private numbering plan */ ++#define PRI_NPI_RESERVED 0xF /*!< Reserved for extension */ + + /* Type of number */ + #define PRI_TON_UNKNOWN 0x0 +@@ -135,16 +151,49 @@ + #define PRI_UNKNOWN 0x0 + + /* Presentation */ +-#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00 +-#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01 +-#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02 +-#define PRES_ALLOWED_NETWORK_NUMBER 0x03 +-#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20 +-#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21 +-#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22 +-#define PRES_PROHIB_NETWORK_NUMBER 0x23 +-#define PRES_NUMBER_NOT_AVAILABLE 0x43 ++#define PRI_PRES_NUMBER_TYPE 0x03 ++#define PRI_PRES_USER_NUMBER_UNSCREENED 0x00 ++#define PRI_PRES_USER_NUMBER_PASSED_SCREEN 0x01 ++#define PRI_PRES_USER_NUMBER_FAILED_SCREEN 0x02 ++#define PRI_PRES_NETWORK_NUMBER 0x03 + ++#define PRI_PRES_RESTRICTION 0x60 ++#define PRI_PRES_ALLOWED 0x00 ++#define PRI_PRES_RESTRICTED 0x20 ++#define PRI_PRES_UNAVAILABLE 0x40 ++#define PRI_PRES_RESERVED 0x60 ++ ++#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED \ ++ (PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED) ++ ++#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN \ ++ (PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_PASSED_SCREEN) ++ ++#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN \ ++ (PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_FAILED_SCREEN) ++ ++#define PRES_ALLOWED_NETWORK_NUMBER \ ++ (PRI_PRES_ALLOWED | PRI_PRES_NETWORK_NUMBER) ++ ++#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED \ ++ (PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED) ++ ++#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN \ ++ (PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_PASSED_SCREEN) ++ ++#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN \ ++ (PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_FAILED_SCREEN) ++ ++#define PRES_PROHIB_NETWORK_NUMBER \ ++ (PRI_PRES_RESTRICTED | PRI_PRES_NETWORK_NUMBER) ++ ++#define PRES_NUMBER_NOT_AVAILABLE \ ++ (PRI_PRES_UNAVAILABLE | PRI_PRES_NETWORK_NUMBER) ++ ++/* Reverse Charging Indication */ ++#define PRI_REVERSECHARGE_NONE -1 ++#define PRI_REVERSECHARGE_REQUESTED 1 ++ + /* Causes for disconnection */ + #define PRI_CAUSE_UNALLOCATED 1 + #define PRI_CAUSE_NO_ROUTE_TRANSIT_NET 2 /* !Q.SIG */ +@@ -157,6 +206,7 @@ + #define PRI_CAUSE_NO_ANSWER 19 + #define PRI_CAUSE_CALL_REJECTED 21 + #define PRI_CAUSE_NUMBER_CHANGED 22 ++#define PRI_CAUSE_NONSELECTED_USER_CLEARING 26 + #define PRI_CAUSE_DESTINATION_OUT_OF_ORDER 27 + #define PRI_CAUSE_INVALID_NUMBER_FORMAT 28 + #define PRI_CAUSE_FACILITY_REJECTED 29 /* !Q.SIG */ +@@ -169,6 +219,7 @@ + #define PRI_CAUSE_ACCESS_INFO_DISCARDED 43 /* !Q.SIG */ + #define PRI_CAUSE_REQUESTED_CHAN_UNAVAIL 44 + #define PRI_CAUSE_PRE_EMPTED 45 /* !Q.SIG */ ++#define PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED 47 + #define PRI_CAUSE_FACILITY_NOT_SUBSCRIBED 50 /* !Q.SIG */ + #define PRI_CAUSE_OUTGOING_CALL_BARRED 52 /* !Q.SIG */ + #define PRI_CAUSE_INCOMING_CALL_BARRED 54 /* !Q.SIG */ +@@ -259,8 +310,8 @@ + #define PRI_RATE_ADAPT_ASYNC 0x40 + + /* Notifications */ +-#define PRI_NOTIFY_USER_SUSPENDED 0x00 /* User suspended */ +-#define PRI_NOTIFY_USER_RESUMED 0x01 /* User resumed */ ++#define PRI_NOTIFY_USER_SUSPENDED 0x00 /* User suspended (Q.931) (Call is placed on hold) */ ++#define PRI_NOTIFY_USER_RESUMED 0x01 /* User resumed (Q.931) (Call is taken off hold) */ + #define PRI_NOTIFY_BEARER_CHANGE 0x02 /* Bearer service change (DSS1) */ + #define PRI_NOTIFY_ASN1_COMPONENT 0x03 /* ASN.1 encoded component (DSS1) */ + #define PRI_NOTIFY_COMPLETION_DELAY 0x04 /* Call completion delay */ +@@ -275,12 +326,12 @@ + #define PRI_NOTIFY_CONF_OTHER_DISCONNECTED 0x4a /* Other party disconnected */ + #define PRI_NOTIFY_CONF_FLOATING 0x4b /* Conference floating */ + #define PRI_NOTIFY_WAITING_CALL 0x60 /* Call is waiting call */ +-#define PRI_NOTIFY_DIVERSION_ACTIVATED 0x68 /* Diversion activated (DSS1) */ +-#define PRI_NOTIFY_TRANSFER_ALERTING 0x69 /* Call transfer, alerting */ +-#define PRI_NOTIFY_TRANSFER_ACTIVE 0x6a /* Call transfer, active */ ++#define PRI_NOTIFY_DIVERSION_ACTIVATED 0x68 /* Diversion activated (DSS1) (cfu, cfb, cfnr) (EN 300 207-1 Section 7.2.1) */ ++#define PRI_NOTIFY_TRANSFER_ALERTING 0x69 /* Call transfer, alerting (EN 300 369-1 Section 7.2) */ ++#define PRI_NOTIFY_TRANSFER_ACTIVE 0x6a /* Call transfer, active(answered) (EN 300 369-1 Section 7.2) */ + #define PRI_NOTIFY_REMOTE_HOLD 0x79 /* Remote hold */ + #define PRI_NOTIFY_REMOTE_RETRIEVAL 0x7a /* Remote retrieval */ +-#define PRI_NOTIFY_CALL_DIVERTING 0x7b /* Call is diverting */ ++#define PRI_NOTIFY_CALL_DIVERTING 0x7b /* Call is diverting (EN 300 207-1 Section 7.2.1) */ + + #define PRI_COPY_DIGITS_CALLED_NUMBER + +@@ -305,6 +356,200 @@ + + typedef struct q931_call q931_call; + ++/* Name character set enumeration values */ ++#define PRI_CHAR_SET_UNKNOWN 0 ++#define PRI_CHAR_SET_ISO8859_1 1 ++#define PRI_CHAR_SET_WITHDRAWN 2 ++#define PRI_CHAR_SET_ISO8859_2 3 ++#define PRI_CHAR_SET_ISO8859_3 4 ++#define PRI_CHAR_SET_ISO8859_4 5 ++#define PRI_CHAR_SET_ISO8859_5 6 ++#define PRI_CHAR_SET_ISO8859_7 7 ++#define PRI_CHAR_SET_ISO10646_BMPSTRING 8 ++#define PRI_CHAR_SET_ISO10646_UTF_8STRING 9 ++ ++/*! \brief Q.SIG name information. */ ++struct pri_party_name { ++ /*! \brief TRUE if the name information is valid/present */ ++ int valid; ++ /*! ++ * \brief Q.931 presentation-indicator encoded field ++ * \note Must tollerate the Q.931 screening-indicator field values being present. ++ */ ++ int presentation; ++ /*! ++ * \brief Character set the name is using. ++ * \details ++ * unknown(0), ++ * iso8859-1(1), ++ * enum-value-withdrawn-by-ITU-T(2) ++ * iso8859-2(3), ++ * iso8859-3(4), ++ * iso8859-4(5), ++ * iso8859-5(6), ++ * iso8859-7(7), ++ * iso10646-BmpString(8), ++ * iso10646-utf-8String(9) ++ * \details ++ * Set to iso8859-1(1) if unsure what to use. ++ */ ++ int char_set; ++ /*! \brief Name data with null terminator. */ ++ char str[64]; ++}; ++ ++struct pri_party_number { ++ /*! \brief TRUE if the number information is valid/present */ ++ int valid; ++ /*! \brief Q.931 presentation-indicator and screening-indicator encoded fields */ ++ int presentation; ++ /*! \brief Q.931 Type-Of-Number and numbering-plan encoded fields */ ++ int plan; ++ /*! \brief Number data with null terminator. */ ++ char str[64]; ++}; ++ ++/*! ++ * \note This structure is a place holder for possible future subaddress support ++ * to maintain ABI compatibility. ++ */ ++struct pri_party_subaddress { ++ /*! \brief TRUE if the subaddress information is valid/present */ ++ int valid; ++ /*! ++ * \brief Subaddress type. ++ * \details ++ * nsap(0), ++ * user_specified(2) ++ */ ++ int type; ++ /*! ++ * \brief TRUE if odd number of address signals ++ * \note The odd/even indicator is used when the type of subaddress is ++ * user_specified and the coding is BCD. ++ */ ++ int odd_even_indicator; ++ /*! \brief Length of the subaddress data */ ++ int length; ++ /*! ++ * \brief Subaddress data with null terminator. ++ * \note The null terminator is a convenience only since the data could be ++ * BCD/binary and thus have a null byte as part of the contents. ++ */ ++ unsigned char data[32]; ++}; ++ ++/*! \brief Information needed to identify an endpoint in a call. */ ++struct pri_party_id { ++ /*! \brief Subscriber name */ ++ struct pri_party_name name; ++ /*! \brief Subscriber phone number */ ++ struct pri_party_number number; ++ /*! \brief Subscriber subaddress */ ++ struct pri_party_subaddress subaddress; ++}; ++ ++/*! \brief Connected Line/Party information */ ++struct pri_party_connected_line { ++ /*! Connected party ID */ ++ struct pri_party_id id; ++}; ++ ++/*! ++ * \brief Redirecting Line information. ++ * \details ++ * RDNIS (Redirecting Directory Number Information Service) ++ * Where a call diversion or transfer was invoked. ++ */ ++struct pri_party_redirecting { ++ /*! Who is redirecting the call (Sent to the party the call is redirected toward) */ ++ struct pri_party_id from; ++ /*! Call is redirecting to a new party (Sent to the caller) */ ++ struct pri_party_id to; ++ /*! Originally called party (in cases of multiple redirects) */ ++ struct pri_party_id orig_called; ++ /*! Number of times the call was redirected */ ++ int count; ++ /*! Original reason for redirect (in cases of multiple redirects) */ ++ int orig_reason; ++ /*! Redirection reason */ ++ int reason; ++}; ++ ++/*! ++ * \brief Information for rerouting/deflecting the call. ++ */ ++struct pri_rerouting_data { ++ /*! ++ * \brief Updated caller-id information. ++ * \note The information may have been altered by procedure in the private network. ++ */ ++ struct pri_party_id caller; ++ /*! ++ * \note ++ * deflection.to is the new called number and must always be present. ++ */ ++ struct pri_party_redirecting deflection; ++ /*! ++ * \brief Diverting user subscription option to specify if caller is notified. ++ * \details ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2), ++ * notApplicable(3) (Status only.) ++ */ ++ int subscription_option; ++ /*! Invocation ID to use when sending a reply to the call rerouting/deflection request. */ ++ int invoke_id; ++}; ++ ++/* Subcommands derived from supplementary services. */ ++#define PRI_SUBCMD_REDIRECTING 1 ++#define PRI_SUBCMD_CONNECTED_LINE 2 ++#define PRI_SUBCMD_REROUTING 3 ++ ++ ++struct pri_subcommand { ++ /*! PRI_SUBCMD_xxx defined values */ ++ int cmd; ++ union { ++ /*! Reserve room for possible expansion to maintain ABI compatibility. */ ++ char reserve_space[512]; ++ struct pri_party_connected_line connected_line; ++ struct pri_party_redirecting redirecting; ++ struct pri_rerouting_data rerouting; ++ } u; ++}; ++ ++/* Max number of subcommands per event message */ ++#define PRI_MAX_SUBCOMMANDS 8 ++ ++struct pri_subcommands { ++ int counter_subcmd; ++ struct pri_subcommand subcmd[PRI_MAX_SUBCOMMANDS]; ++}; ++ ++ ++/* ++ * Event channel parameter encoding: ++ * 3322 2222 2222 1111 1111 1100 0000 0000 ++ * 1098 7654 3210 9876 5432 1098 7654 3210 ++ * xxxx xxxx xxxx xEDC BBBBBBBBB AAAAAAAAA ++ * ++ * Bit field ++ * A - B channel ++ * B - Span (DS1) (0 - 127) ++ * C - DS1 Explicit bit ++ * D - D channel (cis_call) bit (status only) ++ * E - Call is held bit (status only) ++ * ++ * B channel values: ++ * 0 - No channel (ISDN uses for call waiting feature) ++ * 1-127 - B channel # ++ * 0xFF - Any channel (Also if whole channel value is -1 in event) ++ */ ++ ++ + typedef struct pri_event_generic { + /* Events with no additional information fall in this category */ + int e; +@@ -328,6 +573,7 @@ + int progressmask; + q931_call *call; + char useruserinfo[260]; /* User->User info */ ++ struct pri_subcommands *subcmds; + } pri_event_ringing; + + typedef struct pri_event_answer { +@@ -338,8 +584,10 @@ + int progressmask; + q931_call *call; + char useruserinfo[260]; /* User->User info */ ++ struct pri_subcommands *subcmds; + } pri_event_answer; + ++/*! Deprecated replaced by struct pri_event_facility. */ + typedef struct pri_event_facname { + int e; + char callingname[256]; +@@ -351,6 +599,24 @@ + int callingplan; /* Dialing plan of Calling entity */ + } pri_event_facname; + ++struct pri_event_facility { ++ int e; ++ char callingname[256]; /*!< Deprecated, preserved for struct pri_event_facname compatibility */ ++ char callingnum[256]; /*!< Deprecated, preserved for struct pri_event_facname compatibility */ ++ int channel; ++ int cref; ++ /*! ++ * \brief Master call or normal call. ++ * \note Call pointer known about by upper layer. ++ * \note NULL if dummy call reference. ++ */ ++ q931_call *call; ++ int callingpres; /*!< Presentation of Calling CallerID (Deprecated, preserved for struct pri_event_facname compatibility) */ ++ int callingplan; /*!< Dialing plan of Calling entity (Deprecated, preserved for struct pri_event_facname compatibility) */ ++ struct pri_subcommands *subcmds; ++ q931_call *subcall; /*!< Subcall to send any reply toward. */ ++}; ++ + #define PRI_CALLINGPLANANI + #define PRI_CALLINGPLANRDNIS + typedef struct pri_event_ring { +@@ -376,13 +642,18 @@ + int layer1; /* User layer 1 */ + int complete; /* Have we seen "Complete" i.e. no more number? */ + q931_call *call; /* Opaque call pointer */ +- char callingsubaddr[256]; /* Calling parties subaddress */ ++ char callingsubaddr[256]; /* Calling parties subaddress, backwards compatibility */ + int progress; + int progressmask; + char origcalledname[256]; + char origcallednum[256]; + int callingplanorigcalled; /* Dialing plan of Originally Called Number */ + int origredirectingreason; ++ int reversecharge; ++ struct pri_subcommands *subcmds; ++ struct pri_party_id calling; /* Calling Party's info, initially subaddress' */ ++ struct pri_party_subaddress called_subaddress; /* Called party's subaddress */ ++ char keypad_digits[64]; /* Keypad digits in the SETUP message. */ + } pri_event_ring; + + typedef struct pri_event_hangup { +@@ -390,10 +661,23 @@ + int channel; /* Channel requested */ + int cause; + int cref; +- q931_call *call; /* Opaque call pointer */ ++ q931_call *call; /* Opaque call pointer of call hanging up. */ + long aoc_units; /* Advise of Charge number of charged units */ + char useruserinfo[260]; /* User->User info */ +-} pri_event_hangup; ++ struct pri_subcommands *subcmds; ++ /*! ++ * \brief Opaque held call pointer for possible transfer to active call. ++ * \note The call_held and call_active pointers must not be NULL if ++ * transfer held call on disconnect is available. ++ */ ++ q931_call *call_held; ++ /*! ++ * \brief Opaque active call pointer for possible transfer with held call. ++ * \note The call_held and call_active pointers must not be NULL if ++ * transfer held call on disconnect is available. ++ */ ++ q931_call *call_active; ++} pri_event_hangup; + + typedef struct pri_event_restart_ack { + int e; +@@ -409,18 +693,22 @@ + int progressmask; + int cause; + q931_call *call; ++ struct pri_subcommands *subcmds; + } pri_event_proceeding; +- ++ + typedef struct pri_event_setup_ack { + int e; + int channel; + q931_call *call; ++ struct pri_subcommands *subcmds; + } pri_event_setup_ack; + + typedef struct pri_event_notify { + int e; + int channel; + int info; ++ struct pri_subcommands *subcmds; ++ q931_call *call; + } pri_event_notify; + + typedef struct pri_event_keypad_digit { +@@ -428,14 +716,72 @@ + int channel; + q931_call *call; + char digits[64]; ++ struct pri_subcommands *subcmds; + } pri_event_keypad_digit; + ++typedef struct pri_event_service { ++ int e; ++ int channel; ++ int changestatus; ++} pri_event_service; ++ ++typedef struct pri_event_service_ack { ++ int e; ++ int channel; ++ int changestatus; ++} pri_event_service_ack; ++ ++struct pri_event_hold { ++ int e; ++ int channel; ++ q931_call *call; ++ struct pri_subcommands *subcmds; ++}; ++ ++struct pri_event_hold_ack { ++ int e; ++ int channel; ++ q931_call *call; ++ struct pri_subcommands *subcmds; ++}; ++ ++struct pri_event_hold_rej { ++ int e; ++ int channel; ++ q931_call *call; ++ int cause; ++ struct pri_subcommands *subcmds; ++}; ++ ++struct pri_event_retrieve { ++ int e; ++ int channel; ++ q931_call *call; ++ int flexible; /* Are we flexible with our channel selection? */ ++ struct pri_subcommands *subcmds; ++}; ++ ++struct pri_event_retrieve_ack { ++ int e; ++ int channel; ++ q931_call *call; ++ struct pri_subcommands *subcmds; ++}; ++ ++struct pri_event_retrieve_rej { ++ int e; ++ int channel; ++ q931_call *call; ++ int cause; ++ struct pri_subcommands *subcmds; ++}; ++ + typedef union { + int e; + pri_event_generic gen; /* Generic view */ + pri_event_restart restart; /* Restart view */ + pri_event_error err; /* Error view */ +- pri_event_facname facname; /* Caller*ID Name on Facility */ ++ pri_event_facname facname; /* Caller*ID Name on Facility (Deprecated, use pri_event.facility) */ + pri_event_ring ring; /* Ring */ + pri_event_hangup hangup; /* Hang up */ + pri_event_ringing ringing; /* Ringing */ +@@ -445,6 +791,15 @@ + pri_event_setup_ack setup_ack; /* SETUP_ACKNOWLEDGE structure */ + pri_event_notify notify; /* Notification */ + pri_event_keypad_digit digit; /* Digits that come during a call */ ++ pri_event_service service; /* service message */ ++ pri_event_service_ack service_ack; /* service acknowledgement message */ ++ struct pri_event_facility facility; ++ struct pri_event_hold hold; ++ struct pri_event_hold_ack hold_ack; ++ struct pri_event_hold_rej hold_rej; ++ struct pri_event_retrieve retrieve; ++ struct pri_event_retrieve_ack retrieve_ack; ++ struct pri_event_retrieve_rej retrieve_rej; + } pri_event; + + struct pri; +@@ -456,7 +811,7 @@ + + /* Create a D-channel on a given file descriptor. The file descriptor must be a + channel operating in HDLC mode with FCS computed by the fd's driver. Also it +- must be NON-BLOCKING! Frames received on the fd should include FCS. Nodetype ++ must be NON-BLOCKING! Frames received on the fd should include FCS. Nodetype + must be one of PRI_NETWORK or PRI_CPE. switchtype should be PRI_SWITCH_* */ + struct pri *pri_new(int fd, int nodetype, int switchtype); + struct pri *pri_new_bri(int fd, int ptpmode, int nodetype, int switchtype); +@@ -521,7 +876,7 @@ + + #define PRI_KEYPAD_FACILITY_TX + /* Send a keypad facility string of digits */ +-int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits); ++int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits); + + /* Answer the incomplete(call without called number) call on the given channel. + Set non-isdn to non-zero if you are not connecting to ISDN equipment */ +@@ -531,6 +886,18 @@ + Set non-isdn to non-zero if you are not connecting to ISDN equipment */ + int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn); + ++/*! ++ * \brief Give connected line information to a call ++ * \note Could be used instead of pri_sr_set_caller_party() before calling pri_setup(). ++ */ ++int pri_connected_line_update(struct pri *pri, q931_call *call, const struct pri_party_connected_line *connected); ++ ++/*! ++ * \brief Give redirection information to a call ++ * \note Could be used instead of pri_sr_set_redirecting_parties() before calling pri_setup(). ++ */ ++int pri_redirecting_update(struct pri *pri, q931_call *call, const struct pri_party_redirecting *redirecting); ++ + /* Set CRV reference for GR-303 calls */ + + +@@ -556,9 +923,20 @@ + + int pri_reset(struct pri *pri, int channel); + ++/* handle b-channel maintenance messages */ ++extern int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus); ++ + /* Create a new call */ + q931_call *pri_new_call(struct pri *pri); + ++/*! ++ * \brief Deterimine if the given call control pointer is a dummy call. ++ * ++ * \retval TRUE if given call is a dummy call. ++ * \retval FALSE otherwise. ++ */ ++int pri_is_dummy_call(q931_call *call); ++ + /* Retrieve CRV reference for GR-303 calls. Returns >0 on success. */ + int pri_get_crv(struct pri *pri, q931_call *call, int *callmode); + +@@ -573,8 +951,8 @@ + extern pri_event *pri_schedule_run_tv(struct pri *pri, const struct timeval *now); + + int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, +- int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres, +- char *called,int calledplan, int ulayer1); ++ int exclusive, int nonisdn, char *caller, int callerplan, char *callername, int callerpres, ++ char *called, int calledplan, int ulayer1); + + struct pri_sr *pri_sr_new(void); + void pri_sr_free(struct pri_sr *sr); +@@ -582,25 +960,91 @@ + int pri_sr_set_channel(struct pri_sr *sr, int channel, int exclusive, int nonisdn); + int pri_sr_set_bearer(struct pri_sr *sr, int transmode, int userl1); + int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int complete); ++ ++/*! ++ * \brief Set the caller party ID information in the call SETUP record. ++ * ++ * \param sr New call SETUP record. ++ * \param caller Caller party ID information to set. ++ * ++ * \return Nothing ++ */ ++void pri_sr_set_caller_party(struct pri_sr *sr, const struct pri_party_id *caller); ++/*! \note Use pri_sr_set_caller_party() instead to pass more precise caller information. */ + int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres); ++ ++/*! ++ * \brief Set the calling subaddress information in the call SETUP record. ++ * ++ * \param sr New call SETUP record. ++ * \param subaddress information to set. ++ * ++ * \return Nothing ++ */ ++void pri_sr_set_caller_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress); ++ ++/*! ++ * \brief Set the called subaddress information in the call SETUP record. ++ * ++ * \param sr New call SETUP record. ++ * \param subaddress information to set. ++ * ++ * \return Nothing ++ */ ++void pri_sr_set_called_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress); ++ ++/*! ++ * \brief Set the redirecting information in the call SETUP record. ++ * ++ * \param sr New call SETUP record. ++ * \param caller Redirecting information to set. ++ * ++ * \return Nothing ++ */ ++void pri_sr_set_redirecting_parties(struct pri_sr *sr, const struct pri_party_redirecting *redirecting); ++/*! \note Use pri_sr_set_redirecting_parties() instead to pass more precise redirecting information. */ + int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason); ++ ++/*! ++ * \brief Set the keypad digits in the call SETUP record. ++ * ++ * \param sr New call SETUP record. ++ * \param keypad_digits Keypad digits to send. ++ * ++ * \return Nothing ++ */ ++void pri_sr_set_keypad_digits(struct pri_sr *sr, const char *keypad_digits); ++ + #define PRI_USER_USER_TX + /* Set the user user field. Warning! don't send binary data accross this field */ + void pri_sr_set_useruser(struct pri_sr *sr, const char *userchars); ++void pri_sr_set_reversecharge(struct pri_sr *sr, int requested); + + void pri_call_set_useruser(q931_call *sr, const char *userchars); + + int pri_setup(struct pri *pri, q931_call *call, struct pri_sr *req); + +-/* Set a call has a call indpendent signalling connection (i.e. no bchan) */ ++/*! ++ * \brief Set a call as a call indpendent signalling connection (i.e. no bchan) ++ * \note Call will automaticlly disconnect after signalling sent. ++ */ + int pri_sr_set_connection_call_independent(struct pri_sr *req); + ++/*! ++ * \brief Set a call as a call indpendent signalling connection (i.e. no bchan) ++ * \note Call will stay connected until explicitly disconnected. ++ */ ++int pri_sr_set_no_channel_call(struct pri_sr *req); ++ + /* Send an MWI indication to a remote location. If activate is non zero, activates, if zero, deactivates */ + int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan); + + /* Send an MWI deactivate request to a remote location */ + int pri_mwi_deactivate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, int calledplan); + ++/* Set service message support flag */ ++int pri_set_service_message_support(struct pri *pri, int supportflag); ++ + #define PRI_2BCT + /* Attempt to pass the channels back to the NET side if compatable and + * suscribed. Sometimes called 2 bchannel transfer (2BCT) */ +@@ -656,48 +1100,208 @@ + + int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason); + ++/*! ++ * \brief Set the call deflection/rerouting feature enable flag. ++ * ++ * \param ctrl D channel controller. ++ * \param enable TRUE to enable call deflection/rerouting feature. ++ * ++ * \return Nothing ++ */ ++void pri_reroute_enable(struct pri *ctrl, int enable); ++ ++/*! ++ * \brief Send the CallRerouting/CallDeflection message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. ++ * \param caller Call rerouting/deflecting updated caller data. (NULL if data not updated.) ++ * \param deflection Call rerouting/deflecting redirection data. ++ * \param subscription_option Diverting user subscription option to specify if caller is notified. ++ * ++ * \note ++ * deflection->to is the new called number and must always be present. ++ * \note ++ * subscription option: ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2) ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int pri_reroute_call(struct pri *ctrl, q931_call *call, const struct pri_party_id *caller, const struct pri_party_redirecting *deflection, int subscription_option); ++ ++enum PRI_REROUTING_RSP_CODE { ++ /*! ++ * Rerouting invocation accepted and the network provider option ++ * "served user call retention on invocation of diversion" ++ * is "clear call on invocation". ++ */ ++ PRI_REROUTING_RSP_OK_CLEAR, ++ /*! ++ * Rerouting invocation accepted and the network provider option ++ * "served user call retention on invocation of diversion" ++ * is "retain call until alerting begins at the deflected-to user". ++ */ ++ PRI_REROUTING_RSP_OK_RETAIN, ++ PRI_REROUTING_RSP_NOT_SUBSCRIBED, ++ PRI_REROUTING_RSP_NOT_AVAILABLE, ++ /*! Supplementary service interaction not allowed. */ ++ PRI_REROUTING_RSP_NOT_ALLOWED, ++ PRI_REROUTING_RSP_INVALID_NUMBER, ++ /*! Deflection to prohibited number (e.g., operator, police, emergency). */ ++ PRI_REROUTING_RSP_SPECIAL_SERVICE_NUMBER, ++ /*! Deflection to served user number. */ ++ PRI_REROUTING_RSP_DIVERSION_TO_SELF, ++ PRI_REROUTING_RSP_MAX_DIVERSIONS_EXCEEDED, ++ PRI_REROUTING_RSP_RESOURCE_UNAVAILABLE, ++}; ++ ++/*! ++ * \brief Send the CallRerouteing/CallDeflection response message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. ++ * \param invoke_id Value given by the initiating request. ++ * \param code The result to send. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int pri_rerouting_rsp(struct pri *ctrl, q931_call *call, int invoke_id, enum PRI_REROUTING_RSP_CODE code); ++ ++/*! ++ * \brief Set the call hold feature enable flag. ++ * ++ * \param ctrl D channel controller. ++ * \param enable TRUE to enable call hold feature. ++ * ++ * \return Nothing ++ */ ++void pri_hold_enable(struct pri *ctrl, int enable); ++ ++/*! ++ * \brief Send the HOLD message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int pri_hold(struct pri *ctrl, q931_call *call); ++ ++/*! ++ * \brief Send the HOLD ACKNOWLEDGE message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int pri_hold_ack(struct pri *ctrl, q931_call *call); ++ ++/*! ++ * \brief Send the HOLD REJECT message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg ++ * \param cause Q.931 cause code for rejecting the hold request. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause); ++ ++/*! ++ * \brief Send the RETRIEVE message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg ++ * \param channel Encoded channel id to use. If zero do not send channel id. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int pri_retrieve(struct pri *ctrl, q931_call *call, int channel); ++ ++/*! ++ * \brief Send the RETRIEVE ACKNOWLEDGE message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg ++ * \param channel Encoded channel id to use. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel); ++ ++/*! ++ * \brief Send the RETRIEVE REJECT message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg ++ * \param cause Q.931 cause code for rejecting the retrieve request. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause); ++ + /* Get/Set PRI Timers */ + #define PRI_GETSET_TIMERS + int pri_set_timer(struct pri *pri, int timer, int value); + int pri_get_timer(struct pri *pri, int timer); +-int pri_timer2idx(char *timer); ++int pri_timer2idx(const char *timer_name); + +-#define PRI_MAX_TIMERS 32 ++/*! New configurable timers and counters must be added to the end of the list */ ++enum PRI_TIMERS_AND_COUNTERS { ++ PRI_TIMER_N200, /*!< Maximum numer of Q.921 retransmissions */ ++ PRI_TIMER_N201, /*!< Maximum numer of octets in an information field */ ++ PRI_TIMER_N202, /*!< Maximum numer of transmissions of the TEI identity request message */ ++ PRI_TIMER_K, /*!< Maximum number of outstanding I-frames */ + +-#define PRI_TIMER_N200 0 /* Maximum numer of q921 retransmissions */ +-#define PRI_TIMER_N201 1 /* Maximum numer of octets in an information field */ +-#define PRI_TIMER_N202 2 /* Maximum numer of transmissions of the TEI identity request message */ +-#define PRI_TIMER_K 3 /* Maximum number of outstanding I-frames */ ++ PRI_TIMER_T200, /*!< Time between SABME's */ ++ PRI_TIMER_T201, /*!< Minimum time between retransmissions of the TEI Identity check messages */ ++ PRI_TIMER_T202, /*!< Minimum time between transmission of TEI Identity request messages */ ++ PRI_TIMER_T203, /*!< Maximum time without exchanging packets */ + +-#define PRI_TIMER_T200 4 /* time between SABME's */ +-#define PRI_TIMER_T201 5 /* minimum time between retransmissions of the TEI Identity check messages */ +-#define PRI_TIMER_T202 6 /* minimum time between transmission of TEI Identity request messages */ +-#define PRI_TIMER_T203 7 /* maxiumum time without exchanging packets */ ++ PRI_TIMER_T300, ++ PRI_TIMER_T301, /*!< Maximum time to respond to an ALERT */ ++ PRI_TIMER_T302, ++ PRI_TIMER_T303, /*!< Maximum time to wait after sending a SETUP without a response */ ++ PRI_TIMER_T304, ++ PRI_TIMER_T305, /*!< Wait for DISCONNECT acknowledge */ ++ PRI_TIMER_T306, ++ PRI_TIMER_T307, ++ PRI_TIMER_T308, /*!< Wait for RELEASE acknowledge */ ++ PRI_TIMER_T309, /*!< Time active calls can tollerate data link layer being down before clearing. */ ++ PRI_TIMER_T310, /*!< Maximum time between receiving a CALL_PROCEEDING and receiving a ALERT/CONNECT/DISCONNECT/PROGRESS */ ++ PRI_TIMER_T313, /*!< Wait for CONNECT acknowledge, CPE side only */ ++ PRI_TIMER_T314, ++ PRI_TIMER_T316, /*!< Maximum time between transmitting a RESTART and receiving a RESTART ACK */ ++ PRI_TIMER_T317, ++ PRI_TIMER_T318, ++ PRI_TIMER_T319, ++ PRI_TIMER_T320, ++ PRI_TIMER_T321, ++ PRI_TIMER_T322, + +-#define PRI_TIMER_T300 8 +-#define PRI_TIMER_T301 9 /* maximum time to respond to an ALERT */ +-#define PRI_TIMER_T302 10 +-#define PRI_TIMER_T303 11 /* maximum time to wait after sending a SETUP without a response */ +-#define PRI_TIMER_T304 12 +-#define PRI_TIMER_T305 13 +-#define PRI_TIMER_T306 14 +-#define PRI_TIMER_T307 15 +-#define PRI_TIMER_T308 16 +-#define PRI_TIMER_T309 17 +-#define PRI_TIMER_T310 18 /* maximum time between receiving a CALLPROCEEDING and receiving a ALERT/CONNECT/DISCONNECT/PROGRESS */ +-#define PRI_TIMER_T313 19 +-#define PRI_TIMER_T314 20 +-#define PRI_TIMER_T316 21 /* maximum time between transmitting a RESTART and receiving a RESTART ACK */ +-#define PRI_TIMER_T317 22 +-#define PRI_TIMER_T318 23 +-#define PRI_TIMER_T319 24 +-#define PRI_TIMER_T320 25 +-#define PRI_TIMER_T321 26 +-#define PRI_TIMER_T322 27 ++ PRI_TIMER_TM20, /*!< Maximum time awaiting XID response */ ++ PRI_TIMER_NM20, /*!< Number of XID retransmits */ + +-#define PRI_TIMER_TM20 28 /* maximum time avaiting XID response */ +-#define PRI_TIMER_NM20 29 /* number of XID retransmits */ ++ PRI_TIMER_T_HOLD, /*!< Maximum time to wait for HOLD request response. */ ++ PRI_TIMER_T_RETRIEVE, /*!< Maximum time to wait for RETRIEVE request response. */ + ++ PRI_TIMER_T_RESPONSE, /*!< Maximum time to wait for a typical APDU response. */ ++ ++ /* Must be last in the enum list */ ++ PRI_MAX_TIMERS ++}; ++ + /* Get PRI version */ + const char *pri_get_version(void); + +Index: asn1_primitive.c +=================================================================== +--- a/asn1_primitive.c (.../tags/1.4.10.2) (revision 0) ++++ b/asn1_primitive.c (.../branches/1.4) (revision 1357) +@@ -0,0 +1,1306 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief ASN.1 BER encode/decode primitives ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++ ++#include <stdio.h> ++#include <ctype.h> ++ ++#include "compat.h" ++#include "libpri.h" ++#include "pri_internal.h" ++#include "asn1.h" ++ ++/* ------------------------------------------------------------------- */ ++ ++/*! ++ * \internal ++ * \brief Dump the memory contents indicated in printable characters. (Helper function.) ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param start Dump memory starting position. ++ * \param end Dump memory ending position. (Not included in dump.) ++ * ++ * \return Nothing ++ */ ++static void asn1_dump_mem_helper(struct pri *ctrl, const unsigned char *start, ++ const unsigned char *end) ++{ ++ pri_message(ctrl, " - \""); ++ for (; start < end; ++start) { ++ pri_message(ctrl, "%c", (isprint(*start)) ? *start : '~'); ++ } ++ pri_message(ctrl, "\"\n"); ++} ++ ++/*! ++ * \internal ++ * \brief Dump the memory contents indicated. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param indent Number of spaces to indent for each new memory dump line. ++ * \param pos Dump memory starting position. ++ * \param length Number of bytes to dump. ++ * ++ * \return Nothing ++ */ ++static void asn1_dump_mem(struct pri *ctrl, unsigned indent, const unsigned char *pos, ++ unsigned length) ++{ ++ const unsigned char *seg_start; ++ const unsigned char *end; ++ unsigned delimiter; ++ unsigned count; ++ ++ seg_start = pos; ++ end = pos + length; ++ if (pos < end) { ++ delimiter = '<'; ++ for (;;) { ++ pri_message(ctrl, "%*s", indent, ""); ++ for (count = 0; count++ < 16 && pos < end;) { ++ pri_message(ctrl, "%c%02X", delimiter, *pos++); ++ delimiter = (count == 8) ? '-' : ' '; ++ } ++ if (end <= pos) { ++ break; ++ } ++ asn1_dump_mem_helper(ctrl, seg_start, pos); ++ seg_start = pos; ++ } ++ } else { ++ pri_message(ctrl, "%*s<", indent, ""); ++ } ++ pri_message(ctrl, ">"); ++ asn1_dump_mem_helper(ctrl, seg_start, end); ++} ++ ++/*! ++ * \brief Convert the given tag value to a descriptive string. ++ * ++ * \param tag Component tag value to convert to a string. ++ * ++ * \return Converted tag string. ++ */ ++const char *asn1_tag2str(unsigned tag) ++{ ++ static const char *primitives[32] = { ++ [ASN1_TYPE_INDEF_TERM] = "Indefinite length terminator", ++ [ASN1_TYPE_BOOLEAN] = "Boolean", ++ [ASN1_TYPE_INTEGER] = "Integer", ++ [ASN1_TYPE_BIT_STRING] = "Bit String", ++ [ASN1_TYPE_OCTET_STRING] = "Octet String", ++ [ASN1_TYPE_NULL] = "NULL", ++ [ASN1_TYPE_OBJECT_IDENTIFIER] = "OID", ++ [ASN1_TYPE_OBJECT_DESCRIPTOR] = "Object Descriptor", ++ [ASN1_TYPE_EXTERN] = "External", ++ [ASN1_TYPE_REAL] = "Real", ++ [ASN1_TYPE_ENUMERATED] = "Enumerated", ++ [ASN1_TYPE_EMBEDDED_PDV] = "Embedded PDV", ++ [ASN1_TYPE_UTF8_STRING] = "UTF8 String", ++ [ASN1_TYPE_RELATIVE_OID] = "Relative OID", ++ [ASN1_TYPE_SEQUENCE] = "Sequence", ++ [ASN1_TYPE_SET] = "Set", ++ [ASN1_TYPE_NUMERIC_STRING] = "Numeric String", ++ [ASN1_TYPE_PRINTABLE_STRING] = "Printable String", ++ [ASN1_TYPE_TELETEX_STRING] = "Teletex String", ++ [ASN1_TYPE_VIDEOTEX_STRING] = "Videotex String", ++ [ASN1_TYPE_IA5_STRING] = "IA5 String", ++ [ASN1_TYPE_UTC_TIME] = "UTC Time", ++ [ASN1_TYPE_GENERALIZED_TIME] = "Generalized Time", ++ [ASN1_TYPE_GRAPHIC_STRING] = "Graphic String", ++ [ASN1_TYPE_VISIBLE_STRING] = "Visible/ISO646 String", ++ [ASN1_TYPE_GENERAL_STRING] = "General String", ++ [ASN1_TYPE_UNIVERSAL_STRING] = "Universal String", ++ [ASN1_TYPE_CHAR_STRING] = "Character String", ++ [ASN1_TYPE_BMP_STRING] = "BMP String", ++ [ASN1_TYPE_EXTENSION] = "Type Extension", ++ }; ++ static char buf[64]; ++ const char *description; ++ unsigned asn1_constructed; /*! TRUE if the tag is constructed. */ ++ unsigned asn1_type; ++ ++ asn1_constructed = ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED); ++ asn1_type = tag & ASN1_TYPE_MASK; ++ ++ switch (tag & ASN1_CLASS_MASK) { ++ case ASN1_CLASS_UNIVERSAL: ++ if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_INDEF_TERM)) { ++ description = NULL; ++ } else { ++ description = primitives[asn1_type]; ++ } ++ if (!description) { ++ description = "Reserved"; ++ } ++ snprintf(buf, sizeof(buf), "%s%s(%u 0x%02X)", description, ++ asn1_constructed ? "/C" : "", tag, tag); ++ return buf; ++ case ASN1_CLASS_APPLICATION: ++ description = "Application"; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC: ++ description = "Context Specific"; ++ break; ++ case ASN1_CLASS_PRIVATE: ++ description = "Private"; ++ break; ++ default: ++ snprintf(buf, sizeof(buf), "Unknown tag (%u 0x%02X)", tag, tag); ++ return buf; ++ } ++ snprintf(buf, sizeof(buf), "%s%s [%u 0x%02X]", description, ++ asn1_constructed ? "/C" : "", asn1_type, asn1_type); ++ return buf; ++} ++ ++/*! ++ * \brief Decode the ASN.1 tag value. ++ * ++ * \param tag_pos ASN.1 tag starting position. ++ * \param end End of ASN.1 encoded data buffer. ++ * \param tag Decoded tag value returned on success. ++ * ++ * \retval Next octet after the tag on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *asn1_dec_tag(const unsigned char *tag_pos, const unsigned char *end, ++ unsigned *tag) ++{ ++ unsigned extended_tag; ++ ++ if (end <= tag_pos) { ++ return NULL; ++ } ++ *tag = *tag_pos++; ++ if ((*tag & ASN1_TYPE_MASK) == ASN1_TYPE_EXTENSION) { ++ /* Extract the extended tag value */ ++ extended_tag = 0; ++ do { ++ if (end <= tag_pos) { ++ return NULL; ++ } ++ extended_tag <<= 7; ++ extended_tag |= *tag_pos & ~0x80; ++ } while (*tag_pos++ & 0x80); ++ if (extended_tag && extended_tag < ASN1_TYPE_EXTENSION) { ++ /* ++ * The sender did not need to use the extended format. ++ * This is an encoding error on their part, but we will ++ * accept it anyway. ++ * ++ * Note we cannot return a null tag value from this path. ++ * We would misinterpret the indefinite length ++ * terminator. ++ */ ++ *tag &= ~ASN1_TYPE_MASK; ++ *tag |= extended_tag; ++ } ++ } ++ ++ return tag_pos; ++} ++ ++/*! ++ * \brief Decode the length of an ASN.1 component length. ++ * ++ * \param len_pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param length Decoded length value returned on success. (-1 if indefinite) ++ * ++ * \retval Next octet after the length on success. ++ * \retval NULL on error. ++ * ++ * \note The decoded length is checked to see if there is enough buffer ++ * left for the component body. ++ */ ++const unsigned char *asn1_dec_length(const unsigned char *len_pos, ++ const unsigned char *end, int *length) ++{ ++ unsigned length_size; ++ ++ if (end <= len_pos) { ++ /* Not enough buffer to determine how the length is encoded */ ++ return NULL; ++ } ++ ++ if (*len_pos < 0x80) { ++ /* Short length encoding */ ++ *length = *len_pos++; ++ } else if (*len_pos == 0x80) { ++ /* Indefinite length encoding */ ++ *length = -1; ++ ++len_pos; ++ if (end < len_pos + ASN1_INDEF_TERM_LEN) { ++ /* Not enough buffer for the indefinite length terminator */ ++ return NULL; ++ } ++ return len_pos; ++ } else { ++ /* Long length encoding */ ++ length_size = *len_pos++ & 0x7f; ++ if (length_size == 0x7f) { ++ /* Reserved extension encoding that has not been defined. */ ++ return NULL; ++ } ++ if (end < len_pos + length_size) { ++ /* Not enough buffer for the length value */ ++ return NULL; ++ } ++ *length = 0; ++ while (length_size--) { ++ *length = (*length << 8) | *len_pos++; ++ } ++ } ++ ++ if (end < len_pos + *length) { ++ /* Not enough buffer for the component body. */ ++ return NULL; ++ } ++ return len_pos; ++} ++ ++/*! ++ * \internal ++ * \brief Skip to the end of an indefinite length constructed component helper. ++ * ++ * \param pos ASN.1 tag starting position. ++ * \param end End of ASN.1 decoding data buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *asn1_dec_indef_end_fixup_helper(const unsigned char *pos, ++ const unsigned char *end) ++{ ++ unsigned tag; ++ int length; ++ ++ while (pos < end && *pos != ASN1_INDEF_TERM) { ++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag)); ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ if (length < 0) { ++ /* Skip over indefinite length sub-component */ ++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED ++ || tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET) ++ || tag == ++ (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) { ++ /* This is an ITU encoded indefinite length component. */ ++ ASN1_CALL(pos, asn1_dec_indef_end_fixup_helper(pos, end)); ++ } else { ++ /* This is a non-ITU encoded indefinite length component. */ ++ while (pos < end && *pos != ASN1_INDEF_TERM) { ++ ++pos; ++ } ++ pos += ASN1_INDEF_TERM_LEN; ++ } ++ } else { ++ /* Skip over defininte length sub-component */ ++ pos += length; ++ } ++ } ++ if (end < pos + ASN1_INDEF_TERM_LEN) { ++ return NULL; ++ } ++ ++ return pos + ASN1_INDEF_TERM_LEN; ++} ++ ++/*! ++ * \brief Skip to the end of an indefinite length constructed component. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param pos ASN.1 tag starting position. ++ * \param end End of ASN.1 decoding data buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *asn1_dec_indef_end_fixup(struct pri *ctrl, const unsigned char *pos, ++ const unsigned char *end) ++{ ++ if (pos < end && *pos != ASN1_INDEF_TERM && (ctrl->debug & PRI_DEBUG_APDU)) { ++ pri_message(ctrl, ++ " Skipping unused indefinite length constructed component octets!\n"); ++ } ++ return asn1_dec_indef_end_fixup_helper(pos, end); ++} ++ ++/*! ++ * \brief Decode the boolean primitive. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this primitive. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param value Decoded boolean value. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *asn1_dec_boolean(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, int32_t *value) ++{ ++ int length; ++ ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ if (length != 1) { ++ /* ++ * The encoding rules say the length can only be one. ++ * It is rediculus to get anything else anyway. ++ */ ++ return NULL; ++ } ++ ++ *value = *pos++ ? 1 : 0; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s %s = %d\n", name, asn1_tag2str(tag), *value); ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the integer type primitive. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this primitive. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param value Decoded integer type value. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *asn1_dec_int(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, int32_t *value) ++{ ++ int length; ++ ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ if (length <= 0) { ++ /* ++ * The encoding rules say the length can not be indefinite. ++ * It cannot be empty for that matter either. ++ */ ++ return NULL; ++ } ++ ++#if 1 ++ /* Read value as signed */ ++ if (*pos & 0x80) { ++ /* The value is negative */ ++ *value = -1; ++ } else { ++ *value = 0; ++ } ++#else ++ /* Read value as unsigned */ ++ *value = 0; ++#endif ++ while (length--) { ++ *value = (*value << 8) | *pos; ++ pos++; ++ } ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s %s = %d 0x%04X\n", name, asn1_tag2str(tag), *value, ++ *value); ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the null primitive. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this primitive. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *asn1_dec_null(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end) ++{ ++ int length; ++ ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ if (length != 0) { ++ /* ++ * The encoding rules say the length can only be zero. ++ * It is rediculus to get anything else anyway. ++ */ ++ return NULL; ++ } ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s %s\n", name, asn1_tag2str(tag)); ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the object identifier primitive. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this primitive. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param oid Decoded OID type value. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *asn1_dec_oid(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, struct asn1_oid *oid) ++{ ++ int length; ++ unsigned num_values; ++ unsigned value; ++ unsigned delimiter; ++ ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ if (length < 0) { ++ /* ++ * The encoding rules say the length can not be indefinite. ++ */ ++ return NULL; ++ } ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s %s =", name, asn1_tag2str(tag)); ++ } ++ delimiter = ' '; ++ num_values = 0; ++ while (length) { ++ value = 0; ++ for (;;) { ++ --length; ++ value = (value << 7) | (*pos & 0x7F); ++ if (!(*pos++ & 0x80)) { ++ /* Last octet in the OID subidentifier value */ ++ if (num_values < ARRAY_LEN(oid->value)) { ++ oid->value[num_values] = value; ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "%c%u", delimiter, value); ++ } ++ delimiter = '.'; ++ } else { ++ /* Too many OID subidentifier values */ ++ delimiter = '~'; ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "%c%u", delimiter, value); ++ } ++ } ++ ++num_values; ++ break; ++ } ++ if (!length) { ++ oid->num_values = 0; ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "\n" ++ " Last OID subidentifier value not terminated!\n"); ++ } ++ return NULL; ++ } ++ } ++ } ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "\n"); ++ } ++ ++ if (num_values <= ARRAY_LEN(oid->value)) { ++ oid->num_values = num_values; ++ return pos; ++ } else { ++ /* Need to increase the size of the OID subidentifier list. */ ++ oid->num_values = 0; ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Too many OID values!\n"); ++ } ++ return NULL; ++ } ++} ++ ++/*! ++ * \brief Decode a binary string primitive. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this primitive. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param buf_size Size of the supplied string buffer. (Must be nonzero) ++ * \param str Where to put the decoded string. ++ * \param str_len Length of the decoded string. ++ * ++ * \note The string will be null terminated just in case. ++ * The buffer needs to have enough room for a null terminator. ++ * \note The parse will fail if the parsed string is too large for ++ * the supplied buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *asn1_dec_string_bin(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size, ++ unsigned char *str, size_t *str_len) ++{ ++ int length; ++ size_t sub_buf_size; ++ size_t sub_str_len; ++ unsigned char *sub_str; ++ ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ if (length < 0) { ++ /* This is an indefinite length string */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s %s = Indefinite length string\n", name, ++ asn1_tag2str(tag)); ++ } ++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) { ++ /* ++ * This is an ITU encoded indefinite length string ++ * and could contain null. ++ */ ++ ++ /* Ensure that an empty string is null terminated. */ ++ *str = 0; ++ ++ /* Collect all substrings into the original string buffer. */ ++ *str_len = 0; ++ sub_str = str; ++ sub_buf_size = buf_size; ++ for (;;) { ++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag)); ++ if (tag == ASN1_INDEF_TERM) { ++ /* End-of-contents octets */ ++ break; ++ } ++ ++ /* Append the substring to the accumulated indefinite string. */ ++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end, ++ sub_buf_size, sub_str, &sub_str_len)); ++ ++ sub_buf_size -= sub_str_len; ++ sub_str += sub_str_len; ++ *str_len += sub_str_len; ++ } ++ } else { ++ /* ++ * This is a non-ITU encoded indefinite length string ++ * and must not contain null's. ++ */ ++ for (length = 0;; ++length) { ++ if (end <= pos + length) { ++ /* Not enough buffer left */ ++ return NULL; ++ } ++ if (pos[length] == 0) { ++ /* Found End-of-contents octets */ ++ break; ++ } ++ } ++ ++ if (buf_size - 1 < length) { ++ /* The destination buffer is not large enough for the data */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " String buffer not large enough!\n"); ++ } ++ return NULL; ++ } ++ ++ /* Extract the string and null terminate it. */ ++ memcpy(str, pos, length); ++ str[length] = 0; ++ *str_len = length; ++ ++ pos += length + 1; ++ } ++ if (end <= pos) { ++ /* Not enough buffer left for End-of-contents octets */ ++ return NULL; ++ } ++ if (*pos++ != 0) { ++ /* We actually did not find the End-of-contents octets. */ ++ return NULL; ++ } ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ /* Dump the collected string buffer contents. */ ++ pri_message(ctrl, " Completed string =\n"); ++ asn1_dump_mem(ctrl, 6, str, *str_len); ++ } ++ } else { ++ /* This is a definite length string */ ++ if (buf_size - 1 < length) { ++ /* The destination buffer is not large enough for the data */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s %s = Buffer not large enough!\n", name, ++ asn1_tag2str(tag)); ++ } ++ return NULL; ++ } ++ ++ /* Extract the string and null terminate it. */ ++ memcpy(str, pos, length); ++ str[length] = 0; ++ *str_len = length; ++ ++ pos += length; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ /* Dump the collected string buffer contents. */ ++ pri_message(ctrl, " %s %s =\n", name, asn1_tag2str(tag)); ++ asn1_dump_mem(ctrl, 4, str, *str_len); ++ } ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode a string that can be truncated to a maximum length primitive. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this primitive. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param buf_size Size of the supplied string buffer. (Must be nonzero) ++ * \param str Where to put the decoded null terminated string. ++ * \param str_len Length of the decoded string. ++ * (computed for convenience since you could just do a strlen()) ++ * ++ * \note The parsed string will be truncated if the string buffer ++ * cannot contain it. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *asn1_dec_string_max(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size, ++ unsigned char *str, size_t *str_len) ++{ ++ int length; ++ size_t str_length; ++ size_t sub_buf_size; ++ size_t sub_str_len; ++ unsigned char *sub_str; ++ ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ if (length < 0) { ++ /* This is an indefinite length string */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s %s = Indefinite length string\n", name, ++ asn1_tag2str(tag)); ++ } ++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) { ++ /* This is an ITU encoded indefinite length string. */ ++ ++ /* Ensure that an empty string is null terminated. */ ++ *str = 0; ++ ++ /* Collect all substrings into the original string buffer. */ ++ *str_len = 0; ++ sub_str = str; ++ sub_buf_size = buf_size; ++ for (;;) { ++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag)); ++ if (tag == ASN1_INDEF_TERM) { ++ /* End-of-contents octets */ ++ break; ++ } ++ ++ /* Append the substring to the accumulated indefinite string. */ ++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, name, tag, pos, end, ++ sub_buf_size, sub_str, &sub_str_len)); ++ ++ sub_buf_size -= sub_str_len; ++ sub_str += sub_str_len; ++ *str_len += sub_str_len; ++ } ++ } else { ++ /* This is a non-ITU encoded indefinite length string. */ ++ for (length = 0;; ++length) { ++ if (end <= pos + length) { ++ /* Not enough buffer left */ ++ return NULL; ++ } ++ if (pos[length] == 0) { ++ /* Found End-of-contents octets */ ++ break; ++ } ++ } ++ ++ /* Extract the string, truncate if necessary, and terminate it. */ ++ str_length = (buf_size - 1 < length) ? buf_size - 1 : length; ++ memcpy(str, pos, str_length); ++ str[str_length] = 0; ++ *str_len = str_length; ++ ++ pos += length + 1; ++ } ++ if (end <= pos) { ++ /* Not enough buffer left for End-of-contents octets */ ++ return NULL; ++ } ++ if (*pos++ != 0) { ++ /* We actually did not find the End-of-contents octets. */ ++ return NULL; ++ } ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Completed string = \"%s\"\n", str); ++ } ++ } else { ++ /* ++ * This is a definite length string ++ * ++ * Extract the string, truncate if necessary, and terminate it. ++ */ ++ str_length = (buf_size - 1 < length) ? buf_size - 1 : length; ++ memcpy(str, pos, str_length); ++ str[str_length] = 0; ++ *str_len = str_length; ++ ++ pos += length; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s %s = \"%s\"\n", name, asn1_tag2str(tag), str); ++ } ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Recursive ASN.1 buffer decoding dump helper. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param pos ASN.1 tag starting position. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param level Indentation level to use. ++ * \param indefinite_term TRUE if to stop on an indefinite length terminator. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *asn1_dump_helper(struct pri *ctrl, const unsigned char *pos, ++ const unsigned char *end, unsigned level, unsigned indefinite_term) ++{ ++ unsigned delimiter; ++ unsigned tag; ++ int length; ++ const unsigned char *len_pos; ++ ++ while (pos < end && (!indefinite_term || *pos != ASN1_INDEF_TERM)) { ++ /* Decode the tag */ ++ pri_message(ctrl, "%*s", 2 * level, ""); ++ len_pos = asn1_dec_tag(pos, end, &tag); ++ if (!len_pos) { ++ pri_message(ctrl, "Invalid tag encoding!\n"); ++ return NULL; ++ } ++ ++ /* Dump the tag contents. */ ++ pri_message(ctrl, "%s ", asn1_tag2str(tag)); ++ delimiter = '<'; ++ while (pos < len_pos) { ++ pri_message(ctrl, "%c%02X", delimiter, *pos); ++ delimiter = ' '; ++ ++pos; ++ } ++ pri_message(ctrl, "> "); ++ ++ /* Decode the length */ ++ pos = asn1_dec_length(len_pos, end, &length); ++ if (!pos) { ++ pri_message(ctrl, "Invalid length encoding!\n"); ++ return NULL; ++ } ++ ++ /* Dump the length contents. */ ++ if (length < 0) { ++ pri_message(ctrl, "Indefinite length "); ++ } else { ++ pri_message(ctrl, "Len:%d ", length); ++ } ++ delimiter = '<'; ++ while (len_pos < pos) { ++ pri_message(ctrl, "%c%02X", delimiter, *len_pos); ++ delimiter = ' '; ++ ++len_pos; ++ } ++ pri_message(ctrl, ">\n"); ++ ++ /* Dump the body contents */ ++ ++level; ++ if (length < 0) { ++ /* Indefinite length */ ++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) { ++ /* This is an ITU encoded indefinite length component. */ ++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, end, level, 1)); ++ } else if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET) ++ || tag == ++ (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) { ++ pri_message(ctrl, "%*sThis tag must always be constructed!\n", 2 * level, ++ ""); ++ /* Assume tag was constructed to keep going */ ++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, end, level, 1)); ++ } else { ++ /* This is a non-ITU encoded indefinite length component. */ ++ pri_message(ctrl, "%*sNon-ITU indefininte length component.\n", ++ 2 * level, ""); ++ length = 0; ++ while (pos + length < end && pos[length] != ASN1_INDEF_TERM) { ++ ++length; ++ } ++ if (length) { ++ asn1_dump_mem(ctrl, 2 * level, pos, length); ++ pos += length; ++ } ++ } ++ --level; ++ if (end < pos + ASN1_INDEF_TERM_LEN) { ++ pri_message(ctrl, "%*sNot enough room for the End-of-contents octets!\n", ++ 2 * level, ""); ++ pos = end; ++ } else { ++ pri_message(ctrl, "%*sEnd-of-contents <%02X %02X>%s\n", 2 * level, "", ++ pos[0], pos[1], (pos[1] != 0) ? " Invalid!" : ""); ++ pos += ASN1_INDEF_TERM_LEN; ++ } ++ } else { ++ /* Defininte length */ ++ if ((tag & ASN1_PC_MASK) == ASN1_PC_CONSTRUCTED) { ++ /* Dump constructed contents */ ++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, pos + length, level, 0)); ++ } else if (tag == (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SET) ++ || tag == ++ (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_SEQUENCE)) { ++ /* Assume tag was constructed to keep going */ ++ pri_message(ctrl, "%*sThis tag must always be constructed!\n", 2 * level, ++ ""); ++ ASN1_CALL(pos, asn1_dump_helper(ctrl, pos, pos + length, level, 0)); ++ } else if (0 < length) { ++ /* Dump primitive contents. */ ++ asn1_dump_mem(ctrl, 2 * level, pos, length); ++ pos += length; ++ } ++ --level; ++ } ++ ++#if 0 ++ pri_message(ctrl, "%*sEnd\n", 2 * level, ""); ++#endif ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Dump the given ASN.1 buffer contents. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param start_asn1 First octet in the ASN.1 buffer. (ASN.1 tag starting position) ++ * \param end One beyond the last octet in the ASN.1 buffer. ++ * ++ * \return Nothing ++ */ ++void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1, ++ const unsigned char *end) ++{ ++ pri_message(ctrl, "ASN.1 dump\n"); ++ if (start_asn1) { ++ asn1_dump_helper(ctrl, start_asn1, end, 1, 0); ++ } ++ pri_message(ctrl, "ASN.1 end\n"); ++} ++ ++/*! ++ * \brief Encode the length of an ASN.1 component body of predetermined size. ++ * ++ * \param len_pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param length Predetermined component body length. ++ * ++ * \note The encoding buffer does not need to be checked after calling. ++ * It is already checked to have the requested room. ++ * ++ * \retval Next octet after the length on success. ++ * \retval NULL on error. ++ */ ++unsigned char *asn1_enc_length(unsigned char *len_pos, unsigned char *end, size_t length) ++{ ++ u_int32_t body_length; /* Length of component contents */ ++ u_int32_t value; ++ u_int32_t test_mask; ++ unsigned length_size; /* Length of the length encoding */ ++ ++ body_length = length; ++ ++ /* Determine length encoding length */ ++ if (body_length < 128) { ++ length_size = 1; ++ } else { ++ /* Find most significant octet of 32 bit integer that carries meaning. */ ++ test_mask = 0xFF000000; ++ for (length_size = 4; --length_size;) { ++ if (body_length & test_mask) { ++ /* ++ * Found the first 8 bits of a multiple octet length that ++ * is not all zeroes. ++ */ ++ break; ++ } ++ test_mask >>= 8; ++ } ++ length_size += 1 + 1; ++ } ++ ++ if (end < len_pos + length_size + body_length) { ++ /* No room for the length and component body in the buffer */ ++ return NULL; ++ } ++ ++ /* Encode the component body length */ ++ if (length_size == 1) { ++ *len_pos++ = body_length; ++ } else { ++ *len_pos++ = 0x80 | --length_size; ++ while (length_size--) { ++ value = body_length; ++ value >>= (8 * length_size); ++ *len_pos++ = value & 0xFF; ++ } ++ } ++ ++ return len_pos; ++} ++ ++/*! ++ * \brief Encode the length of an already encoded ASN.1 component. ++ * ++ * \param len_pos Starting position of the ASN.1 component length. ++ * \param component_end Next octet after the component body. ++ * \param end End of ASN.1 encoding data buffer. ++ * ++ * \note The total component size could increase or decrease. ++ * \note The component length field must have been initialized with ++ * ASN1_LEN_INIT() or ASN1_CONSTRUCTED_BEGIN(). ++ * ++ * \retval Next octet after the component body on success. ++ * \retval NULL on error. ++ */ ++unsigned char *asn1_enc_length_fixup(unsigned char *len_pos, ++ unsigned char *component_end, unsigned char *end) ++{ ++ u_int32_t body_length; /* Length of component contents */ ++ u_int32_t value; ++ u_int32_t test_mask; ++ unsigned length_size; /* Length of the length encoding */ ++ ++ if (component_end < len_pos + *len_pos) { ++ /* Sanity check */ ++ return NULL; ++ } ++ ++ body_length = component_end - len_pos - *len_pos; ++ ++ /* Determine length encoding length */ ++ if (body_length < 128) { ++ length_size = 1; ++ } else { ++ /* Find most significant octet of 32 bit integer that carries meaning. */ ++ test_mask = 0xFF000000; ++ for (length_size = 4; --length_size;) { ++ if (body_length & test_mask) { ++ /* ++ * Found the first 8 bits of a multiple octet length that ++ * is not all zeroes. ++ */ ++ break; ++ } ++ test_mask >>= 8; ++ } ++ length_size += 1 + 1; ++ } ++ ++ component_end = len_pos + length_size + body_length; ++ if (end < component_end) { ++ /* No room for the component in the buffer */ ++ return NULL; ++ } ++ if (length_size != *len_pos) { ++ /* Must shift the component body */ ++ memmove(len_pos + length_size, len_pos + *len_pos, body_length); ++ } ++ ++ /* Encode the component body length */ ++ if (length_size == 1) { ++ *len_pos = body_length; ++ } else { ++ *len_pos++ = 0x80 | --length_size; ++ while (length_size--) { ++ value = body_length; ++ value >>= (8 * length_size); ++ *len_pos++ = value & 0xFF; ++ } ++ } ++ ++ return component_end; ++} ++ ++/*! ++ * \brief Encode the boolean primitive. ++ * ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * \param value Component value to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *asn1_enc_boolean(unsigned char *pos, unsigned char *end, unsigned tag, ++ int32_t value) ++{ ++ if (end < pos + 3) { ++ /* No room for the component in the buffer */ ++ return NULL; ++ } ++ ++ /* Encode component */ ++ *pos++ = tag; ++ *pos++ = 1; ++ *pos++ = value ? 1 : 0; ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the integer type primitive. ++ * ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * \param value Component value to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *asn1_enc_int(unsigned char *pos, unsigned char *end, unsigned tag, ++ int32_t value) ++{ ++ unsigned count; ++ u_int32_t test_mask; ++ u_int32_t val; ++ ++ /* Find most significant octet of 32 bit integer that carries meaning. */ ++ test_mask = 0xFF800000; ++ val = (u_int32_t) value; ++ for (count = 4; --count;) { ++ if ((val & test_mask) != test_mask && (val & test_mask) != 0) { ++ /* ++ * The first 9 bits of a multiple octet integer is not ++ * all ones or zeroes. ++ */ ++ break; ++ } ++ test_mask >>= 8; ++ } ++ ++ if (end < pos + 3 + count) { ++ /* No room for the component in the buffer */ ++ return NULL; ++ } ++ ++ /* Encode component */ ++ *pos++ = tag; ++ *pos++ = count + 1; ++ do { ++ val = (u_int32_t) value; ++ val >>= (8 * count); ++ *pos++ = val & 0xFF; ++ } while (count--); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the null type primitive. ++ * ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *asn1_enc_null(unsigned char *pos, unsigned char *end, unsigned tag) ++{ ++ if (end < pos + 2) { ++ /* No room for the component in the buffer */ ++ return NULL; ++ } ++ ++ /* Encode component */ ++ *pos++ = tag; ++ *pos++ = 0; ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the object identifier (OID) primitive. ++ * ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * \param oid Component value to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *asn1_enc_oid(unsigned char *pos, unsigned char *end, unsigned tag, ++ const struct asn1_oid *oid) ++{ ++ unsigned char *len_pos; ++ unsigned num_values; ++ unsigned count; ++ u_int32_t value; ++ ++ if (end < pos + 2) { ++ /* No room for the component tag and length in the buffer */ ++ return NULL; ++ } ++ ++ *pos++ = tag; ++ len_pos = pos++; ++ ++ /* For all OID subidentifer values */ ++ for (num_values = 0; num_values < oid->num_values; ++num_values) { ++ /* ++ * Count the number of 7 bit chunks that are needed ++ * to encode the integer. ++ */ ++ value = oid->value[num_values] >> 7; ++ for (count = 0; value; ++count) { ++ /* There are bits still set */ ++ value >>= 7; ++ } ++ ++ if (end < pos + count + 1) { ++ /* No room for the component body in the buffer */ ++ return NULL; ++ } ++ ++ /* Store OID subidentifier value */ ++ do { ++ value = oid->value[num_values]; ++ value >>= (7 * count); ++ *pos++ = (value & 0x7F) | (count ? 0x80 : 0); ++ } while (count--); ++ } ++ ++ /* length */ ++ *len_pos = pos - len_pos - 1; ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the binary string type primitive. ++ * ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * \param str Binary string to encode. ++ * \param str_len Length of binary string to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *asn1_enc_string_bin(unsigned char *pos, unsigned char *end, unsigned tag, ++ const unsigned char *str, size_t str_len) ++{ ++ if (end < pos + 1) { ++ /* No room for the component tag in the buffer */ ++ return NULL; ++ } ++ ++ /* Encode component */ ++ *pos++ = tag; ++ ASN1_CALL(pos, asn1_enc_length(pos, end, str_len)); ++ memcpy(pos, str, str_len); ++ ++ return pos + str_len; ++} ++ ++/*! ++ * \brief Encode a string that can be truncated to a maximum length primitive. ++ * ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * \param str Null terminated string to encode. ++ * \param max_len Maximum length of string to encode. ++ * ++ * \note The string will be truncated if it is too long. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *asn1_enc_string_max(unsigned char *pos, unsigned char *end, unsigned tag, ++ const unsigned char *str, size_t max_len) ++{ ++ size_t str_len; ++ ++ str_len = strlen((char *) str); ++ if (max_len < str_len) { ++ str_len = max_len; ++ } ++ return asn1_enc_string_bin(pos, end, tag, str, str_len); ++} ++ ++/* ------------------------------------------------------------------- */ ++/* end asn1_primitive.c */ + +Property changes on: asn1_primitive.c +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: pri.c +=================================================================== +--- a/pri.c (.../tags/1.4.10.2) (revision 1357) ++++ b/pri.c (.../branches/1.4) (revision 1357) +@@ -42,8 +42,56 @@ + #include "pri_facility.h" + #include "pri_q921.h" + #include "pri_q931.h" +-#include "pri_timers.h" + ++#define PRI_BIT(a_bit) (1UL << (a_bit)) ++#define PRI_ALL_SWITCHES 0xFFFFFFFF ++ ++struct pri_timer_table { ++ const char *name; ++ enum PRI_TIMERS_AND_COUNTERS number; ++ unsigned long used_by; ++}; ++ ++/*! ++ * \note Sort the timer table entries in the order of the timer name so ++ * pri_dump_info_str() can display them in a consitent order. ++ */ ++static const struct pri_timer_table pri_timer[] = { ++/* *INDENT-OFF* */ ++ /* timer name timer number used by switches */ ++ { "N200", PRI_TIMER_N200, PRI_ALL_SWITCHES }, ++ { "N201", PRI_TIMER_N201, PRI_ALL_SWITCHES }, ++ { "N202", PRI_TIMER_N202, PRI_ALL_SWITCHES }, ++ { "K", PRI_TIMER_K, PRI_ALL_SWITCHES }, ++ { "T200", PRI_TIMER_T200, PRI_ALL_SWITCHES }, ++ { "T202", PRI_TIMER_T202, PRI_ALL_SWITCHES }, ++ { "T203", PRI_TIMER_T203, PRI_ALL_SWITCHES }, ++ { "T300", PRI_TIMER_T300, PRI_ALL_SWITCHES }, ++ { "T301", PRI_TIMER_T301, PRI_ALL_SWITCHES }, ++ { "T302", PRI_TIMER_T302, PRI_ALL_SWITCHES }, ++ { "T303", PRI_TIMER_T303, PRI_ALL_SWITCHES }, ++ { "T304", PRI_TIMER_T304, PRI_ALL_SWITCHES }, ++ { "T305", PRI_TIMER_T305, PRI_ALL_SWITCHES }, ++ { "T306", PRI_TIMER_T306, PRI_ALL_SWITCHES }, ++ { "T307", PRI_TIMER_T307, PRI_ALL_SWITCHES }, ++ { "T308", PRI_TIMER_T308, PRI_ALL_SWITCHES }, ++ { "T309", PRI_TIMER_T309, PRI_ALL_SWITCHES }, ++ { "T310", PRI_TIMER_T310, PRI_ALL_SWITCHES }, ++ { "T313", PRI_TIMER_T313, PRI_ALL_SWITCHES }, ++ { "T314", PRI_TIMER_T314, PRI_ALL_SWITCHES }, ++ { "T316", PRI_TIMER_T316, PRI_ALL_SWITCHES }, ++ { "T317", PRI_TIMER_T317, PRI_ALL_SWITCHES }, ++ { "T318", PRI_TIMER_T318, PRI_ALL_SWITCHES }, ++ { "T319", PRI_TIMER_T319, PRI_ALL_SWITCHES }, ++ { "T320", PRI_TIMER_T320, PRI_ALL_SWITCHES }, ++ { "T321", PRI_TIMER_T321, PRI_ALL_SWITCHES }, ++ { "T322", PRI_TIMER_T322, PRI_ALL_SWITCHES }, ++ { "T-HOLD", PRI_TIMER_T_HOLD, PRI_ALL_SWITCHES }, ++ { "T-RETRIEVE", PRI_TIMER_T_RETRIEVE, PRI_ALL_SWITCHES }, ++ { "T-RESPONSE", PRI_TIMER_T_RESPONSE, PRI_ALL_SWITCHES }, ++/* *INDENT-ON* */ ++}; ++ + char *pri_node2str(int node) + { + switch(node) { +@@ -84,14 +132,39 @@ + } + } + +-static void pri_default_timers(struct pri *pri, int switchtype) ++static void pri_default_timers(struct pri *ctrl, int switchtype) + { +- static const int defaulttimers[20][PRI_MAX_TIMERS] = PRI_TIMERS_ALL; +- int x; ++ unsigned idx; + +- for (x = 0; x<PRI_MAX_TIMERS; x++) { +- pri->timers[x] = defaulttimers[switchtype][x]; ++ /* Initialize all timers/counters to unsupported/disabled. */ ++ for (idx = 0; idx < PRI_MAX_TIMERS; ++idx) { ++ ctrl->timers[idx] = -1; + } ++ ++ /* Set timer values to standard defaults. Time is in ms. */ ++ ctrl->timers[PRI_TIMER_N200] = 3; /* Max numer of Q.921 retransmissions */ ++ ctrl->timers[PRI_TIMER_N202] = 3; /* Max numer of transmissions of the TEI identity request message */ ++ ctrl->timers[PRI_TIMER_K] = 7; /* Max number of outstanding I-frames */ ++ ctrl->timers[PRI_TIMER_T200] = 1000; /* Time between SABME's */ ++ ctrl->timers[PRI_TIMER_T202] = 10 * 1000; /* Min time between transmission of TEI Identity request messages */ ++ ctrl->timers[PRI_TIMER_T203] = 10 * 1000; /* Max time without exchanging packets */ ++ ctrl->timers[PRI_TIMER_T305] = 30 * 1000; /* Wait for DISCONNECT acknowledge */ ++ ctrl->timers[PRI_TIMER_T308] = 4 * 1000; /* Wait for RELEASE acknowledge */ ++ ctrl->timers[PRI_TIMER_T313] = 4 * 1000; /* Wait for CONNECT acknowledge, CPE side only */ ++ ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */ ++ ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */ ++ ctrl->timers[PRI_TIMER_T303] = 4 * 1000; /* Length between SETUP retransmissions and timeout */ ++ ++ ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000; /* Wait for HOLD request response. */ ++ ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */ ++ ++ ctrl->timers[PRI_TIMER_T_RESPONSE] = 4 * 1000; /* Maximum time to wait for a typical APDU response. */ ++ ++ /* Set any switch specific override default values */ ++ switch (switchtype) { ++ default: ++ break; ++ } + } + + int pri_set_timer(struct pri *pri, int timer, int value) +@@ -110,66 +183,30 @@ + return pri->timers[timer]; + } + +-int pri_timer2idx(char *timer) ++int pri_set_service_message_support(struct pri *pri, int supportflag) + { +- if (!strcasecmp(timer, "N200")) +- return PRI_TIMER_N200; +- else if (!strcasecmp(timer, "N201")) +- return PRI_TIMER_N201; +- else if (!strcasecmp(timer, "N202")) +- return PRI_TIMER_N202; +- else if (!strcasecmp(timer, "K")) +- return PRI_TIMER_K; +- else if (!strcasecmp(timer, "T200")) +- return PRI_TIMER_T200; +- else if (!strcasecmp(timer, "T202")) +- return PRI_TIMER_T202; +- else if (!strcasecmp(timer, "T203")) +- return PRI_TIMER_T203; +- else if (!strcasecmp(timer, "T300")) +- return PRI_TIMER_T300; +- else if (!strcasecmp(timer, "T301")) +- return PRI_TIMER_T301; +- else if (!strcasecmp(timer, "T302")) +- return PRI_TIMER_T302; +- else if (!strcasecmp(timer, "T303")) +- return PRI_TIMER_T303; +- else if (!strcasecmp(timer, "T304")) +- return PRI_TIMER_T304; +- else if (!strcasecmp(timer, "T305")) +- return PRI_TIMER_T305; +- else if (!strcasecmp(timer, "T306")) +- return PRI_TIMER_T306; +- else if (!strcasecmp(timer, "T307")) +- return PRI_TIMER_T307; +- else if (!strcasecmp(timer, "T308")) +- return PRI_TIMER_T308; +- else if (!strcasecmp(timer, "T309")) +- return PRI_TIMER_T309; +- else if (!strcasecmp(timer, "T310")) +- return PRI_TIMER_T310; +- else if (!strcasecmp(timer, "T313")) +- return PRI_TIMER_T313; +- else if (!strcasecmp(timer, "T314")) +- return PRI_TIMER_T314; +- else if (!strcasecmp(timer, "T316")) +- return PRI_TIMER_T316; +- else if (!strcasecmp(timer, "T317")) +- return PRI_TIMER_T317; +- else if (!strcasecmp(timer, "T318")) +- return PRI_TIMER_T318; +- else if (!strcasecmp(timer, "T319")) +- return PRI_TIMER_T319; +- else if (!strcasecmp(timer, "T320")) +- return PRI_TIMER_T320; +- else if (!strcasecmp(timer, "T321")) +- return PRI_TIMER_T321; +- else if (!strcasecmp(timer, "T322")) +- return PRI_TIMER_T322; +- else ++ if (!pri) { + return -1; ++ } ++ pri->service_message_support = supportflag; ++ return 0; + } + ++int pri_timer2idx(const char *timer_name) ++{ ++ unsigned idx; ++ enum PRI_TIMERS_AND_COUNTERS timer_number; ++ ++ timer_number = -1; ++ for (idx = 0; idx < ARRAY_LEN(pri_timer); ++idx) { ++ if (!strcasecmp(timer_name, pri_timer[idx].name)) { ++ timer_number = pri_timer[idx].number; ++ break; ++ } ++ } ++ return timer_number; ++} ++ + static int __pri_read(struct pri *pri, void *buf, int buflen) + { + int res = read(pri->fd, buf, buflen); +@@ -192,18 +229,53 @@ + return res; + } + +-/* Pass in the master for this function */ + void __pri_free_tei(struct pri * p) + { +- free (p); ++ if (p) { ++ struct q931_call *call; ++ ++ call = p->dummy_call; ++ if (call) { ++ pri_schedule_del(call->pri, call->retranstimer); ++ pri_call_apdu_queue_cleanup(call); ++ } ++ free(p->msg_line); ++ free(p); ++ } + } + + struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int tei, int bri) + { ++ struct d_ctrl_dummy *dummy_ctrl; + struct pri *p; + +- if (!(p = calloc(1, sizeof(*p)))) +- return NULL; ++ switch (switchtype) { ++ case PRI_SWITCH_GR303_EOC: ++ case PRI_SWITCH_GR303_TMC: ++ case PRI_SWITCH_GR303_TMC_SWITCHING: ++ case PRI_SWITCH_GR303_EOC_PATH: ++ p = calloc(1, sizeof(*p)); ++ if (!p) { ++ return NULL; ++ } ++ dummy_ctrl = NULL; ++ break; ++ default: ++ dummy_ctrl = calloc(1, sizeof(*dummy_ctrl)); ++ if (!dummy_ctrl) { ++ return NULL; ++ } ++ p = &dummy_ctrl->ctrl; ++ break; ++ } ++ if (!master) { ++ /* This is the master record. */ ++ p->msg_line = calloc(1, sizeof(*p->msg_line)); ++ if (!p->msg_line) { ++ free(p); ++ return NULL; ++ } ++ } + + p->bri = bri; + p->fd = fd; +@@ -231,7 +303,14 @@ + p->q931_rxcount = 0; + p->q931_txcount = 0; + #endif +- if (switchtype == PRI_SWITCH_GR303_EOC) { ++ if (dummy_ctrl) { ++ /* Initialize the dummy call reference call record. */ ++ dummy_ctrl->ctrl.dummy_call = &dummy_ctrl->dummy_call; ++ q931_init_call_record(&dummy_ctrl->ctrl, dummy_ctrl->ctrl.dummy_call, ++ Q931_DUMMY_CALL_REFERENCE); ++ } ++ switch (switchtype) { ++ case PRI_SWITCH_GR303_EOC: + p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; + p->sapi = Q921_SAPI_GR303_EOC; + p->tei = Q921_TEI_GR303_EOC_OPS; +@@ -240,7 +319,8 @@ + free(p); + p = NULL; + } +- } else if (switchtype == PRI_SWITCH_GR303_TMC) { ++ break; ++ case PRI_SWITCH_GR303_TMC: + p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; + p->sapi = Q921_SAPI_GR303_TMC_CALLPROC; + p->tei = Q921_TEI_GR303_TMC_CALLPROC; +@@ -249,14 +329,19 @@ + free(p); + p = NULL; + } +- } else if (switchtype == PRI_SWITCH_GR303_TMC_SWITCHING) { ++ break; ++ case PRI_SWITCH_GR303_TMC_SWITCHING: + p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; + p->sapi = Q921_SAPI_GR303_TMC_SWITCHING; + p->tei = Q921_TEI_GR303_TMC_SWITCHING; +- } else if (switchtype == PRI_SWITCH_GR303_EOC_PATH) { ++ break; ++ case PRI_SWITCH_GR303_EOC_PATH: + p->protodisc = GR303_PROTOCOL_DISCRIMINATOR; + p->sapi = Q921_SAPI_GR303_EOC; + p->tei = Q921_TEI_GR303_EOC_PATH; ++ break; ++ default: ++ break; + } + /* Start Q.921 layer, Wait if we're the network */ + if (p) +@@ -327,44 +412,47 @@ + + char *pri_event2str(int id) + { +- switch(id) { +- case PRI_EVENT_DCHAN_UP: +- return "D-Channel Up"; +- case PRI_EVENT_DCHAN_DOWN: +- return "D-channel Down"; +- case PRI_EVENT_RESTART: +- return "Restart channel"; +- case PRI_EVENT_RING: +- return "Ring"; +- case PRI_EVENT_HANGUP: +- return "Hangup"; +- case PRI_EVENT_RINGING: +- return "Ringing"; +- case PRI_EVENT_ANSWER: +- return "Answer"; +- case PRI_EVENT_HANGUP_ACK: +- return "Hangup ACK"; +- case PRI_EVENT_RESTART_ACK: +- return "Restart ACK"; +- case PRI_EVENT_FACNAME: +- return "FacName"; +- case PRI_EVENT_INFO_RECEIVED: +- return "Info Received"; +- case PRI_EVENT_PROCEEDING: +- return "Proceeding"; +- case PRI_EVENT_SETUP_ACK: +- return "Setup ACK"; +- case PRI_EVENT_HANGUP_REQ: +- return "Hangup Req"; +- case PRI_EVENT_NOTIFY: +- return "Notify"; +- case PRI_EVENT_PROGRESS: +- return "Progress"; +- case PRI_EVENT_CONFIG_ERR: +- return "Configuration Error"; +- default: +- return "Unknown Event"; ++ unsigned idx; ++ struct { ++ int id; ++ char *name; ++ } events[] = { ++/* *INDENT-OFF* */ ++ { PRI_EVENT_DCHAN_UP, "D-Channel Up" }, ++ { PRI_EVENT_DCHAN_DOWN, "D-channel Down" }, ++ { PRI_EVENT_RESTART, "Restart channel" }, ++ { PRI_EVENT_CONFIG_ERR, "Configuration Error" }, ++ { PRI_EVENT_RING, "Ring" }, ++ { PRI_EVENT_HANGUP, "Hangup" }, ++ { PRI_EVENT_RINGING, "Ringing" }, ++ { PRI_EVENT_ANSWER, "Answer" }, ++ { PRI_EVENT_HANGUP_ACK, "Hangup ACK" }, ++ { PRI_EVENT_RESTART_ACK, "Restart ACK" }, ++ { PRI_EVENT_FACILITY, "Facility" }, ++ { PRI_EVENT_INFO_RECEIVED, "Info Received" }, ++ { PRI_EVENT_PROCEEDING, "Proceeding" }, ++ { PRI_EVENT_SETUP_ACK, "Setup ACK" }, ++ { PRI_EVENT_HANGUP_REQ, "Hangup Req" }, ++ { PRI_EVENT_NOTIFY, "Notify" }, ++ { PRI_EVENT_PROGRESS, "Progress" }, ++ { PRI_EVENT_KEYPAD_DIGIT, "Keypad Digit" }, ++ { PRI_EVENT_SERVICE, "Service" }, ++ { PRI_EVENT_SERVICE_ACK, "Service ACK" }, ++ { PRI_EVENT_HOLD, "Hold" }, ++ { PRI_EVENT_HOLD_ACK, "Hold Ack" }, ++ { PRI_EVENT_HOLD_REJ, "Hold Rej" }, ++ { PRI_EVENT_RETRIEVE, "Retrieve" }, ++ { PRI_EVENT_RETRIEVE_ACK, "Retrieve ACK" }, ++ { PRI_EVENT_RETRIEVE_REJ, "Retrieve Rej" }, ++/* *INDENT-ON* */ ++ }; ++ ++ for (idx = 0; idx < ARRAY_LEN(events); ++idx) { ++ if (events[idx].id == id) { ++ return events[idx].name; ++ } + } ++ return "Unknown Event"; + } + + pri_event *pri_check_event(struct pri *pri) +@@ -506,7 +594,7 @@ + return q931_information(pri, call, digit); + } + +-int pri_keypad_facility(struct pri *pri, q931_call *call, char *digits) ++int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits) + { + if (!pri || !call || !digits || !digits[0]) + return -1; +@@ -514,15 +602,6 @@ + return q931_keypad_facility(pri, call, digits); + } + +- +-int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason) +-{ +- if (!pri || !call) +- return -1; +- +- return qsig_cf_callrerouting(pri, call, dest, original, reason); +-} +- + int pri_notify(struct pri *pri, q931_call *call, int channel, int info) + { + if (!pri || !call) +@@ -533,7 +612,7 @@ + void pri_destroycall(struct pri *pri, q931_call *call) + { + if (pri && call) +- __q931_destroycall(pri, call); ++ q931_destroycall(pri, call); + return; + } + +@@ -551,6 +630,268 @@ + return q931_connect(pri, call, channel, nonisdn); + } + ++/*! ++ * \internal ++ * \brief Copy the PRI party name to the Q.931 party name structure. ++ * ++ * \param q931_name Q.931 party name structure ++ * \param pri_name PRI party name structure ++ * ++ * \return Nothing ++ */ ++static void pri_copy_party_name_to_q931(struct q931_party_name *q931_name, const struct pri_party_name *pri_name) ++{ ++ q931_party_name_init(q931_name); ++ if (pri_name->valid) { ++ q931_name->valid = 1; ++ q931_name->presentation = pri_name->presentation; ++ q931_name->char_set = pri_name->char_set; ++ libpri_copy_string(q931_name->str, pri_name->str, sizeof(q931_name->str)); ++ } ++} ++ ++/*! ++ * \internal ++ * \brief Copy the PRI party number to the Q.931 party number structure. ++ * ++ * \param q931_number Q.931 party number structure ++ * \param pri_number PRI party number structure ++ * ++ * \return Nothing ++ */ ++static void pri_copy_party_number_to_q931(struct q931_party_number *q931_number, const struct pri_party_number *pri_number) ++{ ++ q931_party_number_init(q931_number); ++ if (pri_number->valid) { ++ q931_number->valid = 1; ++ q931_number->presentation = pri_number->presentation; ++ q931_number->plan = pri_number->plan; ++ libpri_copy_string(q931_number->str, pri_number->str, sizeof(q931_number->str)); ++ } ++} ++ ++/*! ++ * \internal ++ * \brief Copy the PRI party subaddress to the Q.931 party subaddress structure. ++ * ++ * \param q931_subaddress Q.931 party subaddress structure ++ * \param pri_subaddress PRI party subaddress structure ++ * ++ * \return Nothing ++ */ ++static void pri_copy_party_subaddress_to_q931(struct q931_party_subaddress *q931_subaddress, const struct pri_party_subaddress *pri_subaddress) ++{ ++ int length; ++ int maxlen = sizeof(q931_subaddress->data) - 1; ++ ++ q931_party_subaddress_init(q931_subaddress); ++ ++ if (!pri_subaddress->valid) { ++ return; ++ } ++ ++ q931_subaddress->valid = 1; ++ q931_subaddress->type = pri_subaddress->type; ++ ++ length = pri_subaddress->length; ++ if (length > maxlen){ ++ length = maxlen; ++ } else { ++ q931_subaddress->odd_even_indicator = pri_subaddress->odd_even_indicator; ++ } ++ q931_subaddress->length = length; ++ memcpy(q931_subaddress->data, pri_subaddress->data, length); ++ q931_subaddress->data[length] = '\0'; ++} ++ ++/*! ++ * \internal ++ * \brief Copy the PRI party id to the Q.931 party id structure. ++ * ++ * \param q931_id Q.931 party id structure ++ * \param pri_id PRI party id structure ++ * ++ * \return Nothing ++ */ ++static void pri_copy_party_id_to_q931(struct q931_party_id *q931_id, const struct pri_party_id *pri_id) ++{ ++ pri_copy_party_name_to_q931(&q931_id->name, &pri_id->name); ++ pri_copy_party_number_to_q931(&q931_id->number, &pri_id->number); ++ pri_copy_party_subaddress_to_q931(&q931_id->subaddress, &pri_id->subaddress); ++} ++ ++int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pri_party_connected_line *connected) ++{ ++ struct q931_party_id party_id; ++ unsigned idx; ++ struct q931_call *subcall; ++ ++ if (!ctrl || !call) { ++ return -1; ++ } ++ ++ pri_copy_party_id_to_q931(&party_id, &connected->id); ++ q931_party_id_fixup(ctrl, &party_id); ++ if (!q931_party_id_cmp(&party_id, &call->local_id)) { ++ /* The local party information did not change so do nothing. */ ++ return 0; ++ } ++ call->local_id = party_id; ++ ++ /* Update all subcalls with new local_id. */ ++ if (call->outboundbroadcast && call->master_call == call) { ++ for (idx = 0; idx < Q931_MAX_TEI; ++idx) { ++ subcall = call->subcalls[idx]; ++ if (subcall) { ++ subcall->local_id = party_id; ++ } ++ } ++ } ++ ++ switch (call->ourcallstate) { ++ case Q931_CALL_STATE_CALL_INITIATED: ++ case Q931_CALL_STATE_OVERLAP_SENDING: ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ /* ++ * The local party transferred to someone else before ++ * the remote end answered. ++ */ ++ case Q931_CALL_STATE_ACTIVE: ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ if (q931_is_ptmp(ctrl)) { ++ /* PTMP mode */ ++ q931_notify_redirection(ctrl, call, PRI_NOTIFY_TRANSFER_ACTIVE, ++ &call->local_id.number); ++ } else { ++ /* PTP mode */ ++ /* Immediately send EctInform APDU, callStatus=answered(0) */ ++ send_call_transfer_complete(ctrl, call, 0); ++ } ++ break; ++ case PRI_SWITCH_QSIG: ++ /* Immediately send CallTransferComplete APDU, callStatus=answered(0) */ ++ send_call_transfer_complete(ctrl, call, 0); ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ /* Just save the data for further developments. */ ++ break; ++ } ++ ++ return 0; ++} ++ ++int pri_redirecting_update(struct pri *ctrl, q931_call *call, const struct pri_party_redirecting *redirecting) ++{ ++ unsigned idx; ++ struct q931_call *subcall; ++ ++ if (!ctrl || !call) { ++ return -1; ++ } ++ ++ /* Save redirecting.to information and reason. */ ++ pri_copy_party_id_to_q931(&call->redirecting.to, &redirecting->to); ++ q931_party_id_fixup(ctrl, &call->redirecting.to); ++ call->redirecting.reason = redirecting->reason; ++ ++ /* ++ * Update all subcalls with new redirecting.to information and reason. ++ * I do not think we will ever have any subcalls when this data is relevant, ++ * but update it just in case. ++ */ ++ if (call->outboundbroadcast && call->master_call == call) { ++ for (idx = 0; idx < Q931_MAX_TEI; ++idx) { ++ subcall = call->subcalls[idx]; ++ if (subcall) { ++ subcall->redirecting.to = call->redirecting.to; ++ subcall->redirecting.reason = redirecting->reason; ++ } ++ } ++ } ++ ++ switch (call->ourcallstate) { ++ case Q931_CALL_STATE_NULL: ++ /* Save the remaining redirecting information before we place a call. */ ++ pri_copy_party_id_to_q931(&call->redirecting.from, &redirecting->from); ++ q931_party_id_fixup(ctrl, &call->redirecting.from); ++ pri_copy_party_id_to_q931(&call->redirecting.orig_called, &redirecting->orig_called); ++ q931_party_id_fixup(ctrl, &call->redirecting.orig_called); ++ call->redirecting.orig_reason = redirecting->orig_reason; ++ if (redirecting->count <= 0) { ++ if (call->redirecting.from.number.valid) { ++ /* ++ * We are redirecting with an unknown count ++ * so assume the count is one. ++ */ ++ call->redirecting.count = 1; ++ } else { ++ call->redirecting.count = 0; ++ } ++ } else if (redirecting->count < PRI_MAX_REDIRECTS) { ++ call->redirecting.count = redirecting->count; ++ } else { ++ call->redirecting.count = PRI_MAX_REDIRECTS; ++ } ++ break; ++ case Q931_CALL_STATE_OVERLAP_RECEIVING: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ /* This is an incoming call that has not connected yet. */ ++ if (!call->redirecting.to.number.valid) { ++ /* Not being redirected toward valid number data. Ignore. */ ++ break; ++ } ++ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ if (q931_is_ptmp(ctrl)) { ++ /* PTMP mode */ ++ q931_notify_redirection(ctrl, call, PRI_NOTIFY_CALL_DIVERTING, ++ &call->redirecting.to.number); ++ break; ++ } ++ /* PTP mode - same behaviour as Q.SIG */ ++ /* fall through */ ++ case PRI_SWITCH_QSIG: ++ if (call->redirecting.state != Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3 ++ || strcmp(call->redirecting.to.number.str, call->called.number.str) != 0) { ++ /* immediately send divertingLegInformation1 APDU */ ++ if (rose_diverting_leg_information1_encode(ctrl, call) ++ || q931_facility(ctrl, call)) { ++ pri_message(ctrl, ++ "Could not schedule facility message for divertingLegInfo1\n"); ++ } ++ } ++ call->redirecting.state = Q931_REDIRECTING_STATE_IDLE; ++ ++ /* immediately send divertingLegInformation3 APDU */ ++ if (rose_diverting_leg_information3_encode(ctrl, call, Q931_FACILITY) ++ || q931_facility(ctrl, call)) { ++ pri_message(ctrl, ++ "Could not schedule facility message for divertingLegInfo3\n"); ++ } ++ break; ++ default: ++ break; ++ } ++ break; ++ default: ++ pri_message(ctrl, "Ignored redirecting update because call in state %s(%d).\n", ++ q931_call_state_str(call->ourcallstate), call->ourcallstate); ++ break; ++ } ++ ++ return 0; ++} ++ + #if 0 + /* deprecated routines, use pri_hangup */ + int pri_release(struct pri *pri, q931_call *call, int cause) +@@ -619,7 +960,7 @@ + return -1; + if (cause == -1) + /* normal clear cause */ +- cause = 16; ++ cause = PRI_CAUSE_NORMAL_CLEARING; + return q931_hangup(pri, call, cause); + } + +@@ -630,6 +971,14 @@ + return q931_restart(pri, channel); + } + ++int pri_maintenance_service(struct pri *pri, int span, int channel, int changestatus) ++{ ++ if (!pri) { ++ return -1; ++ } ++ return maintenance_service(pri, span, channel, changestatus); ++} ++ + q931_call *pri_new_call(struct pri *pri) + { + if (!pri) +@@ -637,6 +986,14 @@ + return q931_new_call(pri); + } + ++int pri_is_dummy_call(q931_call *call) ++{ ++ if (!call) { ++ return 0; ++ } ++ return q931_is_dummy_call(call); ++} ++ + void pri_dump_event(struct pri *pri, pri_event *e) + { + if (!pri || !e) +@@ -667,7 +1024,10 @@ + static void pri_sr_init(struct pri_sr *req) + { + memset(req, 0, sizeof(struct pri_sr)); +- ++ q931_party_redirecting_init(&req->redirecting); ++ q931_party_id_init(&req->caller); ++ q931_party_address_init(&req->called); ++ req->reversecharge = PRI_REVERSECHARGE_NONE; + } + + int pri_sr_set_connection_call_independent(struct pri_sr *req) +@@ -675,10 +1035,21 @@ + if (!req) + return -1; + +- req->justsignalling = 1; /* have to set justsignalling for all those pesky IEs we need to setup */ ++ req->cis_call = 1; /* have to set cis_call for all those pesky IEs we need to setup */ ++ req->cis_auto_disconnect = 1; + return 0; + } + ++int pri_sr_set_no_channel_call(struct pri_sr *req) ++{ ++ if (!req) { ++ return -1; ++ } ++ ++ req->cis_call = 1; ++ return 0; ++} ++ + /* Don't call any other pri functions on this */ + int pri_mwi_activate(struct pri *pri, q931_call *c, char *caller, int callerplan, char *callername, int callerpres, char *called, + int calledplan) +@@ -689,14 +1060,9 @@ + + pri_sr_init(&req); + pri_sr_set_connection_call_independent(&req); ++ pri_sr_set_caller(&req, caller, callername, callerplan, callerpres); ++ pri_sr_set_called(&req, called, calledplan, 0); + +- req.caller = caller; +- req.callerplan = callerplan; +- req.callername = callername; +- req.callerpres = callerpres; +- req.called = called; +- req.calledplan = calledplan; +- + if (mwi_message_send(pri, c, &req, 1) < 0) { + pri_message(pri, "Unable to send MWI activate message\n"); + return -1; +@@ -714,14 +1080,9 @@ + + pri_sr_init(&req); + pri_sr_set_connection_call_independent(&req); ++ pri_sr_set_caller(&req, caller, callername, callerplan, callerpres); ++ pri_sr_set_called(&req, called, calledplan, 0); + +- req.caller = caller; +- req.callerplan = callerplan; +- req.callername = callername; +- req.callerpres = callerpres; +- req.called = called; +- req.calledplan = calledplan; +- + if(mwi_message_send(pri, c, &req, 0) < 0) { + pri_message(pri, "Unable to send MWI deactivate message\n"); + return -1; +@@ -740,22 +1101,18 @@ + + int pri_call(struct pri *pri, q931_call *c, int transmode, int channel, int exclusive, + int nonisdn, char *caller, int callerplan, char *callername, int callerpres, char *called, +- int calledplan,int ulayer1) ++ int calledplan, int ulayer1) + { + struct pri_sr req; + if (!pri || !c) + return -1; + pri_sr_init(&req); ++ pri_sr_set_caller(&req, caller, callername, callerplan, callerpres); ++ pri_sr_set_called(&req, called, calledplan, 0); + req.transmode = transmode; + req.channel = channel; + req.exclusive = exclusive; + req.nonisdn = nonisdn; +- req.caller = caller; +- req.callerplan = callerplan; +- req.callername = callername; +- req.callerpres = callerpres; +- req.called = called; +- req.calledplan = calledplan; + req.userl1 = ulayer1; + return q931_setup(pri, c, &req); + } +@@ -773,28 +1130,85 @@ + __pri_error = func; + } + +-void pri_message(struct pri *pri, char *fmt, ...) ++static void pri_old_message(struct pri *ctrl, const char *fmt, va_list *ap) + { + char tmp[1024]; +- va_list ap; +- va_start(ap, fmt); +- vsnprintf(tmp, sizeof(tmp), fmt, ap); +- va_end(ap); ++ ++ vsnprintf(tmp, sizeof(tmp), fmt, *ap); + if (__pri_message) +- __pri_message(pri, tmp); ++ __pri_message(ctrl, tmp); + else + fputs(tmp, stdout); + } + +-void pri_error(struct pri *pri, char *fmt, ...) ++void pri_message(struct pri *ctrl, const char *fmt, ...) + { ++ int added_length; ++ va_list ap; ++ ++ ctrl = PRI_MASTER(ctrl); ++ if (!ctrl || !ctrl->msg_line) { ++ /* Just have to do it the old way. */ ++ va_start(ap, fmt); ++ pri_old_message(ctrl, fmt, &ap); ++ va_end(ap); ++ return; ++ } ++ ++ va_start(ap, fmt); ++ added_length = vsnprintf(ctrl->msg_line->str + ctrl->msg_line->length, ++ sizeof(ctrl->msg_line->str) - ctrl->msg_line->length, fmt, ap); ++ va_end(ap); ++ if (added_length < 0 ++ || sizeof(ctrl->msg_line->str) <= ctrl->msg_line->length + added_length) { ++ static char truncated_output[] = ++ "v-- Error building output or output was truncated. (Next line) --v\n"; ++ ++ /* ++ * This clause should never need to run because the ++ * output line accumulation buffer is quite large. ++ */ ++ ++ /* vsnprintf() error or output string was truncated. */ ++ if (__pri_message) { ++ __pri_message(ctrl, truncated_output); ++ } else { ++ fputs(truncated_output, stdout); ++ } ++ ++ /* Add a terminating '\n' to force a flush of the line. */ ++ ctrl->msg_line->length = strlen(ctrl->msg_line->str); ++ if (ctrl->msg_line->length) { ++ ctrl->msg_line->str[ctrl->msg_line->length - 1] = '\n'; ++ } else { ++ ctrl->msg_line->str[0] = '\n'; ++ ctrl->msg_line->str[1] = '\0'; ++ } ++ } else { ++ ctrl->msg_line->length += added_length; ++ } ++ ++ if (ctrl->msg_line->length ++ && ctrl->msg_line->str[ctrl->msg_line->length - 1] == '\n') { ++ /* The accumulated output line was terminated so send it out. */ ++ ctrl->msg_line->length = 0; ++ if (__pri_message) { ++ __pri_message(ctrl, ctrl->msg_line->str); ++ } else { ++ fputs(ctrl->msg_line->str, stdout); ++ } ++ } ++} ++ ++void pri_error(struct pri *pri, const char *fmt, ...) ++{ + char tmp[1024]; + va_list ap; + va_start(ap, fmt); + vsnprintf(tmp, sizeof(tmp), fmt, ap); + va_end(ap); + if (__pri_error) +- __pri_error(pri, tmp); ++ __pri_error(PRI_MASTER(pri), tmp); + else + fputs(tmp, stderr); + } +@@ -821,49 +1235,102 @@ + return pri->fd; + } + +-char *pri_dump_info_str(struct pri *pri) ++/*! ++ * \internal ++ * \brief Append snprintf output to the given buffer. ++ * ++ * \param buf Buffer currently filling. ++ * \param buf_used Offset into buffer where to put new stuff. ++ * \param buf_size Actual buffer size of buf. ++ * \param format printf format string. ++ * ++ * \return Total buffer space used. ++ */ ++static size_t pri_snprintf(char *buf, size_t buf_used, size_t buf_size, const char *format, ...) __attribute__((format(printf, 4, 5))); ++static size_t pri_snprintf(char *buf, size_t buf_used, size_t buf_size, const char *format, ...) + { +- char buf[4096]; +- int len = 0; ++ va_list args; ++ ++ if (buf_used < buf_size) { ++ va_start(args, format); ++ buf_used += vsnprintf(buf + buf_used, buf_size - buf_used, format, args); ++ va_end(args); ++ } ++ if (buf_size < buf_used) { ++ buf_used = buf_size + 1; ++ } ++ return buf_used; ++} ++ ++char *pri_dump_info_str(struct pri *ctrl) ++{ ++ char *buf; ++ size_t buf_size; ++ size_t used; + #ifdef LIBPRI_COUNTERS + struct q921_frame *f; +- int q921outstanding = 0; ++ unsigned q921outstanding; + #endif +- if (!pri) ++ unsigned idx; ++ unsigned long switch_bit; ++ ++ if (!ctrl) { + return NULL; ++ } + ++ buf_size = 4096; /* This should be bigger than we will ever need. */ ++ buf = malloc(buf_size); ++ if (!buf) { ++ return NULL; ++ } ++ + /* Might be nice to format these a little better */ +- len += sprintf(buf + len, "Switchtype: %s\n", pri_switch2str(pri->switchtype)); +- len += sprintf(buf + len, "Type: %s\n", pri_node2str(pri->localtype)); ++ used = 0; ++ used = pri_snprintf(buf, used, buf_size, "Switchtype: %s\n", ++ pri_switch2str(ctrl->switchtype)); ++ used = pri_snprintf(buf, used, buf_size, "Type: %s\n", pri_node2str(ctrl->localtype)); + #ifdef LIBPRI_COUNTERS + /* Remember that Q921 Counters include Q931 packets (and any retransmissions) */ +- len += sprintf(buf + len, "Q931 RX: %d\n", pri->q931_rxcount); +- len += sprintf(buf + len, "Q931 TX: %d\n", pri->q931_txcount); +- len += sprintf(buf + len, "Q921 RX: %d\n", pri->q921_rxcount); +- len += sprintf(buf + len, "Q921 TX: %d\n", pri->q921_txcount); +- f = pri->txqueue; ++ used = pri_snprintf(buf, used, buf_size, "Q931 RX: %d\n", ctrl->q931_rxcount); ++ used = pri_snprintf(buf, used, buf_size, "Q931 TX: %d\n", ctrl->q931_txcount); ++ used = pri_snprintf(buf, used, buf_size, "Q921 RX: %d\n", ctrl->q921_rxcount); ++ used = pri_snprintf(buf, used, buf_size, "Q921 TX: %d\n", ctrl->q921_txcount); ++ q921outstanding = 0; ++ f = ctrl->txqueue; + while (f) { + q921outstanding++; + f = f->next; + } +- len += sprintf(buf + len, "Q921 Outstanding: %d\n", q921outstanding); ++ used = pri_snprintf(buf, used, buf_size, "Q921 Outstanding: %u\n", q921outstanding); + #endif +- len += sprintf(buf + len, "Window Length: %d/%d\n", pri->windowlen, pri->window); +- len += sprintf(buf + len, "Sentrej: %d\n", pri->sentrej); +- len += sprintf(buf + len, "SolicitFbit: %d\n", pri->solicitfbit); +- len += sprintf(buf + len, "Retrans: %d\n", pri->retrans); +- len += sprintf(buf + len, "Busy: %d\n", pri->busy); +- len += sprintf(buf + len, "Overlap Dial: %d\n", pri->overlapdial); +- len += sprintf(buf + len, "Logical Channel Mapping: %d\n", pri->chan_mapping_logical); +- len += sprintf(buf + len, "T200 Timer: %d\n", pri->timers[PRI_TIMER_T200]); +- len += sprintf(buf + len, "T203 Timer: %d\n", pri->timers[PRI_TIMER_T203]); +- len += sprintf(buf + len, "T305 Timer: %d\n", pri->timers[PRI_TIMER_T305]); +- len += sprintf(buf + len, "T308 Timer: %d\n", pri->timers[PRI_TIMER_T308]); +- len += sprintf(buf + len, "T309 Timer: %d\n", pri->timers[PRI_TIMER_T309]); +- len += sprintf(buf + len, "T313 Timer: %d\n", pri->timers[PRI_TIMER_T313]); +- len += sprintf(buf + len, "N200 Counter: %d\n", pri->timers[PRI_TIMER_N200]); ++ used = pri_snprintf(buf, used, buf_size, "Window Length: %d/%d\n", ctrl->windowlen, ++ ctrl->window); ++ used = pri_snprintf(buf, used, buf_size, "Sentrej: %d\n", ctrl->sentrej); ++ used = pri_snprintf(buf, used, buf_size, "SolicitFbit: %d\n", ctrl->solicitfbit); ++ used = pri_snprintf(buf, used, buf_size, "Retrans: %d\n", ctrl->retrans); ++ used = pri_snprintf(buf, used, buf_size, "Busy: %d\n", ctrl->busy); ++ used = pri_snprintf(buf, used, buf_size, "Overlap Dial: %d\n", ctrl->overlapdial); ++ used = pri_snprintf(buf, used, buf_size, "Logical Channel Mapping: %d\n", ++ ctrl->chan_mapping_logical); ++ used = pri_snprintf(buf, used, buf_size, "Timer and counter settings:\n"); ++ switch_bit = PRI_BIT(ctrl->switchtype); ++ for (idx = 0; idx < ARRAY_LEN(pri_timer); ++idx) { ++ if (pri_timer[idx].used_by & switch_bit) { ++ enum PRI_TIMERS_AND_COUNTERS tmr; + +- return strdup(buf); ++ tmr = pri_timer[idx].number; ++ if (0 <= ctrl->timers[tmr] || tmr == PRI_TIMER_T309) { ++ used = pri_snprintf(buf, used, buf_size, " %s: %d\n", ++ pri_timer[idx].name, ctrl->timers[tmr]); ++ } ++ } ++ } ++ ++ if (buf_size < used) { ++ pri_message(ctrl, ++ "pri_dump_info_str(): Produced output exceeded buffer capacity. (Truncated)\n"); ++ } ++ return buf; + } + + int pri_get_crv(struct pri *pri, q931_call *call, int *callmode) +@@ -913,26 +1380,213 @@ + + int pri_sr_set_called(struct pri_sr *sr, char *called, int calledplan, int numcomplete) + { +- sr->called = called; +- sr->calledplan = calledplan; ++ q931_party_address_init(&sr->called); ++ if (called) { ++ sr->called.number.valid = 1; ++ sr->called.number.plan = calledplan; ++ libpri_copy_string(sr->called.number.str, called, sizeof(sr->called.number.str)); ++ } + sr->numcomplete = numcomplete; + return 0; + } + ++void pri_sr_set_called_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress) ++{ ++ pri_copy_party_subaddress_to_q931(&sr->called.subaddress, subaddress); ++} ++ + int pri_sr_set_caller(struct pri_sr *sr, char *caller, char *callername, int callerplan, int callerpres) + { +- sr->caller = caller; +- sr->callername = callername; +- sr->callerplan = callerplan; +- sr->callerpres = callerpres; ++ q931_party_id_init(&sr->caller); ++ if (caller) { ++ sr->caller.number.valid = 1; ++ sr->caller.number.presentation = callerpres; ++ sr->caller.number.plan = callerplan; ++ libpri_copy_string(sr->caller.number.str, caller, sizeof(sr->caller.number.str)); ++ ++ if (callername) { ++ sr->caller.name.valid = 1; ++ sr->caller.name.presentation = callerpres; ++ sr->caller.name.char_set = PRI_CHAR_SET_ISO8859_1; ++ libpri_copy_string(sr->caller.name.str, callername, ++ sizeof(sr->caller.name.str)); ++ } ++ } + return 0; + } + ++void pri_sr_set_caller_subaddress(struct pri_sr *sr, const struct pri_party_subaddress *subaddress) ++{ ++ pri_copy_party_subaddress_to_q931(&sr->caller.subaddress, subaddress); ++} ++ ++void pri_sr_set_caller_party(struct pri_sr *sr, const struct pri_party_id *caller) ++{ ++ pri_copy_party_id_to_q931(&sr->caller, caller); ++} ++ + int pri_sr_set_redirecting(struct pri_sr *sr, char *num, int plan, int pres, int reason) + { +- sr->redirectingnum = num; +- sr->redirectingplan = plan; +- sr->redirectingpres = pres; +- sr->redirectingreason = reason; ++ q931_party_redirecting_init(&sr->redirecting); ++ if (num && num[0]) { ++ sr->redirecting.from.number.valid = 1; ++ sr->redirecting.from.number.presentation = pres; ++ sr->redirecting.from.number.plan = plan; ++ libpri_copy_string(sr->redirecting.from.number.str, num, ++ sizeof(sr->redirecting.from.number.str)); ++ ++ sr->redirecting.count = 1; ++ sr->redirecting.reason = reason; ++ } + return 0; + } ++ ++void pri_sr_set_redirecting_parties(struct pri_sr *sr, const struct pri_party_redirecting *redirecting) ++{ ++ pri_copy_party_id_to_q931(&sr->redirecting.from, &redirecting->from); ++ pri_copy_party_id_to_q931(&sr->redirecting.to, &redirecting->to); ++ pri_copy_party_id_to_q931(&sr->redirecting.orig_called, &redirecting->orig_called); ++ sr->redirecting.orig_reason = redirecting->orig_reason; ++ sr->redirecting.reason = redirecting->reason; ++ if (redirecting->count <= 0) { ++ if (sr->redirecting.from.number.valid) { ++ /* ++ * We are redirecting with an unknown count ++ * so assume the count is one. ++ */ ++ sr->redirecting.count = 1; ++ } else { ++ sr->redirecting.count = 0; ++ } ++ } else if (redirecting->count < PRI_MAX_REDIRECTS) { ++ sr->redirecting.count = redirecting->count; ++ } else { ++ sr->redirecting.count = PRI_MAX_REDIRECTS; ++ } ++} ++ ++void pri_sr_set_reversecharge(struct pri_sr *sr, int requested) ++{ ++ sr->reversecharge = requested; ++} ++ ++void pri_sr_set_keypad_digits(struct pri_sr *sr, const char *keypad_digits) ++{ ++ sr->keypad_digits = keypad_digits; ++} ++ ++void pri_hold_enable(struct pri *ctrl, int enable) ++{ ++ ctrl = PRI_MASTER(ctrl); ++ if (ctrl) { ++ ctrl->hold_support = enable ? 1 : 0; ++ } ++} ++ ++int pri_hold(struct pri *ctrl, q931_call *call) ++{ ++ if (!ctrl || !call) { ++ return -1; ++ } ++ return q931_send_hold(ctrl, call); ++} ++ ++int pri_hold_ack(struct pri *ctrl, q931_call *call) ++{ ++ if (!ctrl || !call) { ++ return -1; ++ } ++ return q931_send_hold_ack(ctrl, call); ++} ++ ++int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause) ++{ ++ if (!ctrl || !call) { ++ return -1; ++ } ++ return q931_send_hold_rej(ctrl, call, cause); ++} ++ ++int pri_retrieve(struct pri *ctrl, q931_call *call, int channel) ++{ ++ if (!ctrl || !call) { ++ return -1; ++ } ++ return q931_send_retrieve(ctrl, call, channel); ++} ++ ++int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel) ++{ ++ if (!ctrl || !call) { ++ return -1; ++ } ++ return q931_send_retrieve_ack(ctrl, call, channel); ++} ++ ++int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause) ++{ ++ if (!ctrl || !call) { ++ return -1; ++ } ++ return q931_send_retrieve_rej(ctrl, call, cause); ++} ++ ++int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason) ++{ ++ if (!pri || !call || !dest) ++ return -1; ++ ++ return qsig_cf_callrerouting(pri, call, dest, original, reason); ++} ++ ++void pri_reroute_enable(struct pri *ctrl, int enable) ++{ ++ ctrl = PRI_MASTER(ctrl); ++ if (ctrl) { ++ ctrl->deflection_support = enable ? 1 : 0; ++ } ++} ++ ++int pri_reroute_call(struct pri *ctrl, q931_call *call, const struct pri_party_id *caller, const struct pri_party_redirecting *deflection, int subscription_option) ++{ ++ const struct q931_party_id *caller_id; ++ struct q931_party_id local_caller; ++ struct q931_party_redirecting reroute; ++ ++ if (!ctrl || !call || !deflection) { ++ return -1; ++ } ++ ++ if (caller) { ++ /* Convert the caller update information. */ ++ pri_copy_party_id_to_q931(&local_caller, caller); ++ q931_party_id_fixup(ctrl, &local_caller); ++ caller_id = &local_caller; ++ } else { ++ caller_id = NULL; ++ } ++ ++ /* Convert the deflection information. */ ++ q931_party_redirecting_init(&reroute); ++ pri_copy_party_id_to_q931(&reroute.from, &deflection->from); ++ q931_party_id_fixup(ctrl, &reroute.from); ++ pri_copy_party_id_to_q931(&reroute.to, &deflection->to); ++ q931_party_id_fixup(ctrl, &reroute.to); ++ pri_copy_party_id_to_q931(&reroute.orig_called, &deflection->orig_called); ++ q931_party_id_fixup(ctrl, &reroute.orig_called); ++ reroute.reason = deflection->reason; ++ reroute.orig_reason = deflection->orig_reason; ++ if (deflection->count <= 0) { ++ /* ++ * We are deflecting with an unknown count ++ * so assume the count is one. ++ */ ++ reroute.count = 1; ++ } else if (deflection->count < PRI_MAX_REDIRECTS) { ++ reroute.count = deflection->count; ++ } else { ++ reroute.count = PRI_MAX_REDIRECTS; ++ } ++ ++ return send_reroute_request(ctrl, call, caller_id, &reroute, subscription_option); ++} +Index: Makefile +=================================================================== +--- a/Makefile (.../tags/1.4.10.2) (revision 1357) ++++ b/Makefile (.../branches/1.4) (revision 1357) +@@ -41,15 +41,55 @@ + + STATIC_LIBRARY=libpri.a + DYNAMIC_LIBRARY:=libpri.so.$(SONAME) +-STATIC_OBJS=copy_string.o pri.o q921.o prisched.o q931.o pri_facility.o version.o +-DYNAMIC_OBJS=copy_string.lo pri.lo q921.lo prisched.lo q931.lo pri_facility.lo version.lo +-CFLAGS=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) ++STATIC_OBJS= \ ++ copy_string.o \ ++ pri.o \ ++ q921.o \ ++ prisched.o \ ++ q931.o \ ++ pri_facility.o \ ++ asn1_primitive.o \ ++ rose.o \ ++ rose_address.o \ ++ rose_etsi_aoc.o \ ++ rose_etsi_diversion.o \ ++ rose_etsi_ect.o \ ++ rose_other.o \ ++ rose_q931.o \ ++ rose_qsig_aoc.o \ ++ rose_qsig_ct.o \ ++ rose_qsig_diversion.o \ ++ rose_qsig_mwi.o \ ++ rose_qsig_name.o \ ++ version.o ++DYNAMIC_OBJS= \ ++ copy_string.lo \ ++ pri.lo \ ++ q921.lo \ ++ prisched.lo \ ++ q931.lo \ ++ pri_facility.lo \ ++ asn1_primitive.lo \ ++ rose.lo \ ++ rose_address.lo \ ++ rose_etsi_aoc.lo \ ++ rose_etsi_diversion.lo \ ++ rose_etsi_ect.lo \ ++ rose_other.lo \ ++ rose_q931.lo \ ++ rose_qsig_aoc.lo \ ++ rose_qsig_ct.lo \ ++ rose_qsig_diversion.lo \ ++ rose_qsig_mwi.lo \ ++ rose_qsig_name.lo \ ++ version.lo ++CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes -g -fPIC $(ALERTING) $(LIBPRI_COUNTERS) $(LIBPRI_OPT) + INSTALL_PREFIX=$(DESTDIR) + INSTALL_BASE=/usr + libdir?=$(INSTALL_BASE)/lib + SOFLAGS:=-Wl,-h$(DYNAMIC_LIBRARY) + LDCONFIG = /sbin/ldconfig +-ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX)) ++ifneq (,$(findstring X$(OSARCH)X, XLinuxX XGNU/kFreeBSDX XGNUX)) + LDCONFIG_FLAGS=-n + else + ifeq (${OSARCH},FreeBSD) +@@ -74,7 +114,9 @@ + #A ultrasparc cpu is really v9 but the stock debian stable 3.0 gcc doesnt support it. + ifeq ($(PROC),sparc64) + PROC=ultrasparc +-CFLAGS += -mtune=$(PROC) -O3 -pipe -fomit-frame-pointer -mcpu=v8 ++LIBPRI_OPT = -mtune=$(PROC) -O3 -pipe -fomit-frame-pointer -mcpu=v8 ++else ++LIBPRI_OPT = -O2 + endif + + all: $(STATIC_LIBRARY) $(DYNAMIC_LIBRARY) +@@ -132,6 +174,9 @@ + pridump: pridump.o + $(CC) -o pridump pridump.o -L. -lpri $(CFLAGS) + ++rosetest: rosetest.o ++ $(CC) -o rosetest rosetest.o -L. -lpri $(CFLAGS) ++ + MAKE_DEPS= -MD -MT $@ -MF .$(subst /,_,$@).d -MP + + %.o: %.c +Index: q931.c +=================================================================== +--- a/q931.c (.../tags/1.4.10.2) (revision 1357) ++++ b/q931.c (.../branches/1.4) (revision 1357) +@@ -33,6 +33,7 @@ + #include "pri_q921.h" + #include "pri_q931.h" + #include "pri_facility.h" ++#include "rose.h" + + #include <unistd.h> + #include <stdlib.h> +@@ -67,7 +68,7 @@ + { Q931_RESTART_ACKNOWLEDGE, "RESTART ACKNOWLEDGE", { Q931_RESTART_INDICATOR } }, + + /* Miscellaneous */ +- { Q931_STATUS, "STATUS", { Q931_CAUSE, Q931_CALL_STATE } }, ++ { Q931_STATUS, "STATUS", { Q931_CAUSE, Q931_IE_CALL_STATE } }, + { Q931_STATUS_ENQUIRY, "STATUS ENQUIRY" }, + { Q931_USER_INFORMATION, "USER_INFORMATION" }, + { Q931_SEGMENT, "SEGMENT" }, +@@ -79,22 +80,32 @@ + /* Call Management */ + { Q931_HOLD, "HOLD" }, + { Q931_HOLD_ACKNOWLEDGE, "HOLD ACKNOWLEDGE" }, +- { Q931_HOLD_REJECT, "HOLD REJECT" }, ++ { Q931_HOLD_REJECT, "HOLD REJECT", { Q931_CAUSE } }, + { Q931_RETRIEVE, "RETRIEVE" }, + { Q931_RETRIEVE_ACKNOWLEDGE, "RETRIEVE ACKNOWLEDGE" }, +- { Q931_RETRIEVE_REJECT, "RETRIEVE REJECT" }, ++ { Q931_RETRIEVE_REJECT, "RETRIEVE REJECT", { Q931_CAUSE } }, + { Q931_RESUME, "RESUME" }, + { Q931_RESUME_ACKNOWLEDGE, "RESUME ACKNOWLEDGE", { Q931_CHANNEL_IDENT } }, + { Q931_RESUME_REJECT, "RESUME REJECT", { Q931_CAUSE } }, + { Q931_SUSPEND, "SUSPEND" }, + { Q931_SUSPEND_ACKNOWLEDGE, "SUSPEND ACKNOWLEDGE" }, + { Q931_SUSPEND_REJECT, "SUSPEND REJECT" }, ++}; + +- /* Maintenance */ +- { NATIONAL_SERVICE, "SERVICE" }, +- { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE" }, ++static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand); ++static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int *allow_event, int *allow_posthandle); ++ ++struct msgtype att_maintenance_msgs[] = { ++ { ATT_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } }, ++ { ATT_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } }, + }; + ++struct msgtype national_maintenance_msgs[] = { ++ { NATIONAL_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } }, ++ { NATIONAL_SERVICE_ACKNOWLEDGE, "SERVICE ACKNOWLEDGE", { Q931_CHANNEL_IDENT } }, ++}; ++static int post_handle_maintenance_message(struct pri *ctrl, int protodisc, struct q931_mh *mh, struct q931_call *c); ++ + static struct msgtype causes[] = { + { PRI_CAUSE_UNALLOCATED, "Unallocated (unassigned) number" }, + { PRI_CAUSE_NO_ROUTE_TRANSIT_NET, "No route to specified transmit network" }, +@@ -107,6 +118,7 @@ + { PRI_CAUSE_NO_ANSWER, "User alerting, no answer" }, + { PRI_CAUSE_CALL_REJECTED, "Call Rejected" }, + { PRI_CAUSE_NUMBER_CHANGED, "Number changed" }, ++ { PRI_CAUSE_NONSELECTED_USER_CLEARING, "Non-selected user clearing" }, + { PRI_CAUSE_DESTINATION_OUT_OF_ORDER, "Destination out of order" }, + { PRI_CAUSE_INVALID_NUMBER_FORMAT, "Invalid number format" }, + { PRI_CAUSE_FACILITY_REJECTED, "Facility rejected" }, +@@ -119,13 +131,14 @@ + { PRI_CAUSE_ACCESS_INFO_DISCARDED, "Access information discarded" }, + { PRI_CAUSE_REQUESTED_CHAN_UNAVAIL, "Requested channel not available" }, + { PRI_CAUSE_PRE_EMPTED, "Pre-empted" }, ++ { PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED, "Resource unavailable, unspecified" }, + { PRI_CAUSE_FACILITY_NOT_SUBSCRIBED, "Facility not subscribed" }, + { PRI_CAUSE_OUTGOING_CALL_BARRED, "Outgoing call barred" }, + { PRI_CAUSE_INCOMING_CALL_BARRED, "Incoming call barred" }, + { PRI_CAUSE_BEARERCAPABILITY_NOTAUTH, "Bearer capability not authorized" }, + { PRI_CAUSE_BEARERCAPABILITY_NOTAVAIL, "Bearer capability not available" }, ++ { PRI_CAUSE_SERVICEOROPTION_NOTAVAIL, "Service or option not available, unspecified" }, + { PRI_CAUSE_BEARERCAPABILITY_NOTIMPL, "Bearer capability not implemented" }, +- { PRI_CAUSE_SERVICEOROPTION_NOTAVAIL, "Service or option not available, unspecified" }, + { PRI_CAUSE_CHAN_NOT_IMPLEMENTED, "Channel not implemented" }, + { PRI_CAUSE_FACILITY_NOT_IMPLEMENTED, "Facility not implemented" }, + { PRI_CAUSE_INVALID_CALL_REFERENCE, "Invalid call reference value" }, +@@ -163,8 +176,9 @@ + { PRI_NSF_CALL_REDIRECTION_SERVICE, "Call Redirection Service" } + }; + +-#define FLAG_PREFERRED 2 +-#define FLAG_EXCLUSIVE 4 ++#define FLAG_WHOLE_INTERFACE 0x01 ++#define FLAG_PREFERRED 0x02 ++#define FLAG_EXCLUSIVE 0x04 + + #define RESET_INDICATOR_CHANNEL 0 + #define RESET_INDICATOR_DS1 6 +@@ -214,26 +228,49 @@ + #define LOC_NETWORK_BEYOND_INTERWORKING 0xa + + static char *ie2str(int ie); +-static char *msg2str(int msg); + + +-#define FUNC_DUMP(name) void ((name))(int full_ie, struct pri *pri, q931_ie *ie, int len, char prefix) +-#define FUNC_RECV(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len) +-#define FUNC_SEND(name) int ((name))(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len, int order) ++#define FUNC_DUMP(name) void (name)(int full_ie, struct pri *pri, q931_ie *ie, int len, char prefix) ++#define FUNC_RECV(name) int (name)(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len) ++#define FUNC_SEND(name) int (name)(int full_ie, struct pri *pri, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + + #if 1 + /* Update call state with transition trace. */ +-#define UPDATE_OURCALLSTATE(pri,c,newstate) do {\ +- if (pri->debug & (PRI_DEBUG_Q931_STATE) && c->ourcallstate != newstate) \ +- pri_message(pri, DBGHEAD "call %d on channel %d enters state %d (%s)\n", DBGINFO, \ +- c->cr, c->channelno, newstate, callstate2str(newstate)); \ +- c->ourcallstate = newstate; \ ++#define UPDATE_OURCALLSTATE(ctrl, call, newstate) \ ++ do { \ ++ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) && (call)->ourcallstate != (newstate)) { \ ++ pri_message((ctrl), \ ++ DBGHEAD "%s %d enters state %d (%s). Hold state: %s\n", \ ++ DBGINFO, ((call) == (call)->master_call) ? "Call" : "Subcall", \ ++ (call)->cr, (newstate), q931_call_state_str(newstate), \ ++ q931_hold_state_str((call)->master_call->hold_state)); \ ++ } \ ++ (call)->ourcallstate = (newstate); \ + } while (0) + #else + /* Update call state with no trace. */ +-#define UPDATE_OURCALLSTATE(pri,c,newstate) c->ourcallstate = newstate ++#define UPDATE_OURCALLSTATE(ctrl, call, newstate) (call)->ourcallstate = (newstate) + #endif + ++#if 1 ++/* Update hold state with transition trace. */ ++#define UPDATE_HOLD_STATE(ctrl, master_call, newstate) \ ++ do { \ ++ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) \ ++ && (master_call)->hold_state != (newstate)) { \ ++ pri_message((ctrl), \ ++ DBGHEAD "Call %d in state %d (%s) enters Hold state: %s\n", \ ++ DBGINFO, (master_call)->cr, (master_call)->ourcallstate, \ ++ q931_call_state_str((master_call)->ourcallstate), \ ++ q931_hold_state_str(newstate)); \ ++ } \ ++ (master_call)->hold_state = (newstate); \ ++ } while (0) ++#else ++/* Update hold state with no trace. */ ++#define UPDATE_HOLD_STATE(ctrl, master_call, newstate) (master_call)->hold_state = (newstate) ++#endif ++ + struct ie { + /* Maximal count of same IEs at the message (0 - any, 1..n - limited) */ + int max_count; +@@ -249,6 +286,506 @@ + FUNC_SEND(*transmit); + }; + ++/*! ++ * \internal ++ * \brief Encode the channel id information to pass to upper level. ++ * ++ * \param call Q.931 call leg ++ * ++ * \return Encoded channel value. ++ */ ++static int q931_encode_channel(const q931_call *call) ++{ ++ int held_call; ++ int channelno; ++ int ds1no; ++ ++ switch (call->master_call->hold_state) { ++ case Q931_HOLD_STATE_CALL_HELD: ++ case Q931_HOLD_STATE_RETRIEVE_REQ: ++ case Q931_HOLD_STATE_RETRIEVE_IND: ++ held_call = 1 << 18; ++ ++ /* So a -1 does not wipe out the held_call flag. */ ++ channelno = call->channelno & 0xFF; ++ ds1no = call->ds1no & 0xFF; ++ break; ++ default: ++ held_call = 0; ++ channelno = call->channelno; ++ ds1no = call->ds1no; ++ break; ++ } ++ return channelno | (ds1no << 8) | (call->ds1explicit << 16) | (call->cis_call << 17) ++ | held_call; ++} ++ ++/*! ++ * \brief Determine if layer 2 is in PTMP mode. ++ * ++ * \param ctrl D channel controller. ++ * ++ * \retval TRUE if in PTMP mode. ++ * \retval FALSE otherwise. ++ */ ++int q931_is_ptmp(const struct pri *ctrl) ++{ ++ /* Check master control structure */ ++ for (; ctrl->master; ctrl = ctrl->master) { ++ } ++ return ctrl->tei == Q921_TEI_GROUP; ++} ++ ++/*! ++ * \brief Initialize the given struct q931_party_name ++ * ++ * \param name Structure to initialize ++ * ++ * \return Nothing ++ */ ++void q931_party_name_init(struct q931_party_name *name) ++{ ++ name->valid = 0; ++ name->presentation = PRI_PRES_UNAVAILABLE; ++ name->char_set = PRI_CHAR_SET_ISO8859_1; ++ name->str[0] = '\0'; ++} ++ ++/*! ++ * \brief Initialize the given struct q931_party_number ++ * ++ * \param number Structure to initialize ++ * ++ * \return Nothing ++ */ ++void q931_party_number_init(struct q931_party_number *number) ++{ ++ number->valid = 0; ++ number->presentation = PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED; ++ number->plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164; ++ number->str[0] = '\0'; ++} ++ ++/*! ++ * \brief Initialize the given struct q931_party_subaddress ++ * ++ * \param subaddress Structure to initialize ++ * ++ * \return Nothing ++ */ ++void q931_party_subaddress_init(struct q931_party_subaddress *subaddress) ++{ ++ subaddress->valid = 0; ++ subaddress->type = 0; ++ subaddress->odd_even_indicator = 0; ++ subaddress->length = 0; ++ subaddress->data[0] = '\0'; ++} ++ ++/*! ++ * \brief Initialize the given struct q931_party_address ++ * ++ * \param address Structure to initialize ++ * ++ * \return Nothing ++ */ ++void q931_party_address_init(struct q931_party_address *address) ++{ ++ q931_party_number_init(&address->number); ++ q931_party_subaddress_init(&address->subaddress); ++} ++ ++/*! ++ * \brief Initialize the given struct q931_party_id ++ * ++ * \param id Structure to initialize ++ * ++ * \return Nothing ++ */ ++void q931_party_id_init(struct q931_party_id *id) ++{ ++ q931_party_name_init(&id->name); ++ q931_party_number_init(&id->number); ++ q931_party_subaddress_init(&id->subaddress); ++} ++ ++/*! ++ * \brief Initialize the given struct q931_party_redirecting ++ * ++ * \param redirecting Structure to initialize ++ * ++ * \return Nothing ++ */ ++void q931_party_redirecting_init(struct q931_party_redirecting *redirecting) ++{ ++ q931_party_id_init(&redirecting->from); ++ q931_party_id_init(&redirecting->to); ++ q931_party_id_init(&redirecting->orig_called); ++ redirecting->state = Q931_REDIRECTING_STATE_IDLE; ++ redirecting->count = 0; ++ redirecting->orig_reason = PRI_REDIR_UNKNOWN; ++ redirecting->reason = PRI_REDIR_UNKNOWN; ++} ++ ++/*! ++ * \brief Compare the left and right party name. ++ * ++ * \param left Left parameter party name. ++ * \param right Right parameter party name. ++ * ++ * \retval < 0 when left < right. ++ * \retval == 0 when left == right. ++ * \retval > 0 when left > right. ++ */ ++int q931_party_name_cmp(const struct q931_party_name *left, const struct q931_party_name *right) ++{ ++ int cmp; ++ ++ if (!left->valid) { ++ if (!right->valid) { ++ return 0; ++ } ++ return -1; ++ } else if (!right->valid) { ++ return 1; ++ } ++ cmp = left->char_set - right->char_set; ++ if (cmp) { ++ return cmp; ++ } ++ cmp = strcmp(left->str, right->str); ++ if (cmp) { ++ return cmp; ++ } ++ cmp = left->presentation - right->presentation; ++ return cmp; ++} ++ ++/*! ++ * \brief Compare the left and right party number. ++ * ++ * \param left Left parameter party number. ++ * \param right Right parameter party number. ++ * ++ * \retval < 0 when left < right. ++ * \retval == 0 when left == right. ++ * \retval > 0 when left > right. ++ */ ++int q931_party_number_cmp(const struct q931_party_number *left, const struct q931_party_number *right) ++{ ++ int cmp; ++ ++ if (!left->valid) { ++ if (!right->valid) { ++ return 0; ++ } ++ return -1; ++ } else if (!right->valid) { ++ return 1; ++ } ++ cmp = left->plan - right->plan; ++ if (cmp) { ++ return cmp; ++ } ++ cmp = strcmp(left->str, right->str); ++ if (cmp) { ++ return cmp; ++ } ++ cmp = left->presentation - right->presentation; ++ return cmp; ++} ++ ++/*! ++ * \brief Compare the left and right party subaddress. ++ * ++ * \param left Left parameter party subaddress. ++ * \param right Right parameter party subaddress. ++ * ++ * \retval < 0 when left < right. ++ * \retval == 0 when left == right. ++ * \retval > 0 when left > right. ++ */ ++int q931_party_subaddress_cmp(const struct q931_party_subaddress *left, const struct q931_party_subaddress *right) ++{ ++ int cmp; ++ ++ if (!left->valid) { ++ if (!right->valid) { ++ return 0; ++ } ++ return -1; ++ } else if (!right->valid) { ++ return 1; ++ } ++ cmp = left->type - right->type; ++ if (cmp) { ++ return cmp; ++ } ++ cmp = memcmp(left->data, right->data, ++ (left->length < right->length) ? left->length : right->length); ++ if (cmp) { ++ return cmp; ++ } ++ cmp = left->length - right->length; ++ if (cmp) { ++ return cmp; ++ } ++ cmp = left->odd_even_indicator - right->odd_even_indicator; ++ return cmp; ++} ++ ++/*! ++ * \brief Compare the left and right party id. ++ * ++ * \param left Left parameter party id. ++ * \param right Right parameter party id. ++ * ++ * \retval < 0 when left < right. ++ * \retval == 0 when left == right. ++ * \retval > 0 when left > right. ++ */ ++int q931_party_id_cmp(const struct q931_party_id *left, const struct q931_party_id *right) ++{ ++ int cmp; ++ ++ cmp = q931_party_number_cmp(&left->number, &right->number); ++ if (cmp) { ++ return cmp; ++ } ++ cmp = q931_party_subaddress_cmp(&left->subaddress, &right->subaddress); ++ if (cmp) { ++ return cmp; ++ } ++ cmp = q931_party_name_cmp(&left->name, &right->name); ++ return cmp; ++} ++ ++/*! ++ * \brief Copy the Q.931 party name to the PRI party name structure. ++ * ++ * \param pri_name PRI party name structure ++ * \param q931_name Q.931 party name structure ++ * ++ * \return Nothing ++ */ ++void q931_party_name_copy_to_pri(struct pri_party_name *pri_name, const struct q931_party_name *q931_name) ++{ ++ if (q931_name->valid) { ++ pri_name->valid = 1; ++ pri_name->presentation = q931_name->presentation; ++ pri_name->char_set = q931_name->char_set; ++ libpri_copy_string(pri_name->str, q931_name->str, sizeof(pri_name->str)); ++ } else { ++ pri_name->valid = 0; ++ pri_name->presentation = PRI_PRES_UNAVAILABLE; ++ pri_name->char_set = PRI_CHAR_SET_ISO8859_1; ++ pri_name->str[0] = 0; ++ } ++} ++ ++/*! ++ * \brief Copy the Q.931 party number to the PRI party number structure. ++ * ++ * \param pri_number PRI party number structure ++ * \param q931_number Q.931 party number structure ++ * ++ * \return Nothing ++ */ ++void q931_party_number_copy_to_pri(struct pri_party_number *pri_number, const struct q931_party_number *q931_number) ++{ ++ if (q931_number->valid) { ++ pri_number->valid = 1; ++ pri_number->presentation = q931_number->presentation; ++ pri_number->plan = q931_number->plan; ++ libpri_copy_string(pri_number->str, q931_number->str, sizeof(pri_number->str)); ++ } else { ++ pri_number->valid = 0; ++ pri_number->presentation = PRI_PRES_UNAVAILABLE | PRI_PRES_USER_NUMBER_UNSCREENED; ++ pri_number->plan = (PRI_TON_UNKNOWN << 4) | PRI_NPI_E163_E164; ++ pri_number->str[0] = 0; ++ } ++} ++ ++/*! ++ * \brief Copy the Q.931 party subaddress to the PRI party subaddress structure. ++ * ++ * \param pri_subaddress PRI party subaddress structure ++ * \param q931_subaddress Q.931 party subaddress structure ++ * ++ * \return Nothing ++ */ ++void q931_party_subaddress_copy_to_pri(struct pri_party_subaddress *pri_subaddress, const struct q931_party_subaddress *q931_subaddress) ++{ ++ int length; ++ ++ /* ++ * The size of pri_subaddress->data[] is not the same as the size of ++ * q931_subaddress->data[]. ++ */ ++ ++ if (!q931_subaddress->valid) { ++ pri_subaddress->valid = 0; ++ pri_subaddress->type = 0; ++ pri_subaddress->odd_even_indicator = 0; ++ pri_subaddress->length = 0; ++ pri_subaddress->data[0] = '\0'; ++ return; ++ } ++ ++ pri_subaddress->valid = 1; ++ pri_subaddress->type = q931_subaddress->type; ++ pri_subaddress->odd_even_indicator = q931_subaddress->odd_even_indicator; ++ ++ length = q931_subaddress->length; ++ pri_subaddress->length = length; ++ memcpy(pri_subaddress->data, q931_subaddress->data, length); ++ pri_subaddress->data[length] = '\0'; ++} ++ ++/*! ++ * \brief Copy the Q.931 party id to the PRI party id structure. ++ * ++ * \param pri_id PRI party id structure ++ * \param q931_id Q.931 party id structure ++ * ++ * \return Nothing ++ */ ++void q931_party_id_copy_to_pri(struct pri_party_id *pri_id, const struct q931_party_id *q931_id) ++{ ++ q931_party_name_copy_to_pri(&pri_id->name, &q931_id->name); ++ q931_party_number_copy_to_pri(&pri_id->number, &q931_id->number); ++ q931_party_subaddress_copy_to_pri(&pri_id->subaddress, &q931_id->subaddress); ++} ++ ++/*! ++ * \brief Copy the Q.931 redirecting data to the PRI redirecting structure. ++ * ++ * \param pri_redirecting PRI redirecting structure ++ * \param q931_redirecting Q.931 redirecting structure ++ * ++ * \return Nothing ++ */ ++void q931_party_redirecting_copy_to_pri(struct pri_party_redirecting *pri_redirecting, const struct q931_party_redirecting *q931_redirecting) ++{ ++ q931_party_id_copy_to_pri(&pri_redirecting->from, &q931_redirecting->from); ++ q931_party_id_copy_to_pri(&pri_redirecting->to, &q931_redirecting->to); ++ q931_party_id_copy_to_pri(&pri_redirecting->orig_called, ++ &q931_redirecting->orig_called); ++ pri_redirecting->count = q931_redirecting->count; ++ pri_redirecting->orig_reason = q931_redirecting->orig_reason; ++ pri_redirecting->reason = q931_redirecting->reason; ++} ++ ++/*! ++ * \brief Fixup some values in the q931_party_id that may be objectionable by switches. ++ * ++ * \param ctrl D channel controller. ++ * \param id Party ID to tweak. ++ * ++ * \return Nothing ++ */ ++void q931_party_id_fixup(const struct pri *ctrl, struct q931_party_id *id) ++{ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_DMS100: ++ case PRI_SWITCH_ATT4ESS: ++ /* Doesn't like certain presentation types */ ++ if (id->number.valid && !(id->number.presentation & 0x7c)) { ++ /* i.e., If presentation is allowed it must be a network number */ ++ id->number.presentation = PRES_ALLOWED_NETWORK_NUMBER; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++/*! ++ * \brief Determine the overall presentation value for the given party. ++ * ++ * \param id Party to determine the overall presentation value. ++ * ++ * \return Overall presentation value for the given party. ++ */ ++int q931_party_id_presentation(const struct q931_party_id *id) ++{ ++ int number_priority; ++ int number_value; ++ int number_screening; ++ int name_priority; ++ int name_value; ++ ++ /* Determine name presentation priority. */ ++ if (!id->name.valid) { ++ name_value = PRI_PRES_UNAVAILABLE; ++ name_priority = 3; ++ } else { ++ name_value = id->name.presentation & PRI_PRES_RESTRICTION; ++ switch (name_value) { ++ case PRI_PRES_RESTRICTED: ++ name_priority = 0; ++ break; ++ case PRI_PRES_ALLOWED: ++ name_priority = 1; ++ break; ++ case PRI_PRES_UNAVAILABLE: ++ name_priority = 2; ++ break; ++ default: ++ name_value = PRI_PRES_UNAVAILABLE; ++ name_priority = 3; ++ break; ++ } ++ } ++ ++ /* Determine number presentation priority. */ ++ if (!id->number.valid) { ++ number_screening = PRI_PRES_USER_NUMBER_UNSCREENED; ++ number_value = PRI_PRES_UNAVAILABLE; ++ number_priority = 3; ++ } else { ++ number_screening = id->number.presentation & PRI_PRES_NUMBER_TYPE; ++ number_value = id->number.presentation & PRI_PRES_RESTRICTION; ++ switch (number_value) { ++ case PRI_PRES_RESTRICTED: ++ number_priority = 0; ++ break; ++ case PRI_PRES_ALLOWED: ++ number_priority = 1; ++ break; ++ case PRI_PRES_UNAVAILABLE: ++ number_priority = 2; ++ break; ++ default: ++ number_screening = PRI_PRES_USER_NUMBER_UNSCREENED; ++ number_value = PRI_PRES_UNAVAILABLE; ++ number_priority = 3; ++ break; ++ } ++ } ++ ++ /* Select the wining presentation value. */ ++ if (name_priority < number_priority) { ++ number_value = name_value; ++ } ++ ++ return number_value | number_screening; ++} ++ ++static void q931_clr_subcommands(struct pri *ctrl) ++{ ++ ctrl->subcmds.counter_subcmd = 0; ++} ++ ++struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl) ++{ ++ if (ctrl->subcmds.counter_subcmd < PRI_MAX_SUBCOMMANDS) { ++ return &ctrl->subcmds.subcmd[ctrl->subcmds.counter_subcmd++]; ++ } ++ ++ return NULL; ++} ++ + static char *code2str(int code, struct msgtype *codes, int max) + { + int x; +@@ -258,15 +795,18 @@ + return "Unknown"; + } + +-static void call_init(struct q931_call *c) ++static char *pritype(int type) + { +- c->forceinvert = -1; +- c->cr = -1; +- c->slotmap = -1; +- c->channelno = -1; +- c->newcall = 1; +- c->ourcallstate = Q931_CALL_STATE_NULL; +- c->peercallstate = Q931_CALL_STATE_NULL; ++ switch (type) { ++ case PRI_CPE: ++ return "CPE"; ++ break; ++ case PRI_NETWORK: ++ return "NET"; ++ break; ++ default: ++ return "UNKNOWN"; ++ } + } + + static char *binary(int b, int len) { +@@ -280,56 +820,85 @@ + return res; + } + +-static FUNC_RECV(receive_channel_id) ++static int receive_channel_id(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + int x; +- int pos=0; +-#ifdef NO_BRI_SUPPORT +- if (!ie->data[0] & 0x20) { +- pri_error(pri, "!! Not PRI type!?\n"); +- return -1; +- } +-#endif +-#ifndef NOAUTO_CHANNEL_SELECTION_SUPPORT +- if (pri->bri) { +- if (!(ie->data[0] & 3)) +- call->justsignalling = 1; +- else +- call->channelno = ie->data[0] & 3; ++ int pos = 0; ++ int need_extended_channel_octets;/*!< TRUE if octets 3.2 and 3.3 need to be present. */ ++ ++ if (ie->data[0] & 0x08) { ++ call->chanflags = FLAG_EXCLUSIVE; + } else { +- switch (ie->data[0] & 3) { +- case 0: +- call->justsignalling = 1; +- break; +- case 1: +- break; +- default: +- pri_error(pri, "!! Unexpected Channel selection %d\n", ie->data[0] & 3); +- return -1; ++ call->chanflags = FLAG_PREFERRED; ++ } ++ ++ need_extended_channel_octets = 0; ++ if (ie->data[0] & 0x20) { ++ /* PRI encoded interface type */ ++ switch (ie->data[0] & 0x03) { ++ case 0x00: ++ /* No channel */ ++ call->channelno = 0; ++ call->chanflags = FLAG_PREFERRED; ++ break; ++ case 0x01: ++ /* As indicated in following octets */ ++ need_extended_channel_octets = 1; ++ break; ++ case 0x03: ++ /* Any channel */ ++ call->chanflags = FLAG_PREFERRED; ++ break; ++ default: ++ pri_error(ctrl, "!! Unexpected Channel selection %d\n", ie->data[0] & 0x03); ++ return -1; + } ++ } else { ++ /* BRI encoded interface type */ ++ switch (ie->data[0] & 0x03) { ++ case 0x00: ++ /* No channel */ ++ call->channelno = 0; ++ call->chanflags = FLAG_PREFERRED; ++ break; ++ case 0x03: ++ /* Any channel */ ++ call->chanflags = FLAG_PREFERRED; ++ break; ++ default: ++ /* Specified B channel (B1 or B2) */ ++ call->channelno = ie->data[0] & 0x03; ++ break; ++ } + } +-#endif +- if (ie->data[0] & 0x08) +- call->chanflags = FLAG_EXCLUSIVE; +- else +- call->chanflags = FLAG_PREFERRED; ++ + pos++; + if (ie->data[0] & 0x40) { + /* DS1 specified -- stop here */ + call->ds1no = ie->data[1] & 0x7f; + call->ds1explicit = 1; + pos++; +- } else ++ } else { + call->ds1explicit = 0; ++ } + +- if (pos+2 < len) { ++ if (ie->data[0] & 0x04) { ++ /* D channel call. Signaling only. */ ++ call->cis_call = 1; ++ call->chanflags = FLAG_EXCLUSIVE;/* For safety mark this channel as exclusive. */ ++ call->channelno = 0; ++ return 0; ++ } ++ ++ if (need_extended_channel_octets && pos + 2 < len) { + /* More coming */ + if ((ie->data[pos] & 0x0f) != 3) { +- pri_error(pri, "!! Unexpected Channel Type %d\n", ie->data[1] & 0x0f); ++ /* Channel type/mapping is not for B channel units. */ ++ pri_error(ctrl, "!! Unexpected Channel Type %d\n", ie->data[1] & 0x0f); + return -1; + } + if ((ie->data[pos] & 0x60) != 0) { +- pri_error(pri, "!! Invalid CCITT coding %d\n", (ie->data[1] & 0x60) >> 5); ++ pri_error(ctrl, "!! Invalid CCITT coding %d\n", (ie->data[1] & 0x60) >> 5); + return -1; + } + if (ie->data[pos] & 0x10) { +@@ -340,136 +909,167 @@ + call->slotmap <<= 8; + call->slotmap |= ie->data[x + pos]; + } +- return 0; + } else { + pos++; + /* Only expect a particular channel */ + call->channelno = ie->data[pos] & 0x7f; +- if (pri->chan_mapping_logical && call->channelno > 15) ++ if (ctrl->chan_mapping_logical && call->channelno > 15) + call->channelno++; +- return 0; + } +- } else +- return 0; +- return -1; ++ } ++ return 0; + } + +-static FUNC_SEND(transmit_channel_id) ++static int transmit_channel_id(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { +- int pos=0; ++ int pos = 0; + +- + /* We are ready to transmit single IE only */ + if (order > 1) + return 0; +- +- if (call->justsignalling) { +- ie->data[pos++] = 0xac; /* Read the standards docs to figure this out +- ECMA-165 section 7.3 */ ++ ++ if (call->cis_call) { ++ /* ++ * Read the standards docs to figure this out. ++ * Q.SIG ECMA-165 section 7.3 ++ * ITU Q.931 section 4.5.13 ++ */ ++ ie->data[pos++] = ctrl->bri ? 0x8c : 0xac; + return pos + 2; + } +- ++ + /* Start with standard stuff */ +- if (pri->switchtype == PRI_SWITCH_GR303_TMC) ++ if (ctrl->switchtype == PRI_SWITCH_GR303_TMC) + ie->data[pos] = 0x69; +- else if (pri->bri) { ++ else if (ctrl->bri) { + ie->data[pos] = 0x80; +- if (call->channelno > -1) +- ie->data[pos] |= (call->channelno & 0x3); +- } else +- ie->data[pos] = 0xa1; +- /* Add exclusive flag if necessary */ +- if (call->chanflags & FLAG_EXCLUSIVE) ++ ie->data[pos] |= (call->channelno & 0x3); ++ } else { ++ /* PRI */ ++ if (call->slotmap != -1 || (call->chanflags & FLAG_WHOLE_INTERFACE)) { ++ /* Specified channel */ ++ ie->data[pos] = 0xa1; ++ } else if (call->channelno < 0 || call->channelno == 0xff) { ++ /* Any channel */ ++ ie->data[pos] = 0xa3; ++ } else if (!call->channelno) { ++ /* No channel */ ++ ie->data[pos] = 0xa0; ++ } else { ++ /* Specified channel */ ++ ie->data[pos] = 0xa1; ++ } ++ } ++ if (call->chanflags & FLAG_EXCLUSIVE) { ++ /* Channel is exclusive */ + ie->data[pos] |= 0x08; +- else if (!(call->chanflags & FLAG_PREFERRED)) { ++ } else if (!call->chanflags) { + /* Don't need this IE */ + return 0; + } + +- if (((pri->switchtype != PRI_SWITCH_QSIG) && (call->ds1no > 0)) || call->ds1explicit) { +- /* Note that we are specifying the identifier */ ++ if (!ctrl->bri && (((ctrl->switchtype != PRI_SWITCH_QSIG) && (call->ds1no > 0)) || call->ds1explicit)) { ++ /* We are specifying the interface. Octet 3.1 */ + ie->data[pos++] |= 0x40; +- /* We need to use the Channel Identifier Present thingy. Just specify it and we're done */ + ie->data[pos++] = 0x80 | call->ds1no; +- } else +- pos++; ++ } else { ++ ++pos; ++ } + +- if (pri->bri) +- return pos + 2; ++ if (!ctrl->bri && (ie->data[0] & 0x03) == 0x01 /* Specified channel */ ++ && !(call->chanflags & FLAG_WHOLE_INTERFACE)) { ++ /* The 3.2 and 3.3 octets need to be present */ ++ ie->data[pos] = 0x83; ++ if (call->slotmap != -1) { ++ int octet; + +- if ((call->channelno > -1) || (call->slotmap != -1)) { +- /* We'll have the octet 8.2 and 8.3's present */ +- ie->data[pos++] = 0x83; +- if (call->channelno > -1) { ++ /* We have to send a channel map */ ++ ie->data[pos++] |= 0x10; ++ for (octet = 3; octet--;) { ++ ie->data[pos++] = (call->slotmap >> (8 * octet)) & 0xff; ++ } ++ } else { + /* Channel number specified */ +- if (pri->chan_mapping_logical && call->channelno > 16) ++ ++pos; ++ if (ctrl->chan_mapping_logical && call->channelno > 16) { + ie->data[pos++] = 0x80 | (call->channelno - 1); +- else ++ } else { + ie->data[pos++] = 0x80 | call->channelno; +- return pos + 2; ++ } + } +- /* We have to send a channel map */ +- if (call->slotmap != -1) { +- ie->data[pos-1] |= 0x10; +- ie->data[pos++] = (call->slotmap & 0xff0000) >> 16; +- ie->data[pos++] = (call->slotmap & 0xff00) >> 8; +- ie->data[pos++] = (call->slotmap & 0xff); +- return pos + 2; +- } + } +- if (call->ds1no > 0) { +- /* We're done */ +- return pos + 2; +- } +- pri_error(pri, "!! No channel map, no channel, and no ds1? What am I supposed to identify?\n"); +- return -1; ++ ++ return pos + 2; + } + +-static FUNC_DUMP(dump_channel_id) ++static void dump_channel_id(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- int pos=0; ++ int pos; + int x; +- int res = 0; +- static const char* msg_chan_sel[] = { +- "No channel selected", "B1 channel", "B2 channel","Any channel selected", +- "No channel selected", "As indicated in following octets", "Reserved","Any channel selected" ++ int res; ++ ++ static const char *msg_chan_sel[] = { ++ "No channel selected", "B1 channel", "B2 channel", "Any channel selected", ++ "No channel selected", "As indicated in following octets", "Reserved", "Any channel selected" + }; + +- pri_message(pri, "%c Channel ID (len=%2d) [ Ext: %d IntID: %s %s Spare: %d %s Dchan: %d\n", +- prefix, len, (ie->data[0] & 0x80) ? 1 : 0, (ie->data[0] & 0x40) ? "Explicit" : "Implicit", +- (ie->data[0] & 0x20) ? "PRI" : "Other", (ie->data[0] & 0x10) ? 1 : 0, +- (ie->data[0] & 0x08) ? "Exclusive" : "Preferred", (ie->data[0] & 0x04) ? 1 : 0); +- pri_message(pri, "%c ChanSel: %s\n", +- prefix, msg_chan_sel[(ie->data[0] & 0x3) + ((ie->data[0]>>3) & 0x4)]); +- pos++; +- len--; +- if (ie->data[0] & 0x40) { ++ pri_message(ctrl, ++ "%c Channel ID (len=%2d) [ Ext: %d IntID: %s %s Spare: %d %s Dchan: %d\n", ++ prefix, len, ++ (ie->data[0] & 0x80) ? 1 : 0, ++ (ie->data[0] & 0x40) ? "Explicit" : "Implicit", ++ (ie->data[0] & 0x20) ? "Other(PRI)" : "BRI", ++ (ie->data[0] & 0x10) ? 1 : 0, ++ (ie->data[0] & 0x08) ? "Exclusive" : "Preferred", ++ (ie->data[0] & 0x04) ? 1 : 0); ++ pri_message(ctrl, "%c ChanSel: %s\n", ++ prefix, msg_chan_sel[(ie->data[0] & 0x03) | ((ie->data[0] >> 3) & 0x04)]); ++ pos = 1; ++ len -= 2; ++ if (ie->data[0] & 0x40) { + /* Explicitly defined DS1 */ +- pri_message(pri, "%c Ext: %d DS1 Identifier: %d \n", prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f); +- pos++; ++ do { ++ pri_message(ctrl, "%c Ext: %d DS1 Identifier: %d \n", ++ prefix, (ie->data[pos] & 0x80) >> 7, ie->data[pos] & 0x7f); ++ ++pos; ++ } while (!(ie->data[pos - 1] & 0x80) && pos < len); + } else { + /* Implicitly defined DS1 */ + } +- if (pos+2 < len) { ++ if (pos < len) { + /* Still more information here */ +- pri_message(pri, "%c Ext: %d Coding: %d %s Specified Channel Type: %d\n", +- prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5, +- (ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f); +- if (!(ie->data[pos] & 0x10)) { ++ pri_message(ctrl, ++ "%c Ext: %d Coding: %d %s Specified Channel Type: %d\n", ++ prefix, (ie->data[pos] & 0x80) >> 7, (ie->data[pos] & 60) >> 5, ++ (ie->data[pos] & 0x10) ? "Slot Map" : "Number", ie->data[pos] & 0x0f); ++ ++pos; ++ } ++ if (pos < len) { ++ if (!(ie->data[pos - 1] & 0x10)) { + /* Number specified */ +- pos++; +- pri_message(pri, "%c Ext: %d Channel: %d ]\n", prefix, (ie->data[pos] & 0x80) >> 7, +- (ie->data[pos]) & 0x7f); ++ do { ++ pri_message(ctrl, ++ "%c Ext: %d Channel: %d Type: %s%c\n", ++ prefix, (ie->data[pos] & 0x80) >> 7, ++ (ie->data[pos]) & 0x7f, pritype(ctrl->localtype), ++ (pos + 1 < len) ? ' ' : ']'); ++ ++pos; ++ } while (pos < len); + } else { +- pos++; + /* Map specified */ +- for (x=0;x<3;x++) { ++ res = 0; ++ x = 0; ++ do { + res <<= 8; + res |= ie->data[pos++]; +- } +- pri_message(pri, "%c Map: %s ]\n", prefix, binary(res, 24)); ++ ++x; ++ } while (pos < len); ++ pri_message(ctrl, "%c Map len: %d Map: %s ]\n", prefix, ++ x, binary(res, x << 3)); + } +- } else pri_message(pri, " ]\n"); ++ } else { ++ pri_message(ctrl, " ]\n"); ++ } + } + + static char *ri2str(int ri) +@@ -482,20 +1082,20 @@ + return code2str(ri, ris, sizeof(ris) / sizeof(ris[0])); + } + +-static FUNC_DUMP(dump_restart_indicator) ++static void dump_restart_indicator(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- pri_message(pri, "%c Restart Indentifier (len=%2d) [ Ext: %d Spare: %d Resetting %s (%d) ]\n", ++ pri_message(ctrl, "%c Restart Indentifier (len=%2d) [ Ext: %d Spare: %d Resetting %s (%d) ]\n", + prefix, len, (ie->data[0] & 0x80) >> 7, (ie->data[0] & 0x78) >> 3, ri2str(ie->data[0] & 0x7), ie->data[0] & 0x7); + } + +-static FUNC_RECV(receive_restart_indicator) ++static int receive_restart_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + /* Pretty simple */ + call->ri = ie->data[0] & 0x7; + return 0; + } + +-static FUNC_SEND(transmit_restart_indicator) ++static int transmit_restart_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { + /* Pretty simple */ + switch(call->ri) { +@@ -509,7 +1109,7 @@ + ie->data[0] = 0xA0 | (call->ri & 0x7); + break; + default: +- pri_error(pri, "!! Invalid restart indicator value %d\n", call->ri); ++ pri_error(ctrl, "!! Invalid restart indicator value %d\n", call->ri); + return-1; + } + return 3; +@@ -607,16 +1207,16 @@ + return code2str(proto, protos, sizeof(protos) / sizeof(protos[0])); + } + +-static FUNC_DUMP(dump_bearer_capability) ++static void dump_bearer_capability(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { + int pos=2; +- pri_message(pri, "%c Bearer Capability (len=%2d) [ Ext: %d Q.931 Std: %d Info transfer capability: %s (%d)\n", ++ pri_message(ctrl, "%c Bearer Capability (len=%2d) [ Ext: %d Q.931 Std: %d Info transfer capability: %s (%d)\n", + prefix, len, (ie->data[0] & 0x80 ) >> 7, (ie->data[0] & 0x60) >> 5, cap2str(ie->data[0] & 0x1f), (ie->data[0] & 0x1f)); +- pri_message(pri, "%c Ext: %d Trans mode/rate: %s (%d)\n", prefix, (ie->data[1] & 0x80) >> 7, mode2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); ++ pri_message(ctrl, "%c Ext: %d Trans mode/rate: %s (%d)\n", prefix, (ie->data[1] & 0x80) >> 7, mode2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); + + /* octet 4.1 exists iff mode/rate is multirate */ + if ((ie->data[1] & 0x7f) == 0x18) { +- pri_message(pri, "%c Ext: %d Transfer rate multiplier: %d x 64\n", prefix, (ie->data[2] & 0x80) >> 7, ie->data[2] & 0x7f); ++ pri_message(ctrl, "%c Ext: %d Transfer rate multiplier: %d x 64\n", prefix, (ie->data[2] & 0x80) >> 7, ie->data[2] & 0x7f); + pos++; + } + +@@ -632,7 +1232,7 @@ + too, so we have to do the same for binary compatability */ + u_int8_t layer1 = ie->data[pos] & 0x7f; + +- pri_message(pri, "%c User information layer 1: %s (%d)\n", ++ pri_message(ctrl, "%c User information layer 1: %s (%d)\n", + prefix, l12str(layer1), layer1); + pos++; + +@@ -640,7 +1240,7 @@ + if (pos < len && !(ie->data[pos-1] & 0x80)) { + int ra = ie->data[pos] & 0x7f; + +- pri_message(pri, "%c Async: %d, Negotiation: %d, " ++ pri_message(ctrl, "%c Async: %d, Negotiation: %d, " + "User rate: %s (%#x)\n", + prefix, + ra & PRI_RATE_ADAPT_ASYNC ? 1 : 0, +@@ -654,7 +1254,7 @@ + if (pos < len && !(ie->data[pos-1] & 0x80)) { + u_int8_t data = ie->data[pos]; + if (layer1 == PRI_LAYER_1_ITU_RATE_ADAPT) { +- pri_message(pri, "%c Intermediate rate: %s (%d), " ++ pri_message(ctrl, "%c Intermediate rate: %s (%d), " + "NIC on Tx: %d, NIC on Rx: %d, " + "Flow control on Tx: %d, " + "Flow control on Rx: %d\n", +@@ -665,7 +1265,7 @@ + (data & 0x04)?1:0, + (data & 0x02)?1:0); + } else if (layer1 == PRI_LAYER_1_V120_RATE_ADAPT) { +- pri_message(pri, "%c Hdr: %d, Multiframe: %d, Mode: %d, " ++ pri_message(ctrl, "%c Hdr: %d, Multiframe: %d, Mode: %d, " + "LLI negot: %d, Assignor: %d, " + "In-band neg: %d\n", prefix, + (data & 0x40)?1:0, +@@ -675,7 +1275,8 @@ + (data & 0x04)?1:0, + (data & 0x02)?1:0); + } else { +- pri_message(pri, "%c Unknown octet 5b: 0x%x\n", data ); ++ pri_message(ctrl, "%c Unknown octet 5b: 0x%x\n", ++ prefix, data); + } + pos++; + } +@@ -688,7 +1289,7 @@ + const char *parity[] = {"Odd","?","Even","None", + "zero","one","?","?"}; + +- pri_message(pri, "%c Stop bits: %s, data bits: %s, " ++ pri_message(ctrl, "%c Stop bits: %s, data bits: %s, " + "parity: %s\n", prefix, + stop_bits[(data & 0x60) >> 5], + data_bits[(data & 0x18) >> 3], +@@ -700,7 +1301,7 @@ + /* octet 5d? */ + if (pos < len && !(ie->data[pos-1] & 0x80)) { + u_int8_t data = ie->data[pos]; +- pri_message(pri, "%c Duplex mode: %d, modem type: %d\n", ++ pri_message(ctrl, "%c Duplex mode: %d, modem type: %d\n", + prefix, (data & 0x40) ? 1 : 0,data & 0x3F); + pos++; + } +@@ -710,7 +1311,7 @@ + /* Look for octet 6; this is identified by bits 5,6 == 10 */ + if (pos < len && + (ie->data[pos] & 0x60) == 0x40) { +- pri_message(pri, "%c User information layer 2: %s (%d)\n", ++ pri_message(ctrl, "%c User information layer 2: %s (%d)\n", + prefix, l22str(ie->data[pos] & 0x1f), + ie->data[pos] & 0x1f); + pos++; +@@ -718,7 +1319,7 @@ + + /* Look for octet 7; this is identified by bits 5,6 == 11 */ + if (pos < len && (ie->data[pos] & 0x60) == 0x60) { +- pri_message(pri, "%c User information layer 3: %s (%d)\n", ++ pri_message(ctrl, "%c User information layer 3: %s (%d)\n", + prefix, l32str(ie->data[pos] & 0x1f), + ie->data[pos] & 0x1f); + pos++; +@@ -730,18 +1331,18 @@ + proto = ((ie->data[pos] & 0xF) << 4 ) | + (ie->data[pos+1] & 0xF); + +- pri_message(pri, "%c Network layer: 0x%x\n", prefix, ++ pri_message(ctrl, "%c Network layer: 0x%x\n", prefix, + proto ); + pos += 2; + } + } + } + +-static FUNC_RECV(receive_bearer_capability) ++static int receive_bearer_capability(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + int pos=2; + if (ie->data[0] & 0x60) { +- pri_error(pri, "!! non-standard Q.931 standard field\n"); ++ pri_error(ctrl, "!! non-standard Q.931 standard field\n"); + return -1; + } + call->transcapability = ie->data[0] & 0x1f; +@@ -788,7 +1389,7 @@ + return 0; + } + +-static FUNC_SEND(transmit_bearer_capability) ++static int transmit_bearer_capability(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { + int tc; + int pos; +@@ -797,20 +1398,20 @@ + if(order > 1) + return 0; + +- tc = call->transcapability; +- if (pri->subchannel && !pri->bri) { ++ if (ctrl->subchannel && !ctrl->bri) { + /* Bearer capability is *hard coded* in GR-303 */ + ie->data[0] = 0x88; + ie->data[1] = 0x90; + return 4; + } +- +- if (call->justsignalling) { ++ ++ if (call->cis_call) { + ie->data[0] = 0xa8; + ie->data[1] = 0x80; + return 4; + } +- ++ ++ tc = call->transcapability; + ie->data[0] = 0x80 | tc; + ie->data[1] = call->transmoderate | 0x80; + +@@ -820,7 +1421,7 @@ + ie->data[pos++] = call->transmultiple | 0x80; + } + +- if ((tc & PRI_TRANS_CAP_DIGITAL) && (pri->switchtype == PRI_SWITCH_EUROISDN_E1) && ++ if ((tc & PRI_TRANS_CAP_DIGITAL) && (ctrl->switchtype == PRI_SWITCH_EUROISDN_E1) && + (call->transmoderate == TRANS_MODE_PACKET)) { + /* Apparently EuroISDN switches don't seem to like user layer 2/3 */ + return 4; +@@ -833,7 +1434,7 @@ + + if (call->transmoderate != TRANS_MODE_PACKET) { + /* If you have an AT&T 4ESS, you don't send any more info */ +- if ((pri->switchtype != PRI_SWITCH_ATT4ESS) && (call->userl1 > -1)) { ++ if ((ctrl->switchtype != PRI_SWITCH_ATT4ESS) && (call->userl1 > -1)) { + ie->data[pos++] = call->userl1 | 0x80; /* XXX Ext bit? XXX */ + if (call->userl1 == PRI_LAYER_1_ITU_RATE_ADAPT) { + ie->data[pos++] = call->rateadaption | 0x80; +@@ -908,6 +1509,30 @@ + return code2str(plan, plans, sizeof(plans) / sizeof(plans[0])); + } + ++/* Calling Party Category (Definitions from Q.763) */ ++static char *cpc2str(int plan) ++{ ++ static struct msgtype plans[] = { ++ { 0, "Unknown Source" }, ++ { 1, "Operator French" }, ++ { 2, "Operator English" }, ++ { 3, "Operator German" }, ++ { 4, "Operator Russian" }, ++ { 5, "Operator Spanish" }, ++ { 6, "Mut Agree Chinese" }, ++ { 7, "Mut Agreement" }, ++ { 8, "Mut Agree Japanese" }, ++ { 9, "National Operator" }, ++ { 10, "Ordinary Toll Caller" }, ++ { 11, "Priority Toll Caller" }, ++ { 12, "Data Call" }, ++ { 13, "Test Call" }, ++ { 14, "Spare" }, ++ { 15, "Pay Phone" }, ++ }; ++ return code2str(plan, plans, ARRAY_LEN(plans)); ++} ++ + char *pri_pres2str(int pres) + { + static struct msgtype press[] = { +@@ -934,51 +1559,134 @@ + num[len] = 0; + } + +-static FUNC_DUMP(dump_called_party_number) ++static void q931_get_subaddr_specific(unsigned char *num, int maxlen, unsigned char *src, int len, char oddflag) + { +- unsigned char cnum[256]; ++ /* User Specified */ ++ int x; ++ char *ptr = (char *) num; + +- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); +- pri_message(pri, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n", +- prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum); ++ if (len <= 0) { ++ num[0] = '\0'; ++ return; ++ } ++ ++ if (((len * 2) + 1) > maxlen) { ++ len = (maxlen / 2) - 1; ++ } ++ ++ for (x = 0; x < (len - 1); ++x) { ++ ptr += sprintf(ptr, "%02x", src[x]); ++ } ++ ++ if (oddflag) { ++ /* ODD */ ++ sprintf(ptr, "%01x", (src[len - 1]) >> 4); ++ } else { ++ /* EVEN */ ++ sprintf(ptr, "%02x", src[len - 1]); ++ } + } + +-static FUNC_DUMP(dump_called_party_subaddr) ++static int transmit_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_party_subaddress *q931_subaddress, int msgtype, q931_ie *ie, int offset, int len, int order) + { ++ size_t datalen; ++ ++ if (!q931_subaddress->valid) { ++ return 0; ++ } ++ ++ datalen = q931_subaddress->length; ++ if (!q931_subaddress->type) { ++ /* 0 = NSAP */ ++ /* 0 = Odd/Even indicator */ ++ ie->data[0] = 0x80; ++ } else { ++ /* 2 = User Specified */ ++ ie->data[0] = q931_subaddress->odd_even_indicator ? 0xA8 : 0xA0; ++ } ++ memcpy(ie->data + offset, q931_subaddress->data, datalen); ++ ++ return datalen + (offset + 2); ++} ++ ++static int receive_subaddr_helper(int full_ie, struct pri *ctrl, struct q931_party_subaddress *q931_subaddress, int msgtype, q931_ie *ie, int offset, int len) ++{ ++ if (len <= 0) { ++ return -1; ++ } ++ ++ q931_subaddress->valid = 1; ++ q931_subaddress->length = len; ++ /* type: 0 = NSAP, 2 = User Specified */ ++ q931_subaddress->type = ((ie->data[0] & 0x70) >> 4); ++ q931_subaddress->odd_even_indicator = (ie->data[0] & 0x08) ? 1 : 0; ++ q931_get_number(q931_subaddress->data, sizeof(q931_subaddress->data), ++ ie->data + offset, len); ++ ++ return 0; ++} ++ ++static void dump_subaddr_helper(int full_ie, struct pri *ctrl, q931_ie *ie, int offset, int len, int datalen, char prefix, const char *named) ++{ + unsigned char cnum[256]; +- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); +- pri_message(pri, "%c Called Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", +- prefix, len, ie->data[0] >> 7, ++ ++ if (!(ie->data[0] & 0x70)) { ++ /* NSAP */ ++ q931_get_number(cnum, sizeof(cnum), ie->data + offset, datalen); ++ } else { ++ /* User Specified */ ++ q931_get_subaddr_specific(cnum, sizeof(cnum), ie->data + offset, datalen, ++ ie->data[0] & 0x08); ++ } ++ ++ pri_message(ctrl, ++ "%c %s Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", ++ prefix, named, len, ie->data[0] >> 7, + subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, + (ie->data[0] & 0x08) >> 3, cnum); + } + +-static FUNC_DUMP(dump_calling_party_number) ++static void dump_called_party_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { + unsigned char cnum[256]; ++ ++ q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); ++ pri_message(ctrl, "%c Called Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d) '%s' ]\n", ++ prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f, cnum); ++} ++ ++static void dump_called_party_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) ++{ ++ dump_subaddr_helper(full_ie, ctrl, ie, 1 , len, len - 3, prefix, "Called"); ++} ++ ++static void dump_calling_party_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) ++{ ++ unsigned char cnum[256]; + if (ie->data[0] & 0x80) + q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); + else + q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); +- pri_message(pri, "%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); ++ pri_message(ctrl, "%c Calling Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)\n", prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); + if (ie->data[0] & 0x80) +- pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum); ++ pri_message(ctrl, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(0), 0, cnum); + else +- pri_message(pri, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum); ++ pri_message(ctrl, "%c Presentation: %s (%d) '%s' ]\n", prefix, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, cnum); + } + +-static FUNC_DUMP(dump_calling_party_subaddr) ++static void dump_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- unsigned char cnum[256]; +- q931_get_number(cnum, sizeof(cnum), ie->data + 1, len - 3); +- pri_message(pri, "%c Calling Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", +- prefix, len, ie->data[0] >> 7, +- subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, +- (ie->data[0] & 0x08) >> 3, cnum); ++ dump_subaddr_helper(full_ie, ctrl, ie, 1 , len, len - 3, prefix, "Calling"); + } + +-static FUNC_DUMP(dump_redirecting_number) ++static void dump_calling_party_category(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { ++ pri_message(ctrl, "%c Calling Party Category (len=%2d) [ Ext: %d Cat: %s (%d) ]\n", ++ prefix, len, ie->data[0] >> 7, cpc2str(ie->data[0] & 0x0F), ie->data[0] & 0x0F); ++} ++ ++static void dump_redirecting_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) ++{ + unsigned char cnum[256]; + int i = 0; + /* To follow Q.931 (4.5.1), we must search for start of octet 4 by +@@ -986,172 +1694,369 @@ + do { + switch(i) { + case 0: /* Octet 3 */ +- pri_message(pri, "%c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)", ++ pri_message(ctrl, "%c Redirecting Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)", + prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); + break; + case 1: /* Octet 3a */ +- pri_message(pri, "\n%c Ext: %d Presentation: %s (%d)", ++ pri_message(ctrl, "\n%c Ext: %d Presentation: %s (%d)", + prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); + break; + case 2: /* Octet 3b */ +- pri_message(pri, "\n%c Ext: %d Reason: %s (%d)", ++ pri_message(ctrl, "\n%c Ext: %d Reason: %s (%d)", + prefix, ie->data[2] >> 7, redirection_reason2str(ie->data[2] & 0x7f), ie->data[2] & 0x7f); + break; + } +- } +- while(!(ie->data[i++]& 0x80)); ++ } while(!(ie->data[i++]& 0x80)); + q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i); +- pri_message(pri, " '%s' ]\n", cnum); ++ pri_message(ctrl, " '%s' ]\n", cnum); + } + +-static FUNC_DUMP(dump_connected_number) ++static void dump_redirection_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { + unsigned char cnum[256]; + int i = 0; + /* To follow Q.931 (4.5.1), we must search for start of octet 4 by + walking through all bytes until one with ext bit (8) set to 1 */ + do { ++ switch (i) { ++ case 0: /* Octet 3 */ ++ pri_message(ctrl, ++ "%c Redirection Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)", ++ prefix, len, ie->data[0] >> 7, ++ ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, ++ npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); ++ break; ++ case 1: /* Octet 3a */ ++ pri_message(ctrl, "\n%c Ext: %d Presentation: %s (%d)", ++ prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); ++ break; ++ } ++ } while (!(ie->data[i++] & 0x80)); ++ q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i); ++ pri_message(ctrl, " '%s' ]\n", cnum); ++} ++ ++static int receive_connected_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) ++{ ++ int i = 0; ++ ++ call->connected_number_in_message = 1; ++ call->remote_id.number.valid = 1; ++ call->remote_id.number.presentation = ++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by ++ walking through all bytes until one with ext bit (8) set to 1 */ ++ do { ++ switch (i) { ++ case 0: ++ call->remote_id.number.plan = ie->data[i] & 0x7f; ++ break; ++ case 1: ++ /* Keep only the presentation and screening fields */ ++ call->remote_id.number.presentation = ++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE); ++ break; ++ } ++ } while (!(ie->data[i++] & 0x80)); ++ q931_get_number((unsigned char *) call->remote_id.number.str, sizeof(call->remote_id.number.str), ie->data + i, ie->len - i); ++ ++ return 0; ++} ++ ++static int transmit_connected_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) ++{ ++ size_t datalen; ++ ++ if (!call->local_id.number.valid) { ++ return 0; ++ } ++ ++ datalen = strlen(call->local_id.number.str); ++ ie->data[0] = call->local_id.number.plan; ++ ie->data[1] = 0x80 | call->local_id.number.presentation; ++ memcpy(ie->data + 2, call->local_id.number.str, datalen); ++ return datalen + (2 + 2); ++} ++ ++static void dump_connected_number(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) ++{ ++ unsigned char cnum[256]; ++ int i = 0; ++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by ++ walking through all bytes until one with ext bit (8) set to 1 */ ++ do { + switch(i) { + case 0: /* Octet 3 */ +- pri_message(pri, "%c Connected Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)", ++ pri_message(ctrl, "%c Connected Number (len=%2d) [ Ext: %d TON: %s (%d) NPI: %s (%d)", + prefix, len, ie->data[0] >> 7, ton2str((ie->data[0] >> 4) & 0x07), (ie->data[0] >> 4) & 0x07, npi2str(ie->data[0] & 0x0f), ie->data[0] & 0x0f); + break; + case 1: /* Octet 3a */ +- pri_message(pri, "\n%c Ext: %d Presentation: %s (%d)", ++ pri_message(ctrl, "\n%c Ext: %d Presentation: %s (%d)", + prefix, ie->data[1] >> 7, pri_pres2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); + break; + } +- } +- while(!(ie->data[i++]& 0x80)); ++ } while(!(ie->data[i++]& 0x80)); + q931_get_number(cnum, sizeof(cnum), ie->data + i, ie->len - i); +- pri_message(pri, " '%s' ]\n", cnum); ++ pri_message(ctrl, " '%s' ]\n", cnum); + } + ++static int receive_connected_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) ++{ ++ if (len < 3) { ++ return -1; ++ } + +-static FUNC_RECV(receive_redirecting_number) ++ return receive_subaddr_helper(full_ie, ctrl, &call->remote_id.subaddress, msgtype, ie, ++ 1, len - 3); ++} ++ ++static int transmit_connected_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { ++ return transmit_subaddr_helper(full_ie, ctrl, &call->local_id.subaddress, msgtype, ie, ++ 1, len, order); ++} ++ ++static void dump_connected_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) ++{ ++ dump_subaddr_helper(full_ie, ctrl, ie, 1 , len, len - 3, prefix, "Connected"); ++} ++ ++static int receive_redirecting_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) ++{ + int i = 0; + ++ call->redirecting_number_in_message = 1; ++ call->redirecting.from.number.valid = 1; ++ call->redirecting.from.number.presentation = ++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ call->redirecting.reason = PRI_REDIR_UNKNOWN; + /* To follow Q.931 (4.5.1), we must search for start of octet 4 by + walking through all bytes until one with ext bit (8) set to 1 */ + do { +- switch(i) { ++ switch (i) { + case 0: +- call->redirectingplan = ie->data[i] & 0x7f; ++ call->redirecting.from.number.plan = ie->data[i] & 0x7f; + break; + case 1: +- call->redirectingpres = ie->data[i] & 0x7f; ++ /* Keep only the presentation and screening fields */ ++ call->redirecting.from.number.presentation = ++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE); + break; + case 2: +- call->redirectingreason = ie->data[i] & 0x0f; ++ call->redirecting.reason = ie->data[i] & 0x0f; + break; + } +- } +- while(!(ie->data[i++] & 0x80)); +- q931_get_number((unsigned char *) call->redirectingnum, sizeof(call->redirectingnum), ie->data + i, ie->len - i); ++ } while (!(ie->data[i++] & 0x80)); ++ q931_get_number((unsigned char *) call->redirecting.from.number.str, sizeof(call->redirecting.from.number.str), ie->data + i, ie->len - i); + return 0; + } + +-static FUNC_SEND(transmit_redirecting_number) ++static int transmit_redirecting_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { ++ size_t datalen; ++ + if (order > 1) + return 0; +- if (call->redirectingnum && *call->redirectingnum) { +- ie->data[0] = call->redirectingplan; +- ie->data[1] = call->redirectingpres; +- ie->data[2] = (call->redirectingreason & 0x0f) | 0x80; +- memcpy(ie->data + 3, call->redirectingnum, strlen(call->redirectingnum)); +- return strlen(call->redirectingnum) + 3 + 2; ++ if (!call->redirecting.from.number.valid) { ++ return 0; + } +- return 0; ++ ++ datalen = strlen(call->redirecting.from.number.str); ++ ie->data[0] = call->redirecting.from.number.plan; ++#if 1 ++ /* ETSI and Q.952 do not define the screening field */ ++ ie->data[1] = call->redirecting.from.number.presentation & PRI_PRES_RESTRICTION; ++#else ++ /* Q.931 defines the screening field */ ++ ie->data[1] = call->redirecting.from.number.presentation; ++#endif ++ ie->data[2] = (call->redirecting.reason & 0x0f) | 0x80; ++ memcpy(ie->data + 3, call->redirecting.from.number.str, datalen); ++ return datalen + (3 + 2); + } + +-static FUNC_DUMP(dump_redirecting_subaddr) ++static void dump_redirecting_subaddr(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- unsigned char cnum[256]; +- q931_get_number(cnum, sizeof(cnum), ie->data + 2, len - 4); +- pri_message(pri, "%c Redirecting Sub-Address (len=%2d) [ Ext: %d Type: %s (%d) O: %d '%s' ]\n", +- prefix, len, ie->data[0] >> 7, +- subaddrtype2str((ie->data[0] & 0x70) >> 4), (ie->data[0] & 0x70) >> 4, +- (ie->data[0] & 0x08) >> 3, cnum); ++ dump_subaddr_helper(full_ie, ctrl, ie, 2, len, len - 4, prefix, "Redirecting"); + } + +-static FUNC_RECV(receive_calling_party_subaddr) ++static int receive_redirection_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { +- /* copy digits to call->callingsubaddr */ +- q931_get_number((unsigned char *) call->callingsubaddr, sizeof(call->callingsubaddr), ie->data + 1, len - 3); ++ int i = 0; ++ ++ call->redirection_number.valid = 1; ++ call->redirection_number.presentation = ++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by ++ walking through all bytes until one with ext bit (8) set to 1 */ ++ do { ++ switch (i) { ++ case 0: ++ call->redirection_number.plan = ie->data[i] & 0x7f; ++ break; ++ case 1: ++ /* Keep only the presentation and screening fields */ ++ call->redirection_number.presentation = ++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE); ++ break; ++ } ++ } while (!(ie->data[i++] & 0x80)); ++ q931_get_number((unsigned char *) call->redirection_number.str, sizeof(call->redirection_number.str), ie->data + i, ie->len - i); + return 0; + } + +-static FUNC_RECV(receive_called_party_number) ++static int transmit_redirection_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { +- /* copy digits to call->callednum */ +- q931_get_number((unsigned char *) call->callednum, sizeof(call->callednum), ie->data + 1, len - 3); +- call->calledplan = ie->data[0] & 0x7f; +- return 0; ++ size_t datalen; ++ ++ if (order > 1) { ++ return 0; ++ } ++ if (!call->redirection_number.valid) { ++ return 0; ++ } ++ ++ datalen = strlen(call->redirection_number.str); ++ ie->data[0] = call->redirection_number.plan; ++ ie->data[1] = (call->redirection_number.presentation & PRI_PRES_RESTRICTION) | 0x80; ++ memcpy(ie->data + 2, call->redirection_number.str, datalen); ++ return datalen + (2 + 2); + } + +-static FUNC_SEND(transmit_called_party_number) ++static int receive_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { +- ie->data[0] = 0x80 | call->calledplan; +- if (*call->callednum) +- memcpy(ie->data + 1, call->callednum, strlen(call->callednum)); +- return strlen(call->callednum) + 3; ++ if (len < 3) { ++ return -1; ++ } ++ ++ return receive_subaddr_helper(full_ie, ctrl, &call->remote_id.subaddress, msgtype, ie, ++ 1, len - 3); + } + +-static FUNC_RECV(receive_calling_party_number) ++static int transmit_calling_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { +- u_int8_t *data; +- size_t length; +- +- if (ie->data[0] & 0x80) { +- data = ie->data + 1; +- length = len - 3; +- call->callerpres = 0; /* PI presentation allowed SI user-provided, not screened */ +- } else { +- data = ie->data + 2; +- length = len - 4; +- call->callerpres = ie->data[1] & 0x7f; ++ return transmit_subaddr_helper(full_ie, ctrl, &call->local_id.subaddress, msgtype, ie, ++ 1, len, order); ++} ++ ++static int receive_called_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) ++{ ++ if (len < 3) { ++ return -1; + } ++ return receive_subaddr_helper(full_ie, ctrl, &call->called.subaddress, msgtype, ie, 1, ++ len - 3); ++} + +- if (call->callerpres == PRES_ALLOWED_NETWORK_NUMBER || +- call->callerpres == PRES_PROHIB_NETWORK_NUMBER) { +- q931_get_number((u_int8_t *)call->callerani, sizeof(call->callerani), data, length); +- call->callerplanani = ie->data[0] & 0x7f; ++static int transmit_called_party_subaddr(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) ++{ ++ return transmit_subaddr_helper(full_ie, ctrl, &call->called.subaddress, msgtype, ie, ++ 1, len, order); ++} + +- if (!*call->callernum) { /*Copy ANI to CallerID if CallerID is not already set */ +- libpri_copy_string(call->callernum, call->callerani, sizeof(call->callernum)); +- call->callerplan = call->callerplanani; ++static int receive_called_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) ++{ ++ size_t called_len; ++ size_t max_len; ++ char *called_end; ++ ++ if (len < 3) { ++ return -1; ++ } ++ ++ call->called.number.valid = 1; ++ call->called.number.plan = ie->data[0] & 0x7f; ++ if (msgtype == Q931_SETUP) { ++ q931_get_number((unsigned char *) call->called.number.str, ++ sizeof(call->called.number.str), ie->data + 1, len - 3); ++ } else if (call->ourcallstate == Q931_CALL_STATE_OVERLAP_RECEIVING) { ++ /* ++ * Since we are receiving overlap digits now, we need to append ++ * them to any previously received digits in call->called.number.str. ++ */ ++ called_len = strlen(call->called.number.str); ++ called_end = call->called.number.str + called_len; ++ max_len = (sizeof(call->called.number.str) - 1) - called_len; ++ if (max_len < len - 3) { ++ called_len = max_len; ++ } else { ++ called_len = len - 3; + } +- +- } else { +- q931_get_number((u_int8_t *)call->callernum, sizeof(call->callernum), data, length); +- call->callerplan = ie->data[0] & 0x7f; ++ strncat(called_end, (char *) ie->data + 1, called_len); + } + ++ q931_get_number((unsigned char *) call->overlap_digits, sizeof(call->overlap_digits), ++ ie->data + 1, len - 3); + return 0; + } + +-static FUNC_SEND(transmit_calling_party_number) ++static int transmit_called_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { +- ie->data[0] = call->callerplan; +- ie->data[1] = 0x80 | call->callerpres; +- if (*call->callernum) +- memcpy(ie->data + 2, call->callernum, strlen(call->callernum)); +- return strlen(call->callernum) + 4; ++ size_t datalen; ++ ++ if (!call->called.number.valid) { ++ return 0; ++ } ++ ++ datalen = strlen(call->overlap_digits); ++ ie->data[0] = 0x80 | call->called.number.plan; ++ memcpy(ie->data + 1, call->overlap_digits, datalen); ++ return datalen + (1 + 2); + } + +-static FUNC_DUMP(dump_user_user) ++static int receive_calling_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { ++ int i = 0; ++ ++ call->remote_id.number.valid = 1; ++ call->remote_id.number.presentation = ++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ /* To follow Q.931 (4.5.1), we must search for start of octet 4 by ++ walking through all bytes until one with ext bit (8) set to 1 */ ++ do { ++ switch (i) { ++ case 0: ++ call->remote_id.number.plan = ie->data[i] & 0x7f; ++ break; ++ case 1: ++ /* Keep only the presentation and screening fields */ ++ call->remote_id.number.presentation = ++ ie->data[i] & (PRI_PRES_RESTRICTION | PRI_PRES_NUMBER_TYPE); ++ break; ++ } ++ } while (!(ie->data[i++] & 0x80)); ++ q931_get_number((unsigned char *) call->remote_id.number.str, ++ sizeof(call->remote_id.number.str), ie->data + i, ie->len - i); ++ ++ return 0; ++} ++ ++static int transmit_calling_party_number(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) ++{ ++ size_t datalen; ++ ++ if (!call->local_id.number.valid) { ++ return 0; ++ } ++ ++ datalen = strlen(call->local_id.number.str); ++ ie->data[0] = call->local_id.number.plan; ++ ie->data[1] = 0x80 | call->local_id.number.presentation; ++ memcpy(ie->data + 2, call->local_id.number.str, datalen); ++ return datalen + (2 + 2); ++} ++ ++static void dump_user_user(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) ++{ + int x; +- pri_message(pri, "%c User-User Information (len=%2d) [", prefix, len); ++ pri_message(ctrl, "%c User-User Information (len=%2d) [", prefix, len); + for (x=0;x<ie->len;x++) +- pri_message(pri, " %02x", ie->data[x] & 0x7f); +- pri_message(pri, " ]\n"); ++ pri_message(ctrl, " %02x", ie->data[x] & 0x7f); ++ pri_message(ctrl, " ]\n"); + } + + +-static FUNC_RECV(receive_user_user) ++static int receive_user_user(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + call->useruserprotocoldisc = ie->data[0] & 0xff; + if (call->useruserprotocoldisc == 4) /* IA5 */ +@@ -1159,7 +2064,7 @@ + return 0; + } + +-static FUNC_SEND(transmit_user_user) ++static int transmit_user_user(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { + int datalen = strlen(call->useruserinfo); + if (datalen > 0) { +@@ -1180,6 +2085,29 @@ + return 0; + } + ++static void dump_change_status(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) ++{ ++ int x; ++ ++ pri_message(ctrl, "%c Change Status Information (len=%2d) [", prefix, len); ++ for (x=0; x<ie->len; x++) { ++ pri_message(ctrl, " %02x", ie->data[x] & 0x7f); ++ } ++ pri_message(ctrl, " ]\n"); ++} ++ ++static int receive_change_status(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) ++{ ++ call->changestatus = ie->data[0] & 0x0f; ++ return 0; ++} ++ ++static int transmit_change_status(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) ++{ ++ ie->data[0] = 0xc0 | call->changestatus; ++ return 3; ++} ++ + static char *prog2str(int prog) + { + static struct msgtype progs[] = { +@@ -1222,47 +2150,83 @@ + return code2str(loc, locs, sizeof(locs) / sizeof(locs[0])); + } + +-static FUNC_DUMP(dump_progress_indicator) ++static void dump_progress_indicator(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- pri_message(pri, "%c Progress Indicator (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n", ++ pri_message(ctrl, "%c Progress Indicator (len=%2d) [ Ext: %d Coding: %s (%d) 0: %d Location: %s (%d)\n", + prefix, len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5, + (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf); +- pri_message(pri, "%c Ext: %d Progress Description: %s (%d) ]\n", ++ pri_message(ctrl, "%c Ext: %d Progress Description: %s (%d) ]\n", + prefix, ie->data[1] >> 7, prog2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f); + } + +-static FUNC_RECV(receive_display) ++static int receive_display(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + unsigned char *data; ++ ++ switch (msgtype) { ++ case Q931_SETUP: ++ case Q931_CONNECT: ++ /* ++ * Only keep the display message on SETUP and CONNECT messages ++ * as the remote name. ++ */ ++ break; ++ default: ++ return 0; ++ } ++ ++ call->remote_id.name.valid = 1; ++ + data = ie->data; + if (data[0] & 0x80) { + /* Skip over character set */ + data++; + len--; + } +- q931_get_number((unsigned char *) call->callername, sizeof(call->callername), data, len - 2); ++ call->remote_id.name.char_set = PRI_CHAR_SET_ISO8859_1; ++ ++ q931_get_number((unsigned char *) call->remote_id.name.str, sizeof(call->remote_id.name.str), data, len - 2); ++ if (call->remote_id.name.str[0]) { ++ call->remote_id.name.presentation = PRI_PRES_ALLOWED; ++ } else { ++ call->remote_id.name.presentation = PRI_PRES_RESTRICTED; ++ } + return 0; + } + +-static FUNC_SEND(transmit_display) ++static int transmit_display(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { ++ size_t datalen; + int i; +- +- if ((pri->switchtype == PRI_SWITCH_QSIG) || +- ((pri->switchtype == PRI_SWITCH_EUROISDN_E1) && (pri->localtype == PRI_CPE)) || +- !call->callername[0]) +- return 0; + + i = 0; +- if(pri->switchtype != PRI_SWITCH_EUROISDN_E1) { ++ ++ if (!call->local_id.name.valid || !call->local_id.name.str[0]) { ++ return 0; ++ } ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_QSIG: ++ /* Q.SIG supports names */ ++ return 0; ++ case PRI_SWITCH_EUROISDN_E1: ++ case PRI_SWITCH_EUROISDN_T1: ++ if (ctrl->localtype == PRI_CPE) { ++ return 0; ++ } ++ break; ++ default: ++ /* Prefix name with character set indicator. */ + ie->data[0] = 0xb1; + ++i; ++ break; + } +- memcpy(ie->data + i, call->callername, strlen(call->callername)); +- return 2 + i + strlen(call->callername); ++ ++ datalen = strlen(call->local_id.name.str); ++ memcpy(ie->data + i, call->local_id.name.str, datalen); ++ return 2 + i + datalen; + } + +-static FUNC_RECV(receive_progress_indicator) ++static int receive_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + call->progloc = ie->data[0] & 0xf; + call->progcode = (ie->data[0] & 0x60) >> 5; +@@ -1298,153 +2262,204 @@ + call->progressmask |= PRI_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER; + break; + default: +- pri_error(pri, "XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f)); ++ pri_error(ctrl, "XXX Invalid Progress indicator value received: %02x\n",(ie->data[1] & 0x7f)); + break; + } + return 0; + } + +-static FUNC_SEND(transmit_facility) ++static void q931_apdu_timeout(void *data); ++ ++static int transmit_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { +- struct apdu_event *tmp; +- int i = 0; ++ struct apdu_event **prev; ++ struct apdu_event *cur; ++ int apdu_len; + +- for (tmp = call->apdus; tmp; tmp = tmp->next) { +- if ((tmp->message == msgtype) && !tmp->sent) ++ for (prev = &call->apdus, cur = call->apdus; ++ cur; ++ prev = &cur->next, cur = cur->next) { ++ if (!cur->sent && cur->message == msgtype) { + break; ++ } + } +- +- if (!tmp) /* No APDU found */ ++ if (!cur) { ++ /* No APDU found */ + return 0; ++ } + +- if (tmp->apdu_len > 235) { /* TODO: find out how much space we can use */ +- pri_message(pri, "Requested APDU (%d bytes) is too long\n", tmp->apdu_len); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "Adding facility ie contents to send in %s message:\n", ++ msg2str(msgtype)); ++ facility_decode_dump(ctrl, cur->apdu, cur->apdu_len); ++ } ++ ++ if (len < cur->apdu_len) { ++ pri_error(ctrl, ++ "Could not fit facility ie in message. Size needed:%d Available space:%d\n", ++ cur->apdu_len + 2, len); ++ ++ /* Remove APDU from list. */ ++ *prev = cur->next; ++ ++ if (cur->response.callback) { ++ /* Indicate to callback that the APDU had a problem getting sent. */ ++ cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL); ++ } ++ ++ free(cur); + return 0; + } +- +- memcpy(&ie->data[i], tmp->apdu, tmp->apdu_len); +- i += tmp->apdu_len; +- tmp->sent = 1; + +- return i + 2; ++ memcpy(ie->data, cur->apdu, cur->apdu_len); ++ apdu_len = cur->apdu_len; ++ cur->sent = 1; ++ ++ if (cur->response.callback && cur->response.timeout_time) { ++ int duration; ++ ++ if (0 < cur->response.timeout_time) { ++ /* Sender specified timeout duration. */ ++ duration = cur->response.timeout_time; ++ } else { ++ /* Sender wants to use the typical timeout duration. */ ++ duration = ctrl->timers[PRI_TIMER_T_RESPONSE]; ++ } ++ cur->timer = pri_schedule_event(ctrl, duration, q931_apdu_timeout, cur); ++ if (!cur->timer) { ++ /* Remove APDU from list. */ ++ *prev = cur->next; ++ ++ /* Indicate to callback that the APDU had a problem getting sent. */ ++ cur->response.callback(APDU_CALLBACK_REASON_ERROR, ctrl, call, cur, NULL); ++ ++ free(cur); ++ } ++ } else if (!cur->timer) { ++ /* Remove APDU from list. */ ++ *prev = cur->next; ++ free(cur); ++ } ++ ++ return apdu_len + 2; + } + +-static FUNC_RECV(receive_facility) ++static int receive_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { +- int i = 0; +- int protocol, next_protocol; +- struct rose_component *comp = NULL; +- enum { +- Q932_STATE_NFE, /* Network facility extension */ +- Q932_STATE_NPP, /* Network protocol profile */ +- Q932_STATE_INTERPRETATION, /* Interpretation component */ +- Q932_STATE_SERVICE /* Service component(s) */ +- } state = Q932_STATE_SERVICE; +-#define Q932_HANDLE_PROC(component, my_state, name, handler) \ +- case component: \ +- if(state > my_state) { \ +- pri_error(pri, "!! %s component received in wrong place\n"); \ +- break; \ +- } \ +- state = my_state; \ +- if (pri->debug) \ +- pri_message(pri, "Handle Q.932 %s component\n", name); \ +- (handler)(pri, call, ie, comp->data, comp->len); \ +- break; +-#define Q932_HANDLE_NULL(component, my_state, name, handle) \ +- case component: \ +- if(state > my_state) { \ +- pri_error(pri, "!! %s component received in wrong place\n"); \ +- break; \ +- } \ +- state = my_state; \ +- if (pri->debug & PRI_DEBUG_APDU) \ +- pri_message(pri, "Q.932 %s component is not handled\n", name); \ +- break; +- +- if (ie->len < 1) ++ /* Delay processing facility ie's till after all other ie's are processed. */ ++ if (MAX_FACILITY_IES <= ctrl->facility.count) { ++ pri_message(ctrl, "!! Too many facility ie's to delay.\n"); + return -1; ++ } ++ /* Make sure we have enough room for the protocol profile ie octet(s) */ ++ if (ie->data + ie->len < ie->data + 2) { ++ return -1; ++ } + +- switch(next_protocol = protocol = (ie->data[i] & 0x1f)) { +- case Q932_PROTOCOL_CMIP: +- case Q932_PROTOCOL_ACSE: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "!! Don't know how to handle Q.932 Protocol Profile of type 0x%X\n", protocol); ++ /* Save the facility ie location for delayed decode. */ ++ ctrl->facility.ie[ctrl->facility.count] = ie; ++ ctrl->facility.codeset[ctrl->facility.count] = Q931_IE_CODESET((unsigned) full_ie); ++ ++ctrl->facility.count; ++ return 0; ++} ++ ++static int process_facility(struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie) ++{ ++ struct fac_extension_header header; ++ struct rose_message rose; ++ const unsigned char *pos; ++ const unsigned char *end; ++ ++ pos = ie->data; ++ end = ie->data + ie->len; ++ ++ /* Make sure we have enough room for the protocol profile ie octet(s) */ ++ if (end < pos + 2) { + return -1; ++ } ++ switch (*pos & Q932_PROTOCOL_MASK) { ++ case Q932_PROTOCOL_ROSE: + case Q932_PROTOCOL_EXTENSIONS: +- state = Q932_STATE_NFE; +- next_protocol = Q932_PROTOCOL_ROSE; + break; +- case Q932_PROTOCOL_ROSE: +- break; + default: +- pri_error(pri, "!! Invalid Q.932 Protocol Profile of type 0x%X received\n", protocol); ++ case Q932_PROTOCOL_CMIP: ++ case Q932_PROTOCOL_ACSE: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, ++ "!! Don't know how to handle Q.932 Protocol Profile type 0x%X\n", ++ *pos & Q932_PROTOCOL_MASK); ++ } + return -1; + } +- /* Service indicator octet - Just ignore for now */ +- if (!(ie->data[i] & 0x80)) +- i++; +- i++; ++ if (!(*pos & 0x80)) { ++ /* DMS-100 Service indicator octet - Just ignore for now */ ++ ++pos; ++ } ++ ++pos; + +- if (ie->len < 3) ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ asn1_dump(ctrl, pos, end); ++ } ++ ++ pos = fac_dec_extension_header(ctrl, pos, end, &header); ++ if (!pos) { + return -1; +- +- while ((i+1 < ie->len) && (&ie->data[i])) { +- comp = (struct rose_component*)&ie->data[i]; +- if (comp->type) { +- if (protocol == Q932_PROTOCOL_EXTENSIONS) { +- switch (comp->type) { +- Q932_HANDLE_NULL(COMP_TYPE_INTERPRETATION, Q932_STATE_INTERPRETATION, "Interpretation", NULL); +- Q932_HANDLE_NULL(COMP_TYPE_NFE, Q932_STATE_NFE, "Network facility extensions", NULL); +- Q932_HANDLE_NULL(COMP_TYPE_NETWORK_PROTOCOL_PROFILE, Q932_STATE_NPP, "Network protocol profile", NULL); +- default: +- protocol = next_protocol; +- break; +- } +- } +- switch (protocol) { +- case Q932_PROTOCOL_ROSE: +- switch (comp->type) { +- Q932_HANDLE_PROC(COMP_TYPE_INVOKE, Q932_STATE_SERVICE, "ROSE Invoke", rose_invoke_decode); +- Q932_HANDLE_PROC(COMP_TYPE_RETURN_RESULT, Q932_STATE_SERVICE, "ROSE return result", rose_return_result_decode); +- Q932_HANDLE_PROC(COMP_TYPE_RETURN_ERROR, Q932_STATE_SERVICE, "ROSE return error", rose_return_error_decode); +- Q932_HANDLE_PROC(COMP_TYPE_REJECT, Q932_STATE_SERVICE, "ROSE reject", rose_reject_decode); +- default: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "Don't know how to handle ROSE component of type 0x%X\n", comp->type); +- break; +- } +- break; +- case Q932_PROTOCOL_CMIP: +- switch (comp->type) { +- default: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "Don't know how to handle CMIP component of type 0x%X\n", comp->type); +- break; +- } +- break; +- case Q932_PROTOCOL_ACSE: +- switch (comp->type) { +- default: +- if (pri->debug & PRI_DEBUG_APDU) +- pri_message(pri, "Don't know how to handle ACSE component of type 0x%X\n", comp->type); +- break; +- } +- break; +- } ++ } ++ if (header.npp_present) { ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, ++ "!! Don't know how to handle Network Protocol Profile type 0x%X\n", ++ header.npp); + } +- i += (comp->len + 2); ++ return -1; + } +-#undef Q932_HANDLE + ++ pos = rose_decode(ctrl, pos, end, &rose); ++ if (!pos) { ++ return -1; ++ } ++ switch (rose.type) { ++ case ROSE_COMP_TYPE_INVOKE: ++ rose_handle_invoke(ctrl, call, msgtype, ie, &header, &rose.component.invoke); ++ break; ++ case ROSE_COMP_TYPE_RESULT: ++ rose_handle_result(ctrl, call, msgtype, ie, &header, &rose.component.result); ++ break; ++ case ROSE_COMP_TYPE_ERROR: ++ rose_handle_error(ctrl, call, msgtype, ie, &header, &rose.component.error); ++ break; ++ case ROSE_COMP_TYPE_REJECT: ++ rose_handle_reject(ctrl, call, msgtype, ie, &header, &rose.component.reject); ++ break; ++ default: ++ return -1; ++ } + return 0; + } + +-static FUNC_SEND(transmit_progress_indicator) ++static void q931_handle_facilities(struct pri *ctrl, q931_call *call, int msgtype) + { ++ unsigned idx; ++ unsigned codeset; ++ unsigned full_ie; ++ q931_ie *ie; ++ ++ for (idx = 0; idx < ctrl->facility.count; ++idx) { ++ ie = ctrl->facility.ie[idx]; ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ codeset = ctrl->facility.codeset[idx]; ++ full_ie = Q931_FULL_IE(codeset, ie->ie); ++ pri_message(ctrl, "-- Delayed processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); ++ } ++ process_facility(ctrl, call, msgtype, ie); ++ } ++} ++ ++static int transmit_progress_indicator(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) ++{ + int code, mask; + /* Can't send progress indicator on GR-303 -- EVER! */ +- if (pri->subchannel && !pri->bri) ++ if (ctrl->subchannel && !ctrl->bri) + return 0; + if (call->progressmask > 0) { + if (call->progressmask & (mask = PRI_PROG_CALL_NOT_E2E_ISDN)) +@@ -1467,7 +2482,7 @@ + code = Q931_PROG_INTERWORKING_NO_RELEASE_POST_ANSWER; + else { + code = 0; +- pri_error(pri, "XXX Undefined progress bit: %x\n", call->progressmask); ++ pri_error(ctrl, "XXX Undefined progress bit: %x\n", call->progressmask); + } + if (code) { + ie->data[0] = 0x80 | (call->progcode << 5) | (call->progloc); +@@ -1479,82 +2494,139 @@ + /* Leave off */ + return 0; + } +-static FUNC_SEND(transmit_call_state) ++static int transmit_call_state(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { +- if (call->ourcallstate > -1 ) { ++ ie->data[0] = Q931_CALL_STATE_NULL; ++ switch (call->ourcallstate) { ++ case Q931_CALL_STATE_NULL: ++ case Q931_CALL_STATE_CALL_INITIATED: ++ case Q931_CALL_STATE_OVERLAP_SENDING: ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_CALL_PRESENT: ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ case Q931_CALL_STATE_CONNECT_REQUEST: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_ACTIVE: ++ case Q931_CALL_STATE_DISCONNECT_REQUEST: ++ case Q931_CALL_STATE_DISCONNECT_INDICATION: ++ case Q931_CALL_STATE_SUSPEND_REQUEST: ++ case Q931_CALL_STATE_RESUME_REQUEST: ++ case Q931_CALL_STATE_RELEASE_REQUEST: ++ case Q931_CALL_STATE_CALL_ABORT: ++ case Q931_CALL_STATE_OVERLAP_RECEIVING: ++ case Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE: ++ case Q931_CALL_STATE_RESTART_REQUEST: ++ case Q931_CALL_STATE_RESTART: + ie->data[0] = call->ourcallstate; +- return 3; ++ break; ++ case Q931_CALL_STATE_NOT_SET: ++ break; + } +- return 0; ++ return 3; + } + +-static FUNC_RECV(receive_call_state) ++static int receive_call_state(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + call->sugcallstate = ie->data[0] & 0x3f; + return 0; + } + +-static char *callstate2str(int callstate) ++/*! ++ * \brief Convert the internal Q.931 call state to a string. ++ * ++ * \param callstate Internal Q.931 call state. ++ * ++ * \return String equivalent of the given Q.931 call state. ++ */ ++const char *q931_call_state_str(enum Q931_CALL_STATE callstate) + { + static struct msgtype callstates[] = { +- { 0, "Null" }, +- { 1, "Call Initiated" }, +- { 2, "Overlap sending" }, +- { 3, "Outgoing call Proceeding" }, +- { 4, "Call Delivered" }, +- { 6, "Call Present" }, +- { 7, "Call Received" }, +- { 8, "Connect Request" }, +- { 9, "Incoming Call Proceeding" }, +- { 10, "Active" }, +- { 11, "Disconnect Request" }, +- { 12, "Disconnect Indication" }, +- { 15, "Suspend Request" }, +- { 17, "Resume Request" }, +- { 19, "Release Request" }, +- { 22, "Call Abort" }, +- { 25, "Overlap Receiving" }, +- { 61, "Restart Request" }, +- { 62, "Restart" }, ++/* *INDENT-OFF* */ ++ { Q931_CALL_STATE_NULL, "Null" }, ++ { Q931_CALL_STATE_CALL_INITIATED, "Call Initiated" }, ++ { Q931_CALL_STATE_OVERLAP_SENDING, "Overlap Sending" }, ++ { Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING, "Outgoing Call Proceeding" }, ++ { Q931_CALL_STATE_CALL_DELIVERED, "Call Delivered" }, ++ { Q931_CALL_STATE_CALL_PRESENT, "Call Present" }, ++ { Q931_CALL_STATE_CALL_RECEIVED, "Call Received" }, ++ { Q931_CALL_STATE_CONNECT_REQUEST, "Connect Request" }, ++ { Q931_CALL_STATE_INCOMING_CALL_PROCEEDING, "Incoming Call Proceeding" }, ++ { Q931_CALL_STATE_ACTIVE, "Active" }, ++ { Q931_CALL_STATE_DISCONNECT_REQUEST, "Disconnect Request" }, ++ { Q931_CALL_STATE_DISCONNECT_INDICATION, "Disconnect Indication" }, ++ { Q931_CALL_STATE_SUSPEND_REQUEST, "Suspend Request" }, ++ { Q931_CALL_STATE_RESUME_REQUEST, "Resume Request" }, ++ { Q931_CALL_STATE_RELEASE_REQUEST, "Release Request" }, ++ { Q931_CALL_STATE_CALL_ABORT, "Call Abort" }, ++ { Q931_CALL_STATE_OVERLAP_RECEIVING, "Overlap Receiving" }, ++ { Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE, "Call Independent Service" }, ++ { Q931_CALL_STATE_RESTART_REQUEST, "Restart Request" }, ++ { Q931_CALL_STATE_RESTART, "Restart" }, ++ { Q931_CALL_STATE_NOT_SET, "Not set. Internal use only." }, ++/* *INDENT-ON* */ + }; +- return code2str(callstate, callstates, sizeof(callstates) / sizeof(callstates[0])); ++ return code2str(callstate, callstates, ARRAY_LEN(callstates)); + } + +-static FUNC_DUMP(dump_call_state) ++/*! ++ * \internal ++ * \brief Convert the Q.932 supplementary hold state to a string. ++ * ++ * \param state Q.932 supplementary hold state. ++ * ++ * \return String equivalent of the given hold state. ++ */ ++static const char *q931_hold_state_str(enum Q931_HOLD_STATE state) + { +- pri_message(pri, "%c Call State (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d)\n", ++ static struct msgtype hold_states[] = { ++/* *INDENT-OFF* */ ++ { Q931_HOLD_STATE_IDLE, "Idle" }, ++ { Q931_HOLD_STATE_HOLD_REQ, "Hold Request" }, ++ { Q931_HOLD_STATE_HOLD_IND, "Hold Indication" }, ++ { Q931_HOLD_STATE_CALL_HELD, "Call Held" }, ++ { Q931_HOLD_STATE_RETRIEVE_REQ, "Retrieve Request" }, ++ { Q931_HOLD_STATE_RETRIEVE_IND, "Retrieve Indication" }, ++/* *INDENT-ON* */ ++ }; ++ return code2str(state, hold_states, ARRAY_LEN(hold_states)); ++} ++ ++static void dump_call_state(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) ++{ ++ pri_message(ctrl, "%c Call State (len=%2d) [ Ext: %d Coding: %s (%d) Call state: %s (%d)\n", + prefix, len, ie->data[0] >> 7, coding2str((ie->data[0] & 0xC0) >> 6), (ie->data[0] & 0xC0) >> 6, +- callstate2str(ie->data[0] & 0x3f), ie->data[0] & 0x3f); ++ q931_call_state_str(ie->data[0] & 0x3f), ie->data[0] & 0x3f); + } + +-static FUNC_DUMP(dump_call_identity) ++static void dump_call_identity(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { + int x; +- pri_message(pri, "%c Call Identity (len=%2d) [ ", prefix, len); ++ pri_message(ctrl, "%c Call Identity (len=%2d) [ ", prefix, len); + for (x=0;x<ie->len;x++) +- pri_message(pri, "0x%02X ", ie->data[x]); +- pri_message(pri, " ]\n"); ++ pri_message(ctrl, "0x%02X ", ie->data[x]); ++ pri_message(ctrl, " ]\n"); + } + +-static FUNC_DUMP(dump_time_date) ++static void dump_time_date(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- pri_message(pri, "%c Time Date (len=%2d) [ ", prefix, len); ++ pri_message(ctrl, "%c Time Date (len=%2d) [ ", prefix, len); + if (ie->len > 0) +- pri_message(pri, "%02d", ie->data[0]); ++ pri_message(ctrl, "%02d", ie->data[0]); + if (ie->len > 1) +- pri_message(pri, "-%02d", ie->data[1]); ++ pri_message(ctrl, "-%02d", ie->data[1]); + if (ie->len > 2) +- pri_message(pri, "-%02d", ie->data[2]); ++ pri_message(ctrl, "-%02d", ie->data[2]); + if (ie->len > 3) +- pri_message(pri, " %02d", ie->data[3]); ++ pri_message(ctrl, " %02d", ie->data[3]); + if (ie->len > 4) +- pri_message(pri, ":%02d", ie->data[4]); ++ pri_message(ctrl, ":%02d", ie->data[4]); + if (ie->len > 5) +- pri_message(pri, ":%02d", ie->data[5]); +- pri_message(pri, " ]\n"); ++ pri_message(ctrl, ":%02d", ie->data[5]); ++ pri_message(ctrl, " ]\n"); + } + +-static FUNC_DUMP(dump_keypad_facility) ++static void dump_keypad_facility(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { + char tmp[64]; + +@@ -1563,10 +2635,10 @@ + + memcpy(tmp, ie->data, ie->len); + tmp[ie->len] = '\0'; +- pri_message(pri, "%c Keypad Facility (len=%2d) [ %s ]\n", prefix, ie->len, tmp ); ++ pri_message(ctrl, "%c Keypad Facility (len=%2d) [ %s ]\n", prefix, ie->len, tmp ); + } + +-static FUNC_RECV(receive_keypad_facility) ++static int receive_keypad_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + int mylen; + +@@ -1584,27 +2656,19 @@ + return 0; + } + +-static FUNC_SEND(transmit_keypad_facility) ++static int transmit_keypad_facility(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { + int sublen; + + sublen = strlen(call->keypad_digits); +- +- if (sublen > 32) { +- sublen = 32; +- call->keypad_digits[32] = '\0'; +- } +- + if (sublen) { +- libpri_copy_string((char *)ie->data, (char *)call->keypad_digits, sizeof(call->keypad_digits)); +- /* Make sure we clear the field */ +- call->keypad_digits[0] = '\0'; ++ libpri_copy_string((char *) ie->data, call->keypad_digits, sizeof(call->keypad_digits)); + return sublen + 2; + } else + return 0; + } + +-static FUNC_DUMP(dump_display) ++static void dump_display(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { + int x, y; + char *buf = malloc(len + 1); +@@ -1618,7 +2682,7 @@ + for (y=x; x<ie->len; x++) + buf[x] = ie->data[x] & 0x7f; + buf[x] = '\0'; +- pri_message(pri, "%c Display (len=%2d) %s[ %s ]\n", prefix, ie->len, tmp, &buf[y]); ++ pri_message(ctrl, "%c Display (len=%2d) %s[ %s ]\n", prefix, ie->len, tmp, &buf[y]); + free(buf); + } + } +@@ -1626,10 +2690,10 @@ + #define CHECK_OVERFLOW(limit) \ + if (tmpptr - tmp + limit >= sizeof(tmp)) { \ + *tmpptr = '\0'; \ +- pri_message(pri, "%s", tmpptr = tmp); \ ++ pri_message(ctrl, "%s", tmpptr = tmp); \ + } + +-static void dump_ie_data(struct pri *pri, unsigned char *c, int len) ++static void dump_ie_data(struct pri *ctrl, unsigned char *c, int len) + { + static char hexs[16] = "0123456789ABCDEF"; + char tmp[1024], *tmpptr; +@@ -1665,47 +2729,54 @@ + if (lastascii) + *tmpptr++ = '\''; + *tmpptr = '\0'; +- pri_message(pri, "%s", tmp); ++ pri_message(ctrl, "%s", tmp); + } + +-static FUNC_DUMP(dump_facility) ++static void dump_facility(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- int dataat = (ie->data[0] & 0x80) ? 1 : 2; +- pri_message(pri, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie)); +- dump_ie_data(pri, ie->data, ie->len); +- pri_message(NULL, " ]\n"); ++ pri_message(ctrl, "%c Facility (len=%2d, codeset=%d) [ ", prefix, len, Q931_IE_CODESET(full_ie)); ++ dump_ie_data(ctrl, ie->data, ie->len); ++ pri_message(ctrl, " ]\n"); ++#if 0 /* Lets not dump parse of facility contents here anymore. */ ++ /* ++ * The ASN.1 decode dump has already been done when the facility ie was added to the outgoing ++ * message or the ASN.1 decode dump will be done when the facility ie is processed on incoming ++ * messages. This dump is redundant and very noisy. ++ */ + if (ie->len > 1) { +- pri_message(pri, "PROTOCOL %02X\n", ie->data[0] & ASN1_TYPE_MASK); +- asn1_dump(pri, &ie->data[dataat], ie->len - dataat); ++ int dataat = (ie->data[0] & 0x80) ? 1 : 2; ++ ++ pri_message(ctrl, "PROTOCOL %02X\n", ie->data[0] & Q932_PROTOCOL_MASK); ++ asn1_dump(ctrl, ie->data + dataat, ie->data + ie->len); + } +- ++#endif /* Lets not dump parse of facility contents here anymore. */ + } + +-static FUNC_DUMP(dump_network_spec_fac) ++static void dump_network_spec_fac(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- pri_message(pri, "%c Network-Specific Facilities (len=%2d) [ ", prefix, ie->len); ++ pri_message(ctrl, "%c Network-Specific Facilities (len=%2d) [ ", prefix, ie->len); + if (ie->data[0] == 0x00) { +- pri_message(pri, "%s", code2str(ie->data[1], facilities, sizeof(facilities) / sizeof(facilities[0]))); ++ pri_message(ctrl, "%s", code2str(ie->data[1], facilities, ARRAY_LEN(facilities))); + } + else +- dump_ie_data(pri, ie->data, ie->len); +- pri_message(pri, " ]\n"); ++ dump_ie_data(ctrl, ie->data, ie->len); ++ pri_message(ctrl, " ]\n"); + } + +-static FUNC_RECV(receive_network_spec_fac) ++static int receive_network_spec_fac(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + return 0; + } + +-static FUNC_SEND(transmit_network_spec_fac) ++static int transmit_network_spec_fac(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { + /* We are ready to transmit single IE only */ + if (order > 1) + return 0; + +- if (pri->nsf != PRI_NSF_NONE) { ++ if (ctrl->nsf != PRI_NSF_NONE) { + ie->data[0] = 0x00; +- ie->data[1] = pri->nsf; ++ ie->data[1] = ctrl->nsf; + return 4; + } + /* Leave off */ +@@ -1732,13 +2803,13 @@ + return code2str(cause, causeclasses, sizeof(causeclasses) / sizeof(causeclasses[0])); + } + +-static FUNC_DUMP(dump_cause) ++static void dump_cause(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { + int x; +- pri_message(pri, "%c Cause (len=%2d) [ Ext: %d Coding: %s (%d) Spare: %d Location: %s (%d)\n", ++ pri_message(ctrl, "%c Cause (len=%2d) [ Ext: %d Coding: %s (%d) Spare: %d Location: %s (%d)\n", + prefix, len, ie->data[0] >> 7, coding2str((ie->data[0] & 0x60) >> 5), (ie->data[0] & 0x60) >> 5, + (ie->data[0] & 0x10) >> 4, loc2str(ie->data[0] & 0xf), ie->data[0] & 0xf); +- pri_message(pri, "%c Ext: %d Cause: %s (%d), class = %s (%d) ]\n", ++ pri_message(ctrl, "%c Ext: %d Cause: %s (%d), class = %s (%d) ]\n", + prefix, (ie->data[1] >> 7), pri_cause2str(ie->data[1] & 0x7f), ie->data[1] & 0x7f, + pri_causeclass2str((ie->data[1] & 0x7f) >> 4), (ie->data[1] & 0x7f) >> 4); + if (ie->len < 3) +@@ -1747,29 +2818,29 @@ + switch(ie->data[1] & 0x7f) { + case PRI_CAUSE_IE_NONEXIST: + for (x=2;x<ie->len;x++) +- pri_message(pri, "%c Cause data %d: %02x (%d, %s IE)\n", prefix, x-1, ie->data[x], ie->data[x], ie2str(ie->data[x])); ++ pri_message(ctrl, "%c Cause data %d: %02x (%d, %s IE)\n", prefix, x-1, ie->data[x], ie->data[x], ie2str(ie->data[x])); + break; + case PRI_CAUSE_WRONG_CALL_STATE: + for (x=2;x<ie->len;x++) +- pri_message(pri, "%c Cause data %d: %02x (%d, %s message)\n", prefix, x-1, ie->data[x], ie->data[x], msg2str(ie->data[x])); ++ pri_message(ctrl, "%c Cause data %d: %02x (%d, %s message)\n", prefix, x-1, ie->data[x], ie->data[x], msg2str(ie->data[x])); + break; + case PRI_CAUSE_RECOVERY_ON_TIMER_EXPIRE: +- pri_message(pri, "%c Cause data:", prefix); ++ pri_message(ctrl, "%c Cause data:", prefix); + for (x=2;x<ie->len;x++) +- pri_message(pri, " %02x", ie->data[x]); +- pri_message(pri, " (Timer T"); ++ pri_message(ctrl, " %02x", ie->data[x]); ++ pri_message(ctrl, " (Timer T"); + for (x=2;x<ie->len;x++) +- pri_message(pri, "%c", ((ie->data[x] >= ' ') && (ie->data[x] < 0x7f)) ? ie->data[x] : '.'); +- pri_message(pri, ")\n"); ++ pri_message(ctrl, "%c", ((ie->data[x] >= ' ') && (ie->data[x] < 0x7f)) ? ie->data[x] : '.'); ++ pri_message(ctrl, ")\n"); + break; + default: + for (x=2;x<ie->len;x++) +- pri_message(pri, "%c Cause data %d: %02x (%d)\n", prefix, x-1, ie->data[x], ie->data[x]); ++ pri_message(ctrl, "%c Cause data %d: %02x (%d)\n", prefix, x-1, ie->data[x], ie->data[x]); + break; + } + } + +-static FUNC_RECV(receive_cause) ++static int receive_cause(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + call->causeloc = ie->data[0] & 0xf; + call->causecode = (ie->data[0] & 0x60) >> 5; +@@ -1777,7 +2848,7 @@ + return 0; + } + +-static FUNC_SEND(transmit_cause) ++static int transmit_cause(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { + /* We are ready to transmit single IE only */ + if (order > 1) +@@ -1793,23 +2864,23 @@ + } + } + +-static FUNC_DUMP(dump_sending_complete) ++static void dump_sending_complete(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- pri_message(pri, "%c Sending Complete (len=%2d)\n", prefix, len); ++ pri_message(ctrl, "%c Sending Complete (len=%2d)\n", prefix, len); + } + +-static FUNC_RECV(receive_sending_complete) ++static int receive_sending_complete(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + /* We've got a "Complete" message: Exect no further digits. */ + call->complete = 1; + return 0; + } + +-static FUNC_SEND(transmit_sending_complete) ++static int transmit_sending_complete(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { +- if ((pri->overlapdial && call->complete) || /* Explicit */ +- (!pri->overlapdial && ((pri->switchtype == PRI_SWITCH_EUROISDN_E1) || +- /* Implicit */ (pri->switchtype == PRI_SWITCH_EUROISDN_T1)))) { ++ if ((ctrl->overlapdial && call->complete) || /* Explicit */ ++ (!ctrl->overlapdial && ((ctrl->switchtype == PRI_SWITCH_EUROISDN_E1) || ++ /* Implicit */ (ctrl->switchtype == PRI_SWITCH_EUROISDN_T1)))) { + /* Include this single-byte IE */ + return 1; + } +@@ -1846,18 +2917,18 @@ + return code2str(info, notifies, sizeof(notifies) / sizeof(notifies[0])); + } + +-static FUNC_DUMP(dump_notify) ++static void dump_notify(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- pri_message(pri, "%c Notification indicator (len=%2d): Ext: %d %s (%d)\n", prefix, len, ie->data[0] >> 7, notify2str(ie->data[0] & 0x7f), ie->data[0] & 0x7f); ++ pri_message(ctrl, "%c Notification indicator (len=%2d): Ext: %d %s (%d)\n", prefix, len, ie->data[0] >> 7, notify2str(ie->data[0] & 0x7f), ie->data[0] & 0x7f); + } + +-static FUNC_RECV(receive_notify) ++static int receive_notify(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + call->notify = ie->data[0] & 0x7F; + return 0; + } + +-static FUNC_SEND(transmit_notify) ++static int transmit_notify(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { + if (call->notify >= 0) { + ie->data[0] = 0x80 | call->notify; +@@ -1866,9 +2937,9 @@ + return 0; + } + +-static FUNC_DUMP(dump_shift) ++static void dump_shift(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- pri_message(pri, "%c %sLocking Shift (len=%02d): Requested codeset %d\n", prefix, (full_ie & 8) ? "Non-" : "", len, full_ie & 7); ++ pri_message(ctrl, "%c %sLocking Shift (len=%02d): Requested codeset %d\n", prefix, (full_ie & 8) ? "Non-" : "", len, full_ie & 7); + } + + static char *lineinfo2str(int info) +@@ -1903,21 +2974,21 @@ + return code2str(info, lineinfo, sizeof(lineinfo) / sizeof(lineinfo[0])); + } + +-static FUNC_DUMP(dump_line_information) ++static void dump_line_information(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- pri_message(pri, "%c Originating Line Information (len=%02d): %s (%d)\n", prefix, len, lineinfo2str(ie->data[0]), ie->data[0]); ++ pri_message(ctrl, "%c Originating Line Information (len=%02d): %s (%d)\n", prefix, len, lineinfo2str(ie->data[0]), ie->data[0]); + } + +-static FUNC_RECV(receive_line_information) ++static int receive_line_information(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + call->ani2 = ie->data[0]; + return 0; + } + +-static FUNC_SEND(transmit_line_information) ++static int transmit_line_information(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { + #if 0 /* XXX Is this IE possible for 4ESS only? XXX */ +- if(pri->switchtype == PRI_SWITCH_ATT4ESS) { ++ if(ctrl->switchtype == PRI_SWITCH_ATT4ESS) { + ie->data[0] = 0; + return 3; + } +@@ -1953,53 +3024,54 @@ + return code2str(type, gdtype, sizeof(gdtype) / sizeof(gdtype[0])); + } + +-static FUNC_DUMP(dump_generic_digits) ++static void dump_generic_digits(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { + int encoding; + int type; + int idx; + int value; + if (len < 3) { +- pri_message(pri, "%c Generic Digits (len=%02d): Invalid length\n", prefix, len); ++ pri_message(ctrl, "%c Generic Digits (len=%02d): Invalid length\n", prefix, len); + return; + } + encoding = (ie->data[0] >> 5) & 7; + type = ie->data[0] & 0x1F; +- pri_message(pri, "%c Generic Digits (len=%02d): Encoding %s Type %s\n", prefix, len, gdencoding2str(encoding), gdtype2str(type)); ++ pri_message(ctrl, "%c Generic Digits (len=%02d): Encoding %s Type %s\n", prefix, len, gdencoding2str(encoding), gdtype2str(type)); + if (encoding == 3) { /* Binary */ +- pri_message(pri, "%c Don't know how to handle binary encoding\n"); ++ pri_message(ctrl, "%c Don't know how to handle binary encoding\n", ++ prefix); + return; + } + if (len == 3) /* No number information */ + return; +- pri_message(pri, "%c Digits: "); ++ pri_message(ctrl, "%c Digits: ", prefix); + value = 0; + for(idx = 3; idx < len; ++idx) { + switch(encoding) { + case 0: /* BCD even */ + case 1: /* BCD odd */ +- pri_message(pri, "%d", ie->data[idx-2] & 0x0f); ++ pri_message(ctrl, "%d", ie->data[idx-2] & 0x0f); + value = value * 10 + (ie->data[idx-2] & 0x0f); + if(!encoding || (idx+1 < len)) { /* Special handling for BCD odd */ +- pri_message(pri, "%d", (ie->data[idx-2] >> 4) & 0x0f); ++ pri_message(ctrl, "%d", (ie->data[idx-2] >> 4) & 0x0f); + value = value * 10 + ((ie->data[idx-2] >> 4) & 0x0f); + } + break; + case 2: /* IA5 */ +- pri_message(pri, "%c", ie->data[idx-2]); ++ pri_message(ctrl, "%c", ie->data[idx-2]); + value = value * 10 + ie->data[idx-2] - '0'; + break; + } + } + switch(type) { + case 4: /* Info Digits */ +- pri_message(pri, " - %s", lineinfo2str(value)); ++ pri_message(ctrl, " - %s", lineinfo2str(value)); + break; + } +- pri_message(pri, "\n"); ++ pri_message(ctrl, "\n"); + } + +-static FUNC_RECV(receive_generic_digits) ++static int receive_generic_digits(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) + { + int encoding; + int type; +@@ -2009,13 +3081,13 @@ + char number[260]; + + if (len < 3) { +- pri_error(pri, "Invalid length of Generic Digits IE\n"); ++ pri_error(ctrl, "Invalid length of Generic Digits IE\n"); + return -1; + } + encoding = (ie->data[0] >> 5) & 7; + type = ie->data[0] & 0x1F; + if (encoding == 3) { /* Binary */ +- pri_message(pri, "!! Unable to handle binary encoded Generic Digits IE\n"); ++ pri_message(ctrl, "!! Unable to handle binary encoded Generic Digits IE\n"); + return 0; + } + if (len == 3) /* No number information */ +@@ -2063,10 +3135,13 @@ + break; + #if 0 + case 5: /* Callid */ +- if (!call->callernum[0]) { +- memcpy(call->callernum, number, sizeof(call->callernum)-1); +- call->callerpres = 0; +- call->callerplan = 0; ++ if (!call->remote_id.number.valid) { ++ call->remote_id.number.valid = 1; ++ call->remote_id.number.presentation = ++ PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ call->remote_id.number.plan = PRI_UNKNOWN; ++ libpri_copy_string(call->remote_id.number.str, number, ++ sizeof(call->remote_id.number.str)); + } + break; + #endif +@@ -2074,13 +3149,13 @@ + return 0; + } + +-static FUNC_SEND(transmit_generic_digits) ++static int transmit_generic_digits(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) + { + #if 0 /* XXX Is this IE possible for other switches? XXX */ + if (order > 1) + return 0; + +- if(pri->switchtype == PRI_SWITCH_NI1) { ++ if(ctrl->switchtype == PRI_SWITCH_NI1) { + ie->data[0] = 0x04; /* BCD even, Info Digits */ + ie->data[1] = 0x00; /* POTS */ + return 4; +@@ -2119,35 +3194,54 @@ + } + + +-static FUNC_DUMP(dump_signal) ++static void dump_signal(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { +- pri_message(pri, "%c Signal (len=%02d): ", prefix, len); ++ pri_message(ctrl, "%c Signal (len=%02d): ", prefix, len); + if (len < 3) { +- pri_message(pri, "Invalid length\n"); ++ pri_message(ctrl, "Invalid length\n"); + return; + } +- pri_message(pri, "Signal %s (%d)\n", signal2str(ie->data[0]), ie->data[0]); ++ pri_message(ctrl, "Signal %s (%d)\n", signal2str(ie->data[0]), ie->data[0]); + } + +-static FUNC_DUMP(dump_transit_count) ++static void dump_transit_count(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) + { + /* Defined in ECMA-225 */ +- pri_message(pri, "%c Transit Count (len=%02d): ", prefix, len); ++ pri_message(ctrl, "%c Transit Count (len=%02d): ", prefix, len); + if (len < 3) { +- pri_message(pri, "Invalid length\n"); ++ pri_message(ctrl, "Invalid length\n"); + return; + } +- pri_message(pri, "Count=%d (0x%02x)\n", ie->data[0] & 0x1f, ie->data[0] & 0x1f); ++ pri_message(ctrl, "Count=%d (0x%02x)\n", ie->data[0] & 0x1f, ie->data[0] & 0x1f); + } + ++static void dump_reverse_charging_indication(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix) ++{ ++ pri_message(ctrl, "%c Reverse Charging Indication (len=%02d): %d\n", prefix, len, ie->data[0] & 0x7); ++} + ++static int receive_reverse_charging_indication(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len) ++{ ++ call->reversecharge = ie->data[0] & 0x7; ++ return 0; ++} ++ ++static int transmit_reverse_charging_indication(int full_ie, struct pri *ctrl, q931_call *call, int msgtype, q931_ie *ie, int len, int order) ++{ ++ if (call->reversecharge != PRI_REVERSECHARGE_NONE) { ++ ie->data[0] = 0x80 | (call->reversecharge & 0x7); ++ return 3; ++ } ++ return 0; ++} ++ + static struct ie ies[] = { + /* Codeset 0 - Common */ +- { 1, NATIONAL_CHANGE_STATUS, "Change Status" }, ++ { 1, NATIONAL_CHANGE_STATUS, "Change Status", dump_change_status, receive_change_status, transmit_change_status }, + { 0, Q931_LOCKING_SHIFT, "Locking Shift", dump_shift }, + { 0, Q931_BEARER_CAPABILITY, "Bearer Capability", dump_bearer_capability, receive_bearer_capability, transmit_bearer_capability }, + { 0, Q931_CAUSE, "Cause", dump_cause, receive_cause, transmit_cause }, +- { 1, Q931_CALL_STATE, "Call State", dump_call_state, receive_call_state, transmit_call_state }, ++ { 1, Q931_IE_CALL_STATE, "Call State", dump_call_state, receive_call_state, transmit_call_state }, + { 0, Q931_CHANNEL_IDENT, "Channel Identification", dump_channel_id, receive_channel_id, transmit_channel_id }, + { 0, Q931_PROGRESS_INDICATOR, "Progress Indicator", dump_progress_indicator, receive_progress_indicator, transmit_progress_indicator }, + { 0, Q931_NETWORK_SPEC_FAC, "Network-Specific Facilities", dump_network_spec_fac, receive_network_spec_fac, transmit_network_spec_fac }, +@@ -2157,11 +3251,11 @@ + { 1, Q931_BINARY_PARAMETERS, "Packet-layer Binary Parameters" }, + { 1, Q931_WINDOW_SIZE, "Packet-layer Window Size" }, + { 1, Q931_CLOSED_USER_GROUP, "Closed User Group" }, +- { 1, Q931_REVERSE_CHARGE_INDIC, "Reverse Charging Indication" }, ++ { 1, Q931_REVERSE_CHARGE_INDIC, "Reverse Charging Indication", dump_reverse_charging_indication, receive_reverse_charging_indication, transmit_reverse_charging_indication }, + { 1, Q931_CALLING_PARTY_NUMBER, "Calling Party Number", dump_calling_party_number, receive_calling_party_number, transmit_calling_party_number }, +- { 1, Q931_CALLING_PARTY_SUBADDR, "Calling Party Subaddress", dump_calling_party_subaddr, receive_calling_party_subaddr }, ++ { 1, Q931_CALLING_PARTY_SUBADDR, "Calling Party Subaddress", dump_calling_party_subaddr, receive_calling_party_subaddr, transmit_calling_party_subaddr }, + { 1, Q931_CALLED_PARTY_NUMBER, "Called Party Number", dump_called_party_number, receive_called_party_number, transmit_called_party_number }, +- { 1, Q931_CALLED_PARTY_SUBADDR, "Called Party Subaddress", dump_called_party_subaddr }, ++ { 1, Q931_CALLED_PARTY_SUBADDR, "Called Party Subaddress", dump_called_party_subaddr, receive_called_party_subaddr, transmit_called_party_subaddr }, + { 0, Q931_REDIRECTING_NUMBER, "Redirecting Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number }, + { 1, Q931_REDIRECTING_SUBADDR, "Redirecting Subaddress", dump_redirecting_subaddr }, + { 0, Q931_TRANSIT_NET_SELECT, "Transit Network Selection" }, +@@ -2170,7 +3264,7 @@ + { 0, Q931_HIGH_LAYER_COMPAT, "High-layer Compatibility" }, + { 1, Q931_PACKET_SIZE, "Packet Size" }, + { 0, Q931_IE_FACILITY, "Facility" , dump_facility, receive_facility, transmit_facility }, +- { 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number" }, ++ { 1, Q931_IE_REDIRECTION_NUMBER, "Redirection Number", dump_redirection_number, receive_redirection_number, transmit_redirection_number }, + { 1, Q931_IE_REDIRECTION_SUBADDR, "Redirection Subaddress" }, + { 1, Q931_IE_FEATURE_ACTIVATE, "Feature Activation" }, + { 1, Q931_IE_INFO_REQUEST, "Feature Request" }, +@@ -2187,15 +3281,18 @@ + { 1, Q931_IE_USER_USER, "User-User", dump_user_user, receive_user_user, transmit_user_user }, + { 1, Q931_IE_ESCAPE_FOR_EXT, "Escape for Extension" }, + { 1, Q931_IE_CALL_STATUS, "Call Status" }, +- { 1, Q931_IE_CHANGE_STATUS, "Change Status" }, ++ { 1, Q931_IE_CHANGE_STATUS, "Change Status", dump_change_status, receive_change_status, transmit_change_status }, + { 1, Q931_IE_CONNECTED_ADDR, "Connected Number", dump_connected_number }, +- { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number }, ++ { 1, Q931_IE_CONNECTED_NUM, "Connected Number", dump_connected_number, receive_connected_number, transmit_connected_number }, ++ { 1, Q931_IE_CONNECTED_SUBADDR, "Connected Subaddress", dump_connected_subaddr, receive_connected_subaddr, transmit_connected_subaddr }, + { 1, Q931_IE_ORIGINAL_CALLED_NUMBER, "Original Called Number", dump_redirecting_number, receive_redirecting_number, transmit_redirecting_number }, + { 1, Q931_IE_USER_USER_FACILITY, "User-User Facility" }, + { 1, Q931_IE_UPDATE, "Update" }, + { 1, Q931_SENDING_COMPLETE, "Sending Complete", dump_sending_complete, receive_sending_complete, transmit_sending_complete }, + /* Codeset 4 - Q.SIG specific */ + { 1, QSIG_IE_TRANSIT_COUNT | Q931_CODESET(4), "Transit Count", dump_transit_count }, ++ /* Codeset 5 - National specific (ETSI PISN specific) */ ++ { 1, Q931_CALLING_PARTY_CATEGORY, "Calling Party Category", dump_calling_party_category }, + /* Codeset 6 - Network specific */ + { 1, Q931_IE_ORIGINATING_LINE_INFO, "Originating Line Information", dump_line_information, receive_line_information, transmit_line_information }, + { 1, Q931_IE_FACILITY | Q931_CODESET(6), "Facility", dump_facility, receive_facility, transmit_facility }, +@@ -2264,7 +3361,7 @@ + return 2 + ie->len; + } + +-static char *msg2str(int msg) ++const char *msg2str(int msg) + { + unsigned int x; + for (x=0;x<sizeof(msgs) / sizeof(msgs[0]); x++) +@@ -2273,35 +3370,64 @@ + return "Unknown Message Type"; + } + ++static char *maintenance_msg2str(int msg, int pd) ++{ ++ unsigned int x, max; ++ struct msgtype *m = NULL; ++ ++ if (pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) { ++ m = att_maintenance_msgs; ++ max = ARRAY_LEN(att_maintenance_msgs); ++ } else { ++ m = national_maintenance_msgs; ++ max = ARRAY_LEN(national_maintenance_msgs); ++ } ++ ++ for (x = 0; x < max; x++) { ++ if (m[x].msgnum == msg) { ++ return m[x].name; ++ } ++ } ++ return "Unknown Message Type"; ++} ++ ++/* Decode the call reference */ + static inline int q931_cr(q931_h *h) + { +- int cr = 0; ++ int cr; + int x; ++ + if (h->crlen > 3) { + pri_error(NULL, "Call Reference Length Too long: %d\n", h->crlen); +- return -1; ++ return Q931_DUMMY_CALL_REFERENCE; + } + switch (h->crlen) { +- case 2: +- for (x=0;x<h->crlen;x++) { +- cr <<= 8; +- cr |= h->crv[x]; +- } +- break; +- case 1: +- cr = h->crv[0]; +- if (cr & 0x80) { +- cr &= ~0x80; +- cr |= 0x8000; +- } +- break; +- default: +- pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen); ++ case 2: ++ cr = 0; ++ for (x = 0; x < h->crlen; ++x) { ++ cr <<= 8; ++ cr |= h->crv[x]; ++ } ++ break; ++ case 1: ++ cr = h->crv[0]; ++ if (cr & 0x80) { ++ cr &= ~0x80; ++ cr |= 0x8000; ++ } ++ break; ++ case 0: ++ cr = Q931_DUMMY_CALL_REFERENCE; ++ break; ++ default: ++ pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen); ++ cr = Q931_DUMMY_CALL_REFERENCE; ++ break; + } + return cr; + } + +-static inline void q931_dumpie(struct pri *pri, int codeset, q931_ie *ie, char prefix) ++static inline void q931_dumpie(struct pri *ctrl, int codeset, q931_ie *ie, char prefix) + { + unsigned int x; + int full_ie = Q931_FULL_IE(codeset, ie->ie); +@@ -2315,7 +3441,7 @@ + for (x = 0; x + 2 < ielen(ie); ++x) + buflen += sprintf(buf + buflen, " %02x", ie->data[x]); + } +- pri_message(pri, "%c [%02x%s]\n", prefix, ie->ie, buf); ++ pri_message(ctrl, "%c [%02x%s]\n", prefix, ie->ie, buf); + free(buf); + + /* Special treatment for shifts */ +@@ -2324,130 +3450,306 @@ + + base_ie = (((full_ie & ~0x7f) == Q931_FULL_IE(0, 0x80)) && ((full_ie & 0x70) != 0x20)) ? full_ie & ~0x0f : full_ie; + +- for (x=0;x<sizeof(ies) / sizeof(ies[0]); x++) ++ for (x = 0; x < ARRAY_LEN(ies); ++x) + if (ies[x].ie == base_ie) { + if (ies[x].dump) +- ies[x].dump(full_ie, pri, ie, ielen(ie), prefix); ++ ies[x].dump(full_ie, ctrl, ie, ielen(ie), prefix); + else +- pri_message(pri, "%c IE: %s (len = %d)\n", prefix, ies[x].name, ielen(ie)); ++ pri_message(ctrl, "%c IE: %s (len = %d)\n", prefix, ies[x].name, ielen(ie)); + return; + } + +- pri_error(pri, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie)); ++ pri_error(ctrl, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie)); + } + +-static q931_call *q931_getcall(struct pri *pri, int cr, int outboundnew) ++/*! ++ * \brief Initialize the call record. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. ++ * ++ * \note The call record is assumed to already be memset() to zero. ++ * ++ * \return Nothing ++ */ ++void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr) + { +- q931_call *cur, *prev; ++ call->cr = cr; ++ call->slotmap = -1; ++ call->channelno = -1; ++ if (cr != Q931_DUMMY_CALL_REFERENCE) { ++ call->newcall = 1; ++ } ++ call->ourcallstate = Q931_CALL_STATE_NULL; ++ call->peercallstate = Q931_CALL_STATE_NULL; ++ call->sugcallstate = Q931_CALL_STATE_NOT_SET; ++ call->ri = -1; ++ call->transcapability = -1; ++ call->transmoderate = -1; ++ call->transmultiple = -1; ++ call->userl1 = -1; ++ call->userl2 = -1; ++ call->userl3 = -1; ++ call->rateadaption = -1; ++ call->progress = -1; ++ call->causecode = -1; ++ call->causeloc = -1; ++ call->cause = -1; ++ call->useruserprotocoldisc = -1; ++ call->aoc_units = -1; ++ call->changestatus = -1; ++ call->reversecharge = -1; ++ call->pri_winner = -1; ++ call->master_call = call; ++ q931_party_number_init(&call->redirection_number); ++ q931_party_address_init(&call->called); ++ q931_party_id_init(&call->local_id); ++ q931_party_id_init(&call->remote_id); ++ q931_party_redirecting_init(&call->redirecting); ++ ++ /* PRI is set to whoever called us */ ++ if (BRI_TE_PTMP(ctrl)) { ++ /* ++ * Point to the master to avoid stale pointer problems if ++ * the TEI is removed later. ++ */ ++ call->pri = PRI_MASTER(ctrl); ++ } else { ++ call->pri = ctrl; ++ } ++} ++ ++static q931_call *q931_getcall(struct pri *ctrl, int cr) ++{ ++ q931_call *cur; ++ q931_call *prev; + struct pri *master; + ++ if (cr == Q931_DUMMY_CALL_REFERENCE) { ++ return ctrl->dummy_call; ++ } ++ + /* Find the master - He has the call pool */ +- if (pri->master) +- master = pri->master; +- else +- master = pri; +- ++ master = PRI_MASTER(ctrl); ++ + cur = *master->callpool; + prev = NULL; +- while(cur) { +- if (cur->cr == cr) ++ while (cur) { ++ if (cur->cr == cr) { ++ /* Found existing call. */ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_GR303_EOC: ++ case PRI_SWITCH_GR303_EOC_PATH: ++ case PRI_SWITCH_GR303_TMC: ++ case PRI_SWITCH_GR303_TMC_SWITCHING: ++ break; ++ default: ++ if (!ctrl->bri) { ++ /* PRI is set to whoever called us */ ++ cur->pri = ctrl; ++ } ++ break; ++ } + return cur; ++ } + prev = cur; + cur = cur->next; + } ++ + /* No call exists, make a new one */ +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "-- Making new call for cr %d\n", cr); +- +- if (!(cur = calloc(1, sizeof(*cur)))) ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "-- Making new call for cr %d\n", cr); ++ } ++ ++ cur = calloc(1, sizeof(*cur)); ++ if (!cur) { + return NULL; ++ } + +- call_init(cur); +- /* Call reference */ +- cur->cr = cr; +- /* PRI is set to whoever called us */ +- if (pri->bri && (pri->localtype == PRI_CPE) && pri->subchannel && outboundnew) +- cur->pri = pri->subchannel; +- else +- cur->pri = pri; ++ /* Initialize call structure. */ ++ q931_init_call_record(ctrl, cur, cr); + + /* Append to end of list */ +- if (prev) ++ if (prev) { + prev->next = cur; +- else ++ } else { + *master->callpool = cur; +- ++ } ++ + return cur; + } + +-q931_call *q931_new_call(struct pri *pri) ++q931_call *q931_new_call(struct pri *ctrl) + { + q931_call *cur; + + do { +- cur = *pri->callpool; +- pri->cref++; +- if (!pri->bri) { +- if (pri->cref > 32767) +- pri->cref = 1; ++ cur = *ctrl->callpool; ++ ctrl->cref++; ++ if (!ctrl->bri) { ++ if (ctrl->cref > 32767) ++ ctrl->cref = 1; + } else { +- if (pri->cref > 127) +- pri->cref = 1; ++ if (ctrl->cref > 127) ++ ctrl->cref = 1; + } + while(cur) { +- if (cur->cr == (0x8000 | pri->cref)) ++ if (cur->cr == (0x8000 | ctrl->cref)) + break; + cur = cur->next; + } + } while(cur); + +- return q931_getcall(pri, pri->cref | 0x8000, 1); ++ return q931_getcall(ctrl, ctrl->cref | 0x8000); + } + +-static void q931_destroy(struct pri *pri, int cr, q931_call *c) ++static void stop_t303(struct q931_call *call); ++ ++static void cleanup_and_free_call(struct q931_call *cur) + { +- q931_call *cur, *prev; ++ stop_t303(cur); ++ pri_schedule_del(cur->pri, cur->retranstimer); ++ pri_call_apdu_queue_cleanup(cur); ++ free(cur); ++} + ++static void pri_create_fake_clearing(struct q931_call *c, struct pri *master); ++ ++void q931_destroycall(struct pri *ctrl, q931_call *c) ++{ ++ q931_call *cur; ++ q931_call *prev; ++ q931_call *slave; ++ int i; ++ int slavesleft; ++ int slaveidx; ++ ++ if (q931_is_dummy_call(c)) { ++ /* Cannot destroy the dummy call. */ ++ return; ++ } ++ if (c->master_call != c) { ++ slave = c; ++ c = slave->master_call; ++ } else { ++ slave = NULL; ++ } ++ + /* For destroying, make sure we are using the master span, since it maintains the call pool */ +- for (;pri->master; pri = pri->master); ++ ctrl = PRI_MASTER(ctrl); + + prev = NULL; +- cur = *pri->callpool; +- while(cur) { +- if ((c && (cur == c)) || (!c && (cur->cr == cr))) { ++ cur = *ctrl->callpool; ++ while (cur) { ++ if (cur == c) { ++ slaveidx = -1; ++ if (slave) { ++ for (i = 0; i < Q931_MAX_TEI; i++) { ++ if (cur->subcalls[i] == slave) { ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "Destroying subcall %p of call %p at %d\n", ++ slave, cur, i); ++ } ++ cleanup_and_free_call(slave); ++ cur->subcalls[i] = NULL; ++ slaveidx = i; ++ break; ++ } ++ } ++ } ++ ++ slavesleft = 0; ++ for (i = 0; i < Q931_MAX_TEI; i++) { ++ if (cur->subcalls[i]) { ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "Subcall still present at %d\n", i); ++ } ++ slavesleft++; ++ } ++ } ++ ++ /* We have 3 different phases to deal with: ++ * 1.) Sent outbound call, but no response, indicated by t203 present ++ * 2.) Sent outbound call, with responses, indicated by lack of t203 and subcalls present ++ * 3.) Outbound call connected, indicated by pri_winner > -1 ++ * ++ * If chan_dahdi hangs up in phase: ++ * 1.) T303 will be present, and we will fake clear in this case ++ * 2.) pri_winner will be < 0 and subcalls will be present. ++ * 3.) pri_winner will be > -1 and we will free the master when the winner dies. ++ * ++ * If remote ends hang up in phase: ++ * 1.) Impossible, defined by phase. ++ * 2.) When last end hangs up, we should cause a fake clearing. ++ * 3.) Pass events to winner up and be freed when winner is freed ++ * ++ * Exceptional conditions in phase: ++ * 1.) None. ++ * 2.) None. ++ * 3.) We hang up a call so quickly that it hangs up before other competing lines finish hangup sequence ++ * Subcalls present still even though we have hung up the winner. ++ * ++ * So, we could say: ++ * If, when the library user hangs up the master call, and there are more than one subcall up, we fake clear ++ * regardless of whether or not we drop down to one subcall left in the clearing process. ++ * ++ * If there are only one call up, we mirror what it does. ++ * ++ * OR ++ * ++ * Phase 2. them clearing: ++ * For handling of Phase 2 (indicated by not running and pri_winner not present): ++ * We create a fake hangup sequence after all the subcalls have been destroyed and after ++ * ++ * "" us clearing: ++ * For we need to start the fake clearing, but it needs to be half of a fake clearing, not a full one (since we already had a hangup). ++ * ++ * For handling of Phase 3 plus exceptions: ++ * ++ * If pri_winner exists, we mirror him in terms of events (which provides our hangup sequence), and when we have the complete ++ * hangup sequence completed (destroy called on master call), if there still exist non winner subcalls at this time, we declare the master ++ * call as dead and free it when the last subcall clears. ++ */ ++ ++ if ((slave && !slavesleft) && ++ ((cur->pri_winner < 0) || (slave && slaveidx != cur->pri_winner))) { ++ pri_create_fake_clearing(cur, ctrl); ++ return; ++ } ++ ++ if (slavesleft) { ++ return; ++ } ++ ++ /* Master call or normal call destruction. */ ++ if ((cur->pri_winner > -1) && cur->outboundbroadcast) { ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, ++ "Since we already had a winner, we should just be able to kill the call anyways\n"); ++ } ++ } + if (prev) + prev->next = cur->next; + else +- *pri->callpool = cur->next; +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",callstate2str(cur->ourcallstate),callstate2str(cur->peercallstate)); +- if (cur->retranstimer) +- pri_schedule_del(pri, cur->retranstimer); +- pri_call_apdu_queue_cleanup(cur); +- free(cur); ++ *ctrl->callpool = cur->next; ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, ++ "NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s, hold-state %s\n", ++ q931_call_state_str(cur->ourcallstate), ++ q931_call_state_str(cur->peercallstate), ++ q931_hold_state_str(cur->hold_state)); ++ pri_schedule_del(ctrl, cur->hold_timer); ++ cleanup_and_free_call(cur); + return; + } + prev = cur; + cur = cur->next; + } +- pri_error(pri, "Can't destroy call %d!\n", cr); ++ pri_error(ctrl, "Can't destroy call %p cref:%d!\n", c, c->cr); + } + +-static void q931_destroycall(struct pri *pri, int cr) ++static int add_ie(struct pri *ctrl, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen, int *codeset) + { +- return q931_destroy(pri, cr, NULL); +-} +- +- +-void __q931_destroycall(struct pri *pri, q931_call *c) +-{ +- if (pri && c) +- q931_destroy(pri,0, c); +- return; +-} +- +-static int add_ie(struct pri *pri, q931_call *call, int msgtype, int ie, q931_ie *iet, int maxlen, int *codeset) +-{ + unsigned int x; + int res, total_res; + int have_shift; +@@ -2473,7 +3775,7 @@ + total_res = 0; + do { + iet->ie = ie; +- res = ies[x].transmit(ie, pri, call, msgtype, iet, maxlen, ++order); ++ res = ies[x].transmit(ie, ctrl, call, msgtype, iet, maxlen, ++order); + /* Error if res < 0 or ignored if res == 0 */ + if (res < 0) + return res; +@@ -2484,8 +3786,7 @@ + maxlen -= res; + iet = (q931_ie *)((char *)iet + res); + } +- } +- while (res > 0 && order < ies_count); ++ } while (res > 0 && order < ies_count); + if (have_shift && total_res) { + if (Q931_IE_CODESET(ies[x].ie)) + *codeset = Q931_IE_CODESET(ies[x].ie); +@@ -2493,12 +3794,12 @@ + } + return total_res; + } else { +- pri_error(pri, "!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie); ++ pri_error(ctrl, "!! Don't know how to add an IE %s (%d)\n", ie2str(ie), ie); + return -1; + } + } + } +- pri_error(pri, "!! Unknown IE %d (%s)\n", ie, ie2str(ie)); ++ pri_error(ctrl, "!! Unknown IE %d (%s)\n", ie, ie2str(ie)); + return -1; + } + +@@ -2513,25 +3814,37 @@ + return code2str(disc, discs, sizeof(discs) / sizeof(discs[0])); + } + +-void q931_dump(struct pri *pri, q931_h *h, int len, int txrx) ++void q931_dump(struct pri *ctrl, q931_h *h, int len, int txrx) + { + q931_mh *mh; + char c; + int x=0, r; + int cur_codeset; + int codeset; ++ int cref; ++ + c = txrx ? '>' : '<'; +- pri_message(pri, "%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len); +- pri_message(pri, "%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n", c, h->crlen, q931_cr(h) & 0x7FFF, q931_cr(h) & 0x7FFF, (h->crv[0] & 0x80) ? "Terminator" : "Originator"); ++ pri_message(ctrl, "%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len); ++ cref = q931_cr(h); ++ pri_message(ctrl, "%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n", ++ c, h->crlen, cref & 0x7FFF, cref & 0x7FFF, ++ (cref == Q931_DUMMY_CALL_REFERENCE) ++ ? "Dummy" ++ : (cref & 0x8000) ? "Terminator" : "Originator"); ++ + /* Message header begins at the end of the call reference number */ + mh = (q931_mh *)(h->contents + h->crlen); +- pri_message(pri, "%c Message type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); ++ if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) { ++ pri_message(ctrl, "%c Message Type: %s (%d)\n", c, maintenance_msg2str(mh->msg, h->pd), mh->msg); ++ } else { ++ pri_message(ctrl, "%c Message Type: %s (%d)\n", c, msg2str(mh->msg), mh->msg); ++ } + /* Drop length of header, including call reference */ + len -= (h->crlen + 3); + codeset = cur_codeset = 0; + while(x < len) { + r = ielen((q931_ie *)(mh->data + x)); +- q931_dumpie(pri, cur_codeset, (q931_ie *)(mh->data + x), c); ++ q931_dumpie(ctrl, cur_codeset, (q931_ie *)(mh->data + x), c); + switch (mh->data[x] & 0xf8) { + case Q931_LOCKING_SHIFT: + if ((mh->data[x] & 7) > 0) +@@ -2547,86 +3860,106 @@ + x += r; + } + if (x > len) +- pri_error(pri, "XXX Message longer than it should be?? XXX\n"); ++ pri_error(ctrl, "XXX Message longer than it should be?? XXX\n"); + } + +-static int q931_handle_ie(int codeset, struct pri *pri, q931_call *c, int msg, q931_ie *ie) ++static int q931_handle_ie(int codeset, struct pri *ctrl, q931_call *c, int msg, q931_ie *ie) + { + unsigned int x; + int full_ie = Q931_FULL_IE(codeset, ie->ie); +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "-- Processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, "-- Processing IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); + for (x=0;x<sizeof(ies) / sizeof(ies[0]);x++) { + if (full_ie == ies[x].ie) { + if (ies[x].receive) +- return ies[x].receive(full_ie, pri, c, msg, ie, ielen(ie)); ++ return ies[x].receive(full_ie, ctrl, c, msg, ie, ielen(ie)); + else { +- if (pri->debug & PRI_DEBUG_Q931_ANOMALY) +- pri_error(pri, "!! No handler for IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); ++ if (ctrl->debug & PRI_DEBUG_Q931_ANOMALY) ++ pri_error(ctrl, "!! No handler for IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); + return -1; + } + } + } +- pri_message(pri, "!! Unknown IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); ++ pri_message(ctrl, "!! Unknown IE %d (cs%d, %s)\n", ie->ie, codeset, ie2str(full_ie)); + return -1; + } + +-static void init_header(struct pri *pri, q931_call *call, unsigned char *buf, q931_h **hb, q931_mh **mhb, int *len) ++/* Returns header and message header and modifies length in place */ ++static void init_header(struct pri *ctrl, q931_call *call, unsigned char *buf, q931_h **hb, q931_mh **mhb, int *len, int protodisc) + { +- /* Returns header and message header and modifies length in place */ +- q931_h *h = (q931_h *)buf; +- q931_mh * mh; +- h->pd = pri->protodisc; ++ q931_h *h = (q931_h *) buf; ++ q931_mh *mh; ++ unsigned crv; ++ ++ if (protodisc) { ++ h->pd = protodisc; ++ } else { ++ h->pd = ctrl->protodisc; ++ } + h->x0 = 0; /* Reserved 0 */ +- if (!pri->bri) { +- h->crlen = 2; /* Two bytes of Call Reference. Invert the top bit to make it from our sense */ +- if (call->cr || call->forceinvert) { +- h->crv[0] = ((call->cr ^ 0x8000) & 0xff00) >> 8; +- h->crv[1] = (call->cr & 0xff); +- } else { +- /* Unless of course this has no call reference */ +- h->crv[0] = 0; +- h->crv[1] = 0; +- } +- if (pri->subchannel && !pri->bri) { ++ if (q931_is_dummy_call(call)) { ++ h->crlen = 0; ++ } else if (!ctrl->bri) { ++ /* Two bytes of Call Reference. */ ++ h->crlen = 2; ++ /* Invert the top bit to make it from our sense */ ++ crv = (unsigned) call->cr; ++ h->crv[0] = ((crv >> 8) ^ 0x80) & 0xff; ++ h->crv[1] = crv & 0xff; ++ if (ctrl->subchannel && !ctrl->bri) { + /* On GR-303, top bit is always 0 */ + h->crv[0] &= 0x7f; + } + } else { + h->crlen = 1; +- if (call->cr || call->forceinvert) { +- h->crv[0] = (((call->cr ^ 0x8000) & 0x8000) >> 8) | (call->cr & 0x7f); +- } else { +- /* Unless of course this has no call reference */ +- h->crv[0] = 0; +- } ++ /* Invert the top bit to make it from our sense */ ++ crv = (unsigned) call->cr; ++ h->crv[0] = (((crv >> 8) ^ 0x80) & 0x80) | (crv & 0x7f); + } +- mh = (q931_mh *)(h->contents + h->crlen); ++ *hb = h; ++ ++ *len -= 3;/* Protocol discriminator, call reference length, message type id */ ++ *len -= h->crlen; ++ ++ mh = (q931_mh *) (h->contents + h->crlen); + mh->f = 0; +- *hb = h; + *mhb = mh; +- if (h->crlen == 2) +- *len -= 5; +- else +- *len -= 4; +- + } + +-static int q931_xmit(struct pri *pri, q931_h *h, int len, int cr) ++static int q931_xmit(struct pri *ctrl, q931_h *h, int len, int cr, int uiframe) + { +- q921_transmit_iframe(pri, h, len, cr); ++ if (uiframe) { ++ q921_transmit_uiframe(ctrl, h, len); ++ } else { ++ q921_transmit_iframe(ctrl, h, len, cr); ++ } + /* The transmit operation might dump the q921 header, so logging the q931 + message body after the transmit puts the sections of the message in the + right order in the log */ +- if (pri->debug & PRI_DEBUG_Q931_DUMP) +- q931_dump(pri, h, len, 1); ++ if (ctrl->debug & PRI_DEBUG_Q931_DUMP) ++ q931_dump(ctrl, h, len, 1); + #ifdef LIBPRI_COUNTERS +- pri->q931_txcount++; ++ ctrl->q931_txcount++; + #endif + return 0; + } + +-static int send_message(struct pri *pri, q931_call *c, int msgtype, int ies[]) ++/*! ++ * \internal ++ * \brief Build and send the requested message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg ++ * \param msgtype Q.931 message type to build. ++ * \param ies List of ie's to put in the message. ++ * ++ * \note The ie's in the ie list must be in numerical order. ++ * See Q.931 section 4.5.1 coding rules. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[]) + { + unsigned char buf[1024]; + q931_h *h; +@@ -2636,18 +3969,24 @@ + int offset=0; + int x; + int codeset; +- ++ ++ if (call->outboundbroadcast && call->master_call == call && msgtype != Q931_SETUP) { ++ pri_error(ctrl, ++ "Attempting to use master call record to send %s on BRI PTMP NT %p\n", ++ msg2str(msgtype), ctrl); ++ return -1; ++ } ++ + memset(buf, 0, sizeof(buf)); + len = sizeof(buf); +- init_header(pri, c, buf, &h, &mh, &len); +- mh->msg = msgtype; ++ init_header(ctrl, call, buf, &h, &mh, &len, (msgtype >> 8)); ++ mh->msg = msgtype & 0x00ff; + x=0; + codeset = 0; + while(ies[x] > -1) { +- res = add_ie(pri, c, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset); +- ++ res = add_ie(ctrl, call, mh->msg, ies[x], (q931_ie *)(mh->data + offset), len, &codeset); + if (res < 0) { +- pri_error(pri, "!! Unable to add IE '%s'\n", ie2str(ies[x])); ++ pri_error(ctrl, "!! Unable to add IE '%s'\n", ie2str(ies[x])); + return -1; + } + +@@ -2657,20 +3996,121 @@ + } + /* Invert the logic */ + len = sizeof(buf) - len; +- q931_xmit(c->pri, h, len, 1); +- c->acked = 1; ++ ++ ctrl = call->pri; ++ if (BRI_TE_PTMP(ctrl)) { ++ /* ++ * Must use the BRI subchannel structure to send with the correct TEI. ++ * Note: If the subchannel is NULL then there is no TEI assigned and ++ * we should not be sending anything out at this time. ++ */ ++ ctrl = ctrl->subchannel; ++ } ++ if (ctrl) { ++ int uiframe; ++ ++ switch (msgtype) { ++ case Q931_SETUP: ++ /* ++ * For NT-PTMP mode, we need to check the following: ++ * MODE = NT-PTMP ++ * MESSAGE = SETUP ++ * ++ * If those are true, we need to send the SETUP in a UI frame ++ * instead of an I-frame. ++ */ ++ if (BRI_NT_PTMP(ctrl)) ++ uiframe = 1; ++ else ++ uiframe = 0; ++ break; ++ case Q931_FACILITY: ++ if (ctrl->tei == Q921_TEI_GROUP) { ++ /* Broadcast TEI. */ ++ if (q931_is_dummy_call(call)) { ++ /* ++ * This is a FACILITY message on the dummy call reference ++ * for the broadcast TEI. ++ */ ++ uiframe = 1; ++ } else { ++ pri_error(ctrl, ++ "Attempting to broadcast %s on cref %d\n", ++ msg2str(msgtype), call->cr); ++ return -1; ++ } ++ } else { ++ uiframe = 0; ++ } ++ break; ++ default: ++ uiframe = 0; ++ break; ++ } ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, ++ "Sending message for call %p on %p TEI/SAPI %d/%d, call->pri is %p, TEI/SAPI %d/%d\n", ++ call, ++ ctrl, ctrl->tei, ctrl->sapi, ++ call->pri, call->pri->tei, call->pri->sapi); ++ } ++ q931_xmit(ctrl, h, len, 1, uiframe); ++ } ++ call->acked = 1; + return 0; + } + +-static int status_ies[] = { Q931_CAUSE, Q931_CALL_STATE, -1 }; ++static int maintenance_service_ies[] = { Q931_IE_CHANGE_STATUS, Q931_CHANNEL_IDENT, -1 }; + +-static int q931_status(struct pri *pri, q931_call *c, int cause) ++int maintenance_service_ack(struct pri *ctrl, q931_call *c) + { ++ int pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1; ++ int mt = ATT_SERVICE_ACKNOWLEDGE; ++ ++ if (ctrl->switchtype == PRI_SWITCH_NI2) { ++ pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2; ++ mt = NATIONAL_SERVICE_ACKNOWLEDGE; ++ } ++ return send_message(ctrl, c, (pd << 8) | mt, maintenance_service_ies); ++} ++ ++int maintenance_service(struct pri *ctrl, int span, int channel, int changestatus) ++{ ++ struct q931_call *c; ++ int pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1; ++ int mt = ATT_SERVICE; ++ ++ c = q931_getcall(ctrl, 0 | 0x8000); ++ if (!c) { ++ return -1; ++ } ++ if (channel > -1) { ++ c->channelno = channel & 0xff; ++ c->chanflags = FLAG_EXCLUSIVE; ++ } else { ++ c->channelno = channel; ++ c->chanflags = FLAG_EXCLUSIVE | FLAG_WHOLE_INTERFACE; ++ } ++ c->ds1no = span; ++ c->ds1explicit = 0; ++ c->changestatus = changestatus; ++ ++ if (ctrl->switchtype == PRI_SWITCH_NI2) { ++ pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_2; ++ mt = NATIONAL_SERVICE; ++ } ++ return send_message(ctrl, c, (pd << 8) | mt, maintenance_service_ies); ++} ++ ++static int status_ies[] = { Q931_CAUSE, Q931_IE_CALL_STATE, -1 }; ++ ++static int q931_status(struct pri *ctrl, q931_call *c, int cause) ++{ + q931_call *cur = NULL; + if (!cause) + cause = PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY; + if (c->cr > -1) +- cur = *pri->callpool; ++ cur = *ctrl->callpool; + while(cur) { + if (cur->cr == c->cr) { + cur->cause=cause; +@@ -2681,79 +4121,156 @@ + cur = cur->next; + } + if (!cur) { +- pri_message(pri, "YYY Here we get reset YYY\n"); ++ pri_message(ctrl, "YYY Here we get reset YYY\n"); + /* something went wrong, respond with "no such call" */ + c->ourcallstate = Q931_CALL_STATE_NULL; + c->peercallstate = Q931_CALL_STATE_NULL; + cur=c; + } +- return send_message(pri, cur, Q931_STATUS, status_ies); ++ return send_message(ctrl, cur, Q931_STATUS, status_ies); + } + +-static int information_ies[] = { Q931_IE_KEYPAD_FACILITY, Q931_CALLED_PARTY_NUMBER, -1 }; ++static int information_ies[] = { Q931_CALLED_PARTY_NUMBER, -1 }; + +-int q931_information(struct pri *pri, q931_call *c, char digit) ++int q931_information(struct pri *ctrl, q931_call *c, char digit) + { +- c->callednum[0] = digit; +- c->callednum[1] = '\0'; +- return send_message(pri, c, Q931_INFORMATION, information_ies); ++ c->overlap_digits[0] = digit; ++ c->overlap_digits[1] = '\0'; ++ ++ /* ++ * Since we are doing overlap dialing now, we need to accumulate ++ * the digits into call->called.number.str. ++ */ ++ c->called.number.valid = 1; ++ if (strlen(c->called.number.str) < sizeof(c->called.number.str) - 1) { ++ /* There is enough room for the new digit. */ ++ strcat(c->called.number.str, c->overlap_digits); ++ } ++ ++ return send_message(ctrl, c, Q931_INFORMATION, information_ies); + } + + static int keypad_facility_ies[] = { Q931_IE_KEYPAD_FACILITY, -1 }; + +-int q931_keypad_facility(struct pri *pri, q931_call *call, char *digits) ++int q931_keypad_facility(struct pri *ctrl, q931_call *call, const char *digits) + { + libpri_copy_string(call->keypad_digits, digits, sizeof(call->keypad_digits)); +- return send_message(pri, call, Q931_INFORMATION, keypad_facility_ies); ++ return send_message(ctrl, call, Q931_INFORMATION, keypad_facility_ies); + } + + static int restart_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 }; + +-static int restart_ack(struct pri *pri, q931_call *c) ++static int restart_ack(struct pri *ctrl, q931_call *c) + { +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); + c->peercallstate = Q931_CALL_STATE_NULL; +- return send_message(pri, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies); ++ return send_message(ctrl, c, Q931_RESTART_ACKNOWLEDGE, restart_ack_ies); + } + + static int facility_ies[] = { Q931_IE_FACILITY, -1 }; + +-int q931_facility(struct pri*pri, q931_call *c) ++int q931_facility(struct pri*ctrl, q931_call *c) + { +- return send_message(pri, c, Q931_FACILITY, facility_ies); ++ return send_message(ctrl, c, Q931_FACILITY, facility_ies); + } + +-static int notify_ies[] = { Q931_IE_NOTIFY_IND, -1 }; ++static int notify_ies[] = { Q931_IE_NOTIFY_IND, Q931_IE_REDIRECTION_NUMBER, -1 }; + +-int q931_notify(struct pri *pri, q931_call *c, int channel, int info) ++/*! ++ * \internal ++ * \brief Actually send a NOTIFY message with optional redirection number. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg ++ * \param notify Notification indicator ++ * \param number Redirection number to send if not NULL. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int q931_notify_redirection_helper(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number) + { +- if ((pri->switchtype == PRI_SWITCH_EUROISDN_T1) || (pri->switchtype != PRI_SWITCH_EUROISDN_E1)) { +- if ((info > 0x2) || (info < 0x00)) ++ if (number) { ++ call->redirection_number = *number; ++ } else { ++ q931_party_number_init(&call->redirection_number); ++ } ++ call->notify = notify; ++ return send_message(ctrl, call, Q931_NOTIFY, notify_ies); ++} ++ ++/*! ++ * \brief Send a NOTIFY message with optional redirection number. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg ++ * \param notify Notification indicator ++ * \param number Redirection number to send if not NULL. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number) ++{ ++ int status; ++ unsigned idx; ++ struct q931_call *subcall; ++ ++ if (call->outboundbroadcast && call->master_call == call) { ++ status = 0; ++ for (idx = 0; idx < Q931_MAX_TEI; ++idx) { ++ subcall = call->subcalls[idx]; ++ if (subcall) { ++ /* Send to all subcalls that have given a positive response. */ ++ switch (subcall->ourcallstate) { ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_ACTIVE: ++ if (q931_notify_redirection_helper(ctrl, subcall, notify, number)) { ++ status = -1; ++ } ++ break; ++ default: ++ break; ++ } ++ } ++ } ++ } else { ++ status = q931_notify_redirection_helper(ctrl, call, notify, number); ++ } ++ return status; ++} ++ ++int q931_notify(struct pri *ctrl, q931_call *c, int channel, int info) ++{ ++ if ((ctrl->switchtype == PRI_SWITCH_EUROISDN_T1) || (ctrl->switchtype != PRI_SWITCH_EUROISDN_E1)) { ++ if ((info > 0x2) || (info < 0x00)) { + return 0; ++ } + } + +- if (info >= 0) +- c->notify = info & 0x7F; +- else +- c->notify = -1; +- return send_message(pri, c, Q931_NOTIFY, notify_ies); ++ if (info >= 0) { ++ info = info & 0x7F; ++ } else { ++ info = -1; ++ } ++ return q931_notify_redirection(ctrl, c, info, NULL); + } + + #ifdef ALERTING_NO_PROGRESS + static int call_progress_ies[] = { -1 }; + #else +-static int call_progress_with_cause_ies[] = { Q931_PROGRESS_INDICATOR, Q931_CAUSE, -1 }; ++static int call_progress_with_cause_ies[] = { Q931_CAUSE, Q931_PROGRESS_INDICATOR, -1 }; + + static int call_progress_ies[] = { Q931_PROGRESS_INDICATOR, -1 }; + #endif + +-int q931_call_progress(struct pri *pri, q931_call *c, int channel, int info) ++int q931_call_progress(struct pri *ctrl, q931_call *c, int channel, int info) + { + if (channel) { + c->ds1no = (channel & 0xff00) >> 8; + c->ds1explicit = (channel & 0x10000) >> 16; +- channel &= 0xff; +- c->channelno = channel; ++ c->channelno = channel & 0xff; + } + + if (info) { +@@ -2762,21 +4279,20 @@ + c->progressmask = PRI_PROG_INBAND_AVAILABLE; + } else { + /* PI is mandatory IE for PROGRESS message - Q.931 3.1.8 */ +- pri_error(pri, "XXX Progress message requested but no information is provided\n"); ++ pri_error(ctrl, "XXX Progress message requested but no information is provided\n"); + c->progressmask = 0; + } + + c->alive = 1; +- return send_message(pri, c, Q931_PROGRESS, call_progress_ies); ++ return send_message(ctrl, c, Q931_PROGRESS, call_progress_ies); + } + +-int q931_call_progress_with_cause(struct pri *pri, q931_call *c, int channel, int info, int cause) ++int q931_call_progress_with_cause(struct pri *ctrl, q931_call *c, int channel, int info, int cause) + { + if (channel) { + c->ds1no = (channel & 0xff00) >> 8; + c->ds1explicit = (channel & 0x10000) >> 16; +- channel &= 0xff; +- c->channelno = channel; ++ c->channelno = channel & 0xff; + } + + if (info) { +@@ -2785,7 +4301,7 @@ + c->progressmask = PRI_PROG_INBAND_AVAILABLE; + } else { + /* PI is mandatory IE for PROGRESS message - Q.931 3.1.8 */ +- pri_error(pri, "XXX Progress message requested but no information is provided\n"); ++ pri_error(ctrl, "XXX Progress message requested but no information is provided\n"); + c->progressmask = 0; + } + +@@ -2794,7 +4310,7 @@ + c->causeloc = LOC_PRIV_NET_LOCAL_USER; + + c->alive = 1; +- return send_message(pri, c, Q931_PROGRESS, call_progress_with_cause_ies); ++ return send_message(ctrl, c, Q931_PROGRESS, call_progress_with_cause_ies); + } + + #ifdef ALERTING_NO_PROGRESS +@@ -2803,17 +4319,16 @@ + static int call_proceeding_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 }; + #endif + +-int q931_call_proceeding(struct pri *pri, q931_call *c, int channel, int info) ++int q931_call_proceeding(struct pri *ctrl, q931_call *c, int channel, int info) + { + if (channel) { + c->ds1no = (channel & 0xff00) >> 8; + c->ds1explicit = (channel & 0x10000) >> 16; +- channel &= 0xff; +- c->channelno = channel; ++ c->channelno = channel & 0xff; + } + c->chanflags &= ~FLAG_PREFERRED; + c->chanflags |= FLAG_EXCLUSIVE; +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_INCOMING_CALL_PROCEEDING); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_INCOMING_CALL_PROCEEDING); + c->peercallstate = Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING; + if (info) { + c->progloc = LOC_PRIV_NET_LOCAL_USER; +@@ -2823,62 +4338,73 @@ + c->progressmask = 0; + c->proc = 1; + c->alive = 1; +- return send_message(pri, c, Q931_CALL_PROCEEDING, call_proceeding_ies); ++ return send_message(ctrl, c, Q931_CALL_PROCEEDING, call_proceeding_ies); + } + #ifndef ALERTING_NO_PROGRESS +-static int alerting_ies[] = { Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, -1 }; ++static int alerting_ies[] = { Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_IE_USER_USER, -1 }; + #else +-static int alerting_ies[] = { -1 }; ++static int alerting_ies[] = { Q931_IE_FACILITY, -1 }; + #endif + +-int q931_alerting(struct pri *pri, q931_call *c, int channel, int info) ++int q931_alerting(struct pri *ctrl, q931_call *c, int channel, int info) + { + if (!c->proc) +- q931_call_proceeding(pri, c, channel, 0); ++ q931_call_proceeding(ctrl, c, channel, 0); + if (info) { + c->progloc = LOC_PRIV_NET_LOCAL_USER; + c->progcode = CODE_CCITT; + c->progressmask = PRI_PROG_INBAND_AVAILABLE; + } else + c->progressmask = 0; +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_RECEIVED); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_RECEIVED); + c->peercallstate = Q931_CALL_STATE_CALL_DELIVERED; + c->alive = 1; +- return send_message(pri, c, Q931_ALERTING, alerting_ies); ++ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_QSIG: ++ if (c->local_id.name.valid) { ++ /* Send calledName with ALERTING */ ++ rose_called_name_encode(ctrl, c, Q931_ALERTING); ++ } ++ break; ++ default: ++ break; ++ } ++ ++ return send_message(ctrl, c, Q931_ALERTING, alerting_ies); + } + +-static int connect_ies[] = { Q931_CHANNEL_IDENT, Q931_PROGRESS_INDICATOR, -1 }; ++static int setup_ack_ies[] = { Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, -1 }; + +-int q931_setup_ack(struct pri *pri, q931_call *c, int channel, int nonisdn) ++int q931_setup_ack(struct pri *ctrl, q931_call *c, int channel, int nonisdn) + { + if (channel) { + c->ds1no = (channel & 0xff00) >> 8; + c->ds1explicit = (channel & 0x10000) >> 16; +- channel &= 0xff; +- c->channelno = channel; ++ c->channelno = channel & 0xff; + } + c->chanflags &= ~FLAG_PREFERRED; + c->chanflags |= FLAG_EXCLUSIVE; +- if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) { ++ if (nonisdn && (ctrl->switchtype != PRI_SWITCH_DMS100)) { + c->progloc = LOC_PRIV_NET_LOCAL_USER; + c->progcode = CODE_CCITT; + c->progressmask = PRI_PROG_CALLED_NOT_ISDN; + } else + c->progressmask = 0; +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OVERLAP_RECEIVING); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OVERLAP_RECEIVING); + c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING; + c->alive = 1; +- return send_message(pri, c, Q931_SETUP_ACKNOWLEDGE, connect_ies); ++ return send_message(ctrl, c, Q931_SETUP_ACKNOWLEDGE, setup_ack_ies); + } + + /* T313 expiry, first time */ + static void pri_connect_timeout(void *data) + { + struct q931_call *c = data; +- struct pri *pri = c->pri; +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "Timed out looking for connect acknowledge\n"); +- q931_disconnect(pri, c, PRI_CAUSE_NORMAL_CLEARING); ++ struct pri *ctrl = c->pri; ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, "Timed out looking for connect acknowledge\n"); ++ q931_disconnect(ctrl, c, PRI_CAUSE_NORMAL_CLEARING); + + } + +@@ -2886,85 +4412,120 @@ + static void pri_release_timeout(void *data) + { + struct q931_call *c = data; +- struct pri *pri = c->pri; +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "Timed out looking for release complete\n"); ++ struct pri *ctrl = c->pri; ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, "Timed out looking for release complete\n"); + c->t308_timedout++; + c->alive = 1; + + /* The call to q931_release will re-schedule T308 */ +- q931_release(pri, c, c->cause); ++ q931_release(ctrl, c, c->cause); + } + + /* T308 expiry, second time */ + static void pri_release_finaltimeout(void *data) + { + struct q931_call *c = data; +- struct pri *pri = c->pri; ++ struct pri *ctrl = c->pri; + c->alive = 1; +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "Final time-out looking for release complete\n"); ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, "Final time-out looking for release complete\n"); + c->t308_timedout++; + c->ourcallstate = Q931_CALL_STATE_NULL; + c->peercallstate = Q931_CALL_STATE_NULL; +- pri->schedev = 1; +- pri->ev.e = PRI_EVENT_HANGUP_ACK; +- pri->ev.hangup.channel = c->channelno; +- pri->ev.hangup.cause = c->cause; +- pri->ev.hangup.cref = c->cr; +- pri->ev.hangup.call = c; +- pri->ev.hangup.aoc_units = c->aoc_units; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); +- q931_hangup(pri, c, c->cause); ++ q931_clr_subcommands(ctrl); ++ ctrl->schedev = 1; ++ ctrl->ev.e = PRI_EVENT_HANGUP_ACK; ++ ctrl->ev.hangup.subcmds = &ctrl->subcmds; ++ ctrl->ev.hangup.channel = q931_encode_channel(c); ++ ctrl->ev.hangup.cause = c->cause; ++ ctrl->ev.hangup.cref = c->cr; ++ ctrl->ev.hangup.call = c->master_call; ++ ctrl->ev.hangup.aoc_units = c->aoc_units; ++ ctrl->ev.hangup.call_held = NULL; ++ ctrl->ev.hangup.call_active = NULL; ++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); ++ pri_hangup(ctrl, c, c->cause); + } + + /* T305 expiry, first time */ + static void pri_disconnect_timeout(void *data) + { + struct q931_call *c = data; +- struct pri *pri = c->pri; +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "Timed out looking for release\n"); ++ struct pri *ctrl = c->pri; ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, "Timed out looking for release\n"); + c->alive = 1; +- q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING); ++ q931_release(ctrl, c, PRI_CAUSE_NORMAL_CLEARING); + } + +-int q931_connect(struct pri *pri, q931_call *c, int channel, int nonisdn) ++static int connect_ies[] = { ++ Q931_CHANNEL_IDENT, ++ Q931_IE_FACILITY, ++ Q931_PROGRESS_INDICATOR, ++ Q931_DISPLAY, ++ Q931_IE_CONNECTED_NUM, ++ Q931_IE_CONNECTED_SUBADDR, ++ -1 ++}; ++ ++int q931_connect(struct pri *ctrl, q931_call *c, int channel, int nonisdn) + { + if (channel) { + c->ds1no = (channel & 0xff00) >> 8; + c->ds1explicit = (channel & 0x10000) >> 16; +- channel &= 0xff; +- c->channelno = channel; ++ c->channelno = channel & 0xff; + } + c->chanflags &= ~FLAG_PREFERRED; + c->chanflags |= FLAG_EXCLUSIVE; +- if (nonisdn && (pri->switchtype != PRI_SWITCH_DMS100)) { ++ if (nonisdn && (ctrl->switchtype != PRI_SWITCH_DMS100)) { + c->progloc = LOC_PRIV_NET_LOCAL_USER; + c->progcode = CODE_CCITT; + c->progressmask = PRI_PROG_CALLED_NOT_ISDN; + } else + c->progressmask = 0; +- if(pri->localtype == PRI_NETWORK || pri->switchtype == PRI_SWITCH_QSIG) +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); ++ if(ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG) ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE); + else +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CONNECT_REQUEST); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CONNECT_REQUEST); + c->peercallstate = Q931_CALL_STATE_ACTIVE; + c->alive = 1; + /* Connect request timer */ +- if (c->retranstimer) +- pri_schedule_del(pri, c->retranstimer); ++ pri_schedule_del(ctrl, c->retranstimer); + c->retranstimer = 0; +- if ((c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && (pri->bri || (!pri->subchannel))) +- c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T313], pri_connect_timeout, c); +- return send_message(pri, c, Q931_CONNECT, connect_ies); ++ if ((c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && (ctrl->bri || (!ctrl->subchannel))) ++ c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T313], pri_connect_timeout, c); ++ ++ if (c->redirecting.state == Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3) { ++ c->redirecting.state = Q931_REDIRECTING_STATE_IDLE; ++ /* Send DivertingLegInformation3 with CONNECT. */ ++ c->redirecting.to = c->local_id; ++ if (!c->redirecting.to.number.valid) { ++ q931_party_number_init(&c->redirecting.to.number); ++ c->redirecting.to.number.valid = 1; ++ c->redirecting.to.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ } ++ rose_diverting_leg_information3_encode(ctrl, c, Q931_CONNECT); ++ } ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_QSIG: ++ if (c->local_id.name.valid) { ++ /* Send connectedName with CONNECT */ ++ rose_connected_name_encode(ctrl, c, Q931_CONNECT); ++ } ++ break; ++ default: ++ break; ++ } ++ return send_message(ctrl, c, Q931_CONNECT, connect_ies); + } + + static int release_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 }; + +-int q931_release(struct pri *pri, q931_call *c, int cause) ++int q931_release(struct pri *ctrl, q931_call *c, int cause) + { +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RELEASE_REQUEST); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RELEASE_REQUEST); + /* c->peercallstate stays the same */ + if (c->alive) { + c->alive = 0; +@@ -2972,26 +4533,26 @@ + c->causecode = CODE_CCITT; + c->causeloc = LOC_PRIV_NET_LOCAL_USER; + if (c->acked) { +- if (c->retranstimer) +- pri_schedule_del(pri, c->retranstimer); ++ pri_schedule_del(ctrl, c->retranstimer); + if (!c->t308_timedout) { +- c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T308], pri_release_timeout, c); ++ c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T308], pri_release_timeout, c); + } else { +- c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T308], pri_release_finaltimeout, c); ++ c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T308], pri_release_finaltimeout, c); + } +- return send_message(pri, c, Q931_RELEASE, release_ies); ++ return send_message(ctrl, c, Q931_RELEASE, release_ies); + } else +- return send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies); /* Yes, release_ies, not release_complete_ies */ ++ return send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_ies); /* Yes, release_ies, not release_complete_ies */ + } else + return 0; + } + + static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 }; + +-int q931_restart(struct pri *pri, int channel) ++int q931_restart(struct pri *ctrl, int channel) + { + struct q931_call *c; +- c = q931_getcall(pri, 0 | 0x8000, 1); ++ ++ c = q931_getcall(ctrl, 0 | 0x8000); + if (!c) + return -1; + if (!channel) +@@ -2999,20 +4560,19 @@ + c->ri = 0; + c->ds1no = (channel & 0xff00) >> 8; + c->ds1explicit = (channel & 0x10000) >> 16; +- channel &= 0xff; +- c->channelno = channel; ++ c->channelno = channel & 0xff; + c->chanflags &= ~FLAG_PREFERRED; + c->chanflags |= FLAG_EXCLUSIVE; +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RESTART); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RESTART); + c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST; +- return send_message(pri, c, Q931_RESTART, restart_ies); ++ return send_message(ctrl, c, Q931_RESTART, restart_ies); + } + +-static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_USER_USER, -1 }; ++static int disconnect_ies[] = { Q931_CAUSE, Q931_IE_FACILITY, Q931_IE_USER_USER, -1 }; + +-int q931_disconnect(struct pri *pri, q931_call *c, int cause) ++int q931_disconnect(struct pri *ctrl, q931_call *c, int cause) + { +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_DISCONNECT_REQUEST); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_DISCONNECT_REQUEST); + c->peercallstate = Q931_CALL_STATE_DISCONNECT_INDICATION; + if (c->alive) { + c->alive = 0; +@@ -3020,27 +4580,125 @@ + c->causecode = CODE_CCITT; + c->causeloc = LOC_PRIV_NET_LOCAL_USER; + c->sendhangupack = 1; +- if (c->retranstimer) +- pri_schedule_del(pri, c->retranstimer); +- c->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T305], pri_disconnect_timeout, c); +- return send_message(pri, c, Q931_DISCONNECT, disconnect_ies); ++ pri_schedule_del(ctrl, c->retranstimer); ++ c->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T305], pri_disconnect_timeout, c); ++ return send_message(ctrl, c, Q931_DISCONNECT, disconnect_ies); + } else + return 0; + } + +-static int setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_PROGRESS_INDICATOR, Q931_NETWORK_SPEC_FAC, Q931_DISPLAY, +- Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_REDIRECTING_NUMBER, Q931_IE_USER_USER, Q931_SENDING_COMPLETE, +- Q931_IE_ORIGINATING_LINE_INFO, Q931_IE_GENERIC_DIGITS, -1 }; ++static int setup_ies[] = { ++ Q931_BEARER_CAPABILITY, ++ Q931_CHANNEL_IDENT, ++ Q931_IE_FACILITY, ++ Q931_PROGRESS_INDICATOR, ++ Q931_NETWORK_SPEC_FAC, ++ Q931_DISPLAY, ++ Q931_IE_KEYPAD_FACILITY, ++ Q931_REVERSE_CHARGE_INDIC, ++ Q931_CALLING_PARTY_NUMBER, ++ Q931_CALLING_PARTY_SUBADDR, ++ Q931_CALLED_PARTY_NUMBER, ++ Q931_CALLED_PARTY_SUBADDR, ++ Q931_REDIRECTING_NUMBER, ++ Q931_IE_USER_USER, ++ Q931_SENDING_COMPLETE, ++ Q931_IE_ORIGINATING_LINE_INFO, ++ Q931_IE_GENERIC_DIGITS, ++ -1 ++}; + +-static int gr303_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, -1 }; ++static int gr303_setup_ies[] = { ++ Q931_BEARER_CAPABILITY, ++ Q931_CHANNEL_IDENT, ++ -1 ++}; + +-static int cis_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLED_PARTY_NUMBER, -1 }; ++/*! Call Independent Signalling SETUP ie's */ ++static int cis_setup_ies[] = { ++ Q931_BEARER_CAPABILITY, ++ Q931_CHANNEL_IDENT, ++ Q931_IE_FACILITY, ++ Q931_IE_KEYPAD_FACILITY, ++ Q931_CALLING_PARTY_NUMBER, ++ Q931_CALLING_PARTY_SUBADDR, ++ Q931_CALLED_PARTY_NUMBER, ++ Q931_CALLED_PARTY_SUBADDR, ++ Q931_SENDING_COMPLETE, ++ -1 ++}; + +-int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req) ++static void stop_t303(struct q931_call *call) + { ++ /* T303 should only be running on the master call */ ++ pri_schedule_del(call->master_call->pri, call->master_call->t303_timer); ++ call->master_call->t303_timer = 0; ++} ++ ++static void t303_expiry(void *data); ++ ++static void start_t303(struct q931_call *call) ++{ ++ if (call->t303_timer) { ++ pri_error(call->pri, "Should not have T303 set when starting again. Stopping first\n"); ++ stop_t303(call); ++ } ++ ++ //pri_error(call->pri, "T303 should be %d\n", call->pri->timers[PRI_TIMER_T303]); ++ call->t303_timer = pri_schedule_event(call->pri, call->pri->timers[PRI_TIMER_T303], t303_expiry, call); ++} ++ ++static void pri_fake_clearing(void *data); ++ ++static void t303_expiry(void *data) ++{ ++ struct q931_call *c = data; ++ struct pri *ctrl = c->pri; + int res; +- +- ++ ++ c->t303_expirycnt++; ++ c->t303_timer = 0; ++ ++ if (c->cause != -1) { ++ /* We got a DISCONNECT, RELEASE, or RELEASE_COMPLETE and no other responses. */ ++ pri_fake_clearing(c); ++ } else if (c->t303_expirycnt < 2) { ++ if (ctrl->subchannel && !ctrl->bri) ++ res = send_message(ctrl, c, Q931_SETUP, gr303_setup_ies); ++ else if (c->cis_call) ++ res = send_message(ctrl, c, Q931_SETUP, cis_setup_ies); ++ else ++ res = send_message(ctrl, c, Q931_SETUP, setup_ies); ++ ++ if (res) { ++ pri_error(c->pri, "Error resending setup message!\n"); ++ } ++ start_t303(c); ++ } else { ++ c->cause = PRI_CAUSE_NO_USER_RESPONSE; ++ pri_fake_clearing(c); ++ } ++} ++ ++int q931_setup(struct pri *ctrl, q931_call *c, struct pri_sr *req) ++{ ++ int res; ++ ++ if (!req->called.number.valid && (!req->keypad_digits || !req->keypad_digits[0])) { ++ /* No called number or keypad digits to send. */ ++ return -1; ++ } ++ ++ c->called = req->called; ++ libpri_copy_string(c->overlap_digits, req->called.number.str, sizeof(c->overlap_digits)); ++ ++ if (req->keypad_digits) { ++ libpri_copy_string(c->keypad_digits, req->keypad_digits, ++ sizeof(c->keypad_digits)); ++ } else { ++ c->keypad_digits[0] = '\0'; ++ } ++ + c->transcapability = req->transmode; + c->transmoderate = TRANS_MODE_64_CIRCUIT; + if (!req->userl1) +@@ -3050,89 +4708,68 @@ + c->userl3 = -1; + c->ds1no = (req->channel & 0xff00) >> 8; + c->ds1explicit = (req->channel & 0x10000) >> 16; +- req->channel &= 0xff; +- if ((pri->localtype == PRI_CPE) && pri->subchannel && !pri->bri) { +- req->channel = 0; +- req->exclusive = 0; ++ if ((ctrl->localtype == PRI_CPE) && ctrl->subchannel && !ctrl->bri) { ++ c->channelno = 0; ++ c->chanflags = 0; ++ } else { ++ c->channelno = req->channel & 0xff; ++ if (req->exclusive) { ++ c->chanflags = FLAG_EXCLUSIVE; ++ } else { ++ c->chanflags = FLAG_PREFERRED; ++ } + } +- +- c->channelno = req->channel; ++ + c->slotmap = -1; + c->nonisdn = req->nonisdn; + c->newcall = 0; +- c->justsignalling = req->justsignalling; ++ c->cis_call = req->cis_call; ++ c->cis_auto_disconnect = req->cis_auto_disconnect; + c->complete = req->numcomplete; +- if (req->exclusive) +- c->chanflags = FLAG_EXCLUSIVE; +- else if (c->channelno) +- c->chanflags = FLAG_PREFERRED; +- if (req->caller) { +- libpri_copy_string(c->callernum, req->caller, sizeof(c->callernum)); +- c->callerplan = req->callerplan; +- if (req->callername) +- libpri_copy_string(c->callername, req->callername, sizeof(c->callername)); +- else +- c->callername[0] = '\0'; +- if ((pri->switchtype == PRI_SWITCH_DMS100) || +- (pri->switchtype == PRI_SWITCH_ATT4ESS)) { +- /* Doesn't like certain presentation types */ +- if (!(req->callerpres & 0x7c)) +- req->callerpres = PRES_ALLOWED_NETWORK_NUMBER; +- } +- c->callerpres = req->callerpres; +- } else { +- c->callernum[0] = '\0'; +- c->callername[0] = '\0'; +- c->callerplan = PRI_UNKNOWN; +- c->callerpres = PRES_NUMBER_NOT_AVAILABLE; ++ ++ if (req->caller.number.valid) { ++ c->local_id = req->caller; ++ q931_party_id_fixup(ctrl, &c->local_id); + } +- if (req->redirectingnum) { +- libpri_copy_string(c->redirectingnum, req->redirectingnum, sizeof(c->redirectingnum)); +- c->redirectingplan = req->redirectingplan; +- if ((pri->switchtype == PRI_SWITCH_DMS100) || +- (pri->switchtype == PRI_SWITCH_ATT4ESS)) { +- /* Doesn't like certain presentation types */ +- if (!(req->redirectingpres & 0x7c)) +- req->redirectingpres = PRES_ALLOWED_NETWORK_NUMBER; +- } +- c->redirectingpres = req->redirectingpres; +- c->redirectingreason = req->redirectingreason; +- } else { +- c->redirectingnum[0] = '\0'; +- c->redirectingplan = PRI_UNKNOWN; +- c->redirectingpres = PRES_NUMBER_NOT_AVAILABLE; +- c->redirectingreason = PRI_REDIR_UNKNOWN; ++ ++ if (req->redirecting.from.number.valid) { ++ c->redirecting = req->redirecting; ++ q931_party_id_fixup(ctrl, &c->redirecting.from); ++ q931_party_id_fixup(ctrl, &c->redirecting.to); ++ q931_party_id_fixup(ctrl, &c->redirecting.orig_called); + } +- if (req->called) { +- libpri_copy_string(c->callednum, req->called, sizeof(c->callednum)); +- c->calledplan = req->calledplan; +- } else +- return -1; + + if (req->useruserinfo) + libpri_copy_string(c->useruserinfo, req->useruserinfo, sizeof(c->useruserinfo)); + else + c->useruserinfo[0] = '\0'; + +- if (req->nonisdn && (pri->switchtype == PRI_SWITCH_NI2)) ++ if (req->nonisdn && (ctrl->switchtype == PRI_SWITCH_NI2)) + c->progressmask = PRI_PROG_CALLER_NOT_ISDN; + else + c->progressmask = 0; + +- pri_call_add_standard_apdus(pri, c); ++ c->reversecharge = req->reversecharge; + +- if (pri->subchannel && !pri->bri) +- res = send_message(pri, c, Q931_SETUP, gr303_setup_ies); +- else if (c->justsignalling) +- res = send_message(pri, c, Q931_SETUP, cis_setup_ies); ++ pri_call_add_standard_apdus(ctrl, c); ++ ++ if (ctrl->subchannel && !ctrl->bri) ++ res = send_message(ctrl, c, Q931_SETUP, gr303_setup_ies); ++ else if (c->cis_call) ++ res = send_message(ctrl, c, Q931_SETUP, cis_setup_ies); + else +- res = send_message(pri, c, Q931_SETUP, setup_ies); ++ res = send_message(ctrl, c, Q931_SETUP, setup_ies); + if (!res) { + c->alive = 1; + /* make sure we call PRI_EVENT_HANGUP_ACK once we send/receive RELEASE_COMPLETE */ + c->sendhangupack = 1; +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_INITIATED); +- c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING; ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_INITIATED); ++ c->peercallstate = Q931_CALL_STATE_CALL_PRESENT; ++ c->t303_expirycnt = 0; ++ if (BRI_NT_PTMP(ctrl)) { ++ c->outboundbroadcast = 1; ++ } ++ start_t303(c); + } + return res; + +@@ -3140,22 +4777,22 @@ + + static int release_complete_ies[] = { Q931_IE_USER_USER, -1 }; + +-static int q931_release_complete(struct pri *pri, q931_call *c, int cause) ++static int q931_release_complete(struct pri *ctrl, q931_call *c, int cause) + { + int res = 0; +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); + c->peercallstate = Q931_CALL_STATE_NULL; + if (cause > -1) { + c->cause = cause; + c->causecode = CODE_CCITT; + c->causeloc = LOC_PRIV_NET_LOCAL_USER; + /* release_ies has CAUSE in it */ +- res = send_message(pri, c, Q931_RELEASE_COMPLETE, release_ies); ++ res = send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_ies); + } else +- res = send_message(pri, c, Q931_RELEASE_COMPLETE, release_complete_ies); ++ res = send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_complete_ies); + c->alive = 0; + /* release the structure */ +- res += q931_hangup(pri,c,cause); ++ res += pri_hangup(ctrl, c, cause); + return res; + } + +@@ -3163,46 +4800,553 @@ + + static int gr303_connect_acknowledge_ies[] = { Q931_CHANNEL_IDENT, -1 }; + +-static int q931_connect_acknowledge(struct pri *pri, q931_call *c) ++static int q931_connect_acknowledge(struct pri *ctrl, q931_call *c) + { +- if (pri->subchannel && !pri->bri) { +- if (pri->localtype == PRI_CPE) +- return send_message(pri, c, Q931_CONNECT_ACKNOWLEDGE, gr303_connect_acknowledge_ies); ++ if (ctrl->subchannel && !ctrl->bri) { ++ if (ctrl->localtype == PRI_CPE) ++ return send_message(ctrl, c, Q931_CONNECT_ACKNOWLEDGE, gr303_connect_acknowledge_ies); + } else +- return send_message(pri, c, Q931_CONNECT_ACKNOWLEDGE, connect_acknowledge_ies); ++ return send_message(ctrl, c, Q931_CONNECT_ACKNOWLEDGE, connect_acknowledge_ies); + return 0; + } + +-int q931_hangup(struct pri *pri, q931_call *c, int cause) ++/*! ++ * \internal ++ * \brief Find the winning subcall if it exists or current call if not outboundbroadcast. ++ * ++ * \param call Starting Q.931 call record of search. ++ * ++ * \retval winning-call or given call if not outboundbroadcast. ++ * \retval NULL if no winning call yet. ++ */ ++static struct q931_call *q931_find_winning_call(struct q931_call *call) + { ++ struct q931_call *master; ++ ++ master = call->master_call; ++ if (master->outboundbroadcast) { ++ /* We have potential subcalls. Now get the winning call if declared yet. */ ++ if (master->pri_winner < 0) { ++ /* Winner not declared yet.*/ ++ call = NULL; ++ } else { ++ call = master->subcalls[master->pri_winner]; ++ } ++ } ++ return call; ++} ++ ++/*! ++ * \internal ++ * \brief Send HOLD message response wait timeout. ++ * ++ * \param data Q.931 call leg. (Master Q.931 subcall structure) ++ * ++ * \return Nothing ++ */ ++static void q931_hold_timeout(void *data) ++{ ++ struct q931_call *call = data; ++ struct pri *ctrl = call->pri; ++ ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "Time-out waiting for HOLD response\n"); ++ } ++ ++ /* Ensure that the timer is deleted. */ ++ pri_schedule_del(ctrl, call->hold_timer); ++ call->hold_timer = 0; ++ ++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE); ++ ++ q931_clr_subcommands(ctrl); ++ ctrl->schedev = 1; ++ ctrl->ev.e = PRI_EVENT_HOLD_REJ; ++ ctrl->ev.hold_rej.channel = q931_encode_channel(call); ++ ctrl->ev.hold_rej.call = call; ++ ctrl->ev.hold_rej.cause = PRI_CAUSE_MESSAGE_TYPE_NONEXIST; ++ ctrl->ev.hold_rej.subcmds = &ctrl->subcmds; ++} ++ ++/*! ++ * \internal ++ * \brief Determine if a hold request is allowed now. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (Master Q.931 subcall structure) ++ * ++ * \retval TRUE if we can send a HOLD request. ++ * \retval FALSE if not allowed. ++ */ ++static int q931_is_hold_allowed(const struct pri *ctrl, const struct q931_call *call) ++{ ++ int allowed; ++ ++ allowed = 0; ++ switch (call->ourcallstate) { ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ case Q931_CALL_STATE_CONNECT_REQUEST: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ if (q931_is_ptmp(ctrl)) { ++ /* HOLD request only allowed in these states if point-to-point mode. */ ++ break; ++ } ++ /* Fall through */ ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_ACTIVE: ++ switch (call->hold_state) { ++ case Q931_HOLD_STATE_IDLE: ++ allowed = 1; ++ break; ++ default: ++ break; ++ } ++ break; ++ case Q931_CALL_STATE_DISCONNECT_INDICATION: ++ case Q931_CALL_STATE_RELEASE_REQUEST: ++ /* Ignore HOLD request in these states. */ ++ break; ++ default: ++ break; ++ } ++ ++ return allowed; ++} ++ ++static int hold_ies[] = { ++ -1 ++}; ++ ++/*! ++ * \brief Send the HOLD message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (Master Q.931 subcall structure) ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int q931_send_hold(struct pri *ctrl, struct q931_call *call) ++{ ++ struct q931_call *winner; ++ ++ winner = q931_find_winning_call(call); ++ if (!winner || !q931_is_hold_allowed(ctrl, call)) { ++ return -1; ++ } ++ pri_schedule_del(ctrl, call->hold_timer); ++ call->hold_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T_HOLD], ++ q931_hold_timeout, call); ++ if (send_message(ctrl, winner, Q931_HOLD, hold_ies)) { ++ pri_schedule_del(ctrl, call->hold_timer); ++ call->hold_timer = 0; ++ return -1; ++ } ++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_HOLD_REQ); ++ return 0; ++} ++ ++static int hold_ack_ies[] = { ++ -1 ++}; ++ ++/*! ++ * \brief Send the HOLD ACKNOWLEDGE message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (Master Q.931 subcall structure) ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call) ++{ ++ struct q931_call *winner; ++ ++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD); ++ ++ winner = q931_find_winning_call(call); ++ if (!winner) { ++ return -1; ++ } ++ ++ /* Call is now on hold so forget the channel. */ ++ winner->channelno = 0;/* No channel */ ++ winner->ds1no = 0; ++ winner->ds1explicit = 0; ++ winner->chanflags = 0; ++ ++ return send_message(ctrl, winner, Q931_HOLD_ACKNOWLEDGE, hold_ack_ies); ++} ++ ++static int hold_reject_ies[] = { ++ Q931_CAUSE, ++ -1 ++}; ++ ++/*! ++ * \internal ++ * \brief Send the HOLD REJECT message only. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (subcall) ++ * \param cause Q.931 cause code for rejecting the hold request. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int q931_send_hold_rej_msg(struct pri *ctrl, struct q931_call *call, int cause) ++{ ++ call->cause = cause; ++ call->causecode = CODE_CCITT; ++ call->causeloc = LOC_PRIV_NET_LOCAL_USER; ++ return send_message(ctrl, call, Q931_HOLD_REJECT, hold_reject_ies); ++} ++ ++/*! ++ * \brief Send the HOLD REJECT message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (Master Q.931 subcall structure) ++ * \param cause Q.931 cause code for rejecting the hold request. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int q931_send_hold_rej(struct pri *ctrl, struct q931_call *call, int cause) ++{ ++ struct q931_call *winner; ++ ++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE); ++ ++ winner = q931_find_winning_call(call); ++ if (!winner) { ++ return -1; ++ } ++ ++ return q931_send_hold_rej_msg(ctrl, winner, cause); ++} ++ ++/*! ++ * \internal ++ * \brief Send RETRIEVE message response wait timeout. ++ * ++ * \param data Q.931 call leg. (Master Q.931 subcall structure) ++ * ++ * \return Nothing ++ */ ++static void q931_retrieve_timeout(void *data) ++{ ++ struct q931_call *call = data; ++ struct pri *ctrl = call->pri; ++ struct q931_call *winner; ++ ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "Time-out waiting for RETRIEVE response\n"); ++ } ++ ++ /* Ensure that the timer is deleted. */ ++ pri_schedule_del(ctrl, call->hold_timer); ++ call->hold_timer = 0; ++ ++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD); ++ ++ winner = q931_find_winning_call(call); ++ if (winner) { ++ /* Call is still on hold so forget the channel. */ ++ winner->channelno = 0;/* No channel */ ++ winner->ds1no = 0; ++ winner->ds1explicit = 0; ++ winner->chanflags = 0; ++ } ++ ++ q931_clr_subcommands(ctrl); ++ ctrl->schedev = 1; ++ ctrl->ev.e = PRI_EVENT_RETRIEVE_REJ; ++ ctrl->ev.retrieve_rej.channel = q931_encode_channel(call); ++ ctrl->ev.retrieve_rej.call = call; ++ ctrl->ev.retrieve_rej.cause = PRI_CAUSE_MESSAGE_TYPE_NONEXIST; ++ ctrl->ev.retrieve_rej.subcmds = &ctrl->subcmds; ++} ++ ++/*! ++ * \internal ++ * \brief Determine if a retrieve request is allowed now. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (Master Q.931 subcall structure) ++ * ++ * \retval TRUE if we can send a RETRIEVE request. ++ * \retval FALSE if not allowed. ++ */ ++static int q931_is_retrieve_allowed(const struct pri *ctrl, const struct q931_call *call) ++{ ++ int allowed; ++ ++ allowed = 0; ++ switch (call->ourcallstate) { ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ case Q931_CALL_STATE_CONNECT_REQUEST: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ if (q931_is_ptmp(ctrl)) { ++ /* RETRIEVE request only allowed in these states if point-to-point mode. */ ++ break; ++ } ++ /* Fall through */ ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_ACTIVE: ++ switch (call->hold_state) { ++ case Q931_HOLD_STATE_CALL_HELD: ++ allowed = 1; ++ break; ++ default: ++ break; ++ } ++ break; ++ case Q931_CALL_STATE_DISCONNECT_INDICATION: ++ case Q931_CALL_STATE_RELEASE_REQUEST: ++ /* Ignore RETRIEVE request in these states. */ ++ break; ++ default: ++ break; ++ } ++ ++ return allowed; ++} ++ ++static int retrieve_ies[] = { ++ Q931_CHANNEL_IDENT, ++ -1 ++}; ++ ++/*! ++ * \brief Send the RETRIEVE message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (Master Q.931 subcall structure) ++ * \param channel Encoded channel id to use. If zero do not send channel id. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int q931_send_retrieve(struct pri *ctrl, struct q931_call *call, int channel) ++{ ++ struct q931_call *winner; ++ ++ winner = q931_find_winning_call(call); ++ if (!winner || !q931_is_retrieve_allowed(ctrl, call)) { ++ return -1; ++ } ++ ++ if (channel) { ++ winner->ds1no = (channel & 0xff00) >> 8; ++ winner->ds1explicit = (channel & 0x10000) >> 16; ++ winner->channelno = channel & 0xff; ++ if (ctrl->localtype == PRI_NETWORK) { ++ winner->chanflags = FLAG_EXCLUSIVE; ++ } else { ++ winner->chanflags = FLAG_PREFERRED; ++ } ++ } else { ++ /* Do not send Q931_CHANNEL_IDENT */ ++ winner->chanflags = 0; ++ } ++ ++ pri_schedule_del(ctrl, call->hold_timer); ++ call->hold_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T_RETRIEVE], ++ q931_retrieve_timeout, call); ++ if (send_message(ctrl, winner, Q931_RETRIEVE, retrieve_ies)) { ++ pri_schedule_del(ctrl, call->hold_timer); ++ call->hold_timer = 0; ++ ++ /* Call is still on hold so forget the channel. */ ++ winner->channelno = 0;/* No channel */ ++ winner->ds1no = 0; ++ winner->ds1explicit = 0; ++ winner->chanflags = 0; ++ return -1; ++ } ++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_RETRIEVE_REQ); ++ return 0; ++} ++ ++static int retrieve_ack_ies[] = { ++ Q931_CHANNEL_IDENT, ++ -1 ++}; ++ ++/*! ++ * \brief Send the RETRIEVE ACKNOWLEDGE message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (Master Q.931 subcall structure) ++ * \param channel Encoded channel id to use. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int q931_send_retrieve_ack(struct pri *ctrl, struct q931_call *call, int channel) ++{ ++ struct q931_call *winner; ++ ++ winner = q931_find_winning_call(call); ++ if (!winner) { ++ return -1; ++ } ++ ++ winner->ds1no = (channel & 0xff00) >> 8; ++ winner->ds1explicit = (channel & 0x10000) >> 16; ++ winner->channelno = channel & 0xff; ++ winner->chanflags = FLAG_EXCLUSIVE; ++ ++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE); ++ ++ return send_message(ctrl, winner, Q931_RETRIEVE_ACKNOWLEDGE, retrieve_ack_ies); ++} ++ ++static int retrieve_reject_ies[] = { ++ Q931_CAUSE, ++ -1 ++}; ++ ++/*! ++ * \internal ++ * \brief Send the RETRIEVE REJECT message only. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (subcall) ++ * \param cause Q.931 cause code for rejecting the retrieve request. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++static int q931_send_retrieve_rej_msg(struct pri *ctrl, struct q931_call *call, int cause) ++{ ++ call->cause = cause; ++ call->causecode = CODE_CCITT; ++ call->causeloc = LOC_PRIV_NET_LOCAL_USER; ++ return send_message(ctrl, call, Q931_RETRIEVE_REJECT, retrieve_reject_ies); ++} ++ ++/*! ++ * \brief Send the RETRIEVE REJECT message. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. (Master Q.931 subcall structure) ++ * \param cause Q.931 cause code for rejecting the retrieve request. ++ * ++ * \retval 0 on success. ++ * \retval -1 on error. ++ */ ++int q931_send_retrieve_rej(struct pri *ctrl, struct q931_call *call, int cause) ++{ ++ struct q931_call *winner; ++ ++ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD); ++ ++ winner = q931_find_winning_call(call); ++ if (!winner) { ++ return -1; ++ } ++ ++ /* Call is still on hold so forget the channel. */ ++ winner->channelno = 0;/* No channel */ ++ winner->ds1no = 0; ++ winner->ds1explicit = 0; ++ winner->chanflags = 0; ++ ++ return q931_send_retrieve_rej_msg(ctrl, winner, cause); ++} ++ ++static int pri_internal_clear(void *data); ++ ++/* Fake RELEASE for NT-PTMP initiated SETUPs w/o response */ ++static void pri_fake_clearing(void *data) ++{ ++ struct q931_call *c = data; ++ struct pri *ctrl = c->pri; ++ ++ c->performing_fake_clearing = 1; ++ if (pri_internal_clear(c) == Q931_RES_HAVEEVENT) ++ ctrl->schedev = 1; ++} ++ ++static void pri_create_fake_clearing(struct q931_call *c, struct pri *master) ++{ ++ c->pri = master; ++ ++ pri_schedule_del(master, c->retranstimer); ++ c->retranstimer = pri_schedule_event(master, 0, pri_fake_clearing, c); ++} ++ ++//static int q931_get_subcall_count(struct q931_call *call); ++ ++static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause) ++{ + int disconnect = 1; + int release_compl = 0; +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "NEW_HANGUP DEBUG: Calling q931_hangup, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate)); +- if (!pri || !c) ++ int t303_was_running = c->master_call->t303_timer; ++ ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, ++ "NEW_HANGUP DEBUG: Calling q931_hangup, ourstate %s, peerstate %s, hold-state %s\n", ++ q931_call_state_str(c->ourcallstate), ++ q931_call_state_str(c->peercallstate), ++ q931_hold_state_str(c->master_call->hold_state)); ++ if (!ctrl || !c) + return -1; + /* If mandatory IE was missing, insist upon that cause code */ + if (c->cause == PRI_CAUSE_MANDATORY_IE_MISSING) + cause = c->cause; +- if (cause == 34 || cause == 44 || cause == 82 || cause == 1 || cause == 81) { ++ switch (cause) { ++ case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION: ++ case PRI_CAUSE_REQUESTED_CHAN_UNAVAIL: ++ case PRI_CAUSE_IDENTIFIED_CHANNEL_NOTEXIST: ++ case PRI_CAUSE_UNALLOCATED: ++ case PRI_CAUSE_INVALID_CALL_REFERENCE: + /* We'll send RELEASE_COMPLETE with these causes */ + disconnect = 0; + release_compl = 1; +- } +- if (cause == 6 || cause == 7 || cause == 26) { ++ break; ++ case PRI_CAUSE_CHANNEL_UNACCEPTABLE: ++ case PRI_CAUSE_CALL_AWARDED_DELIVERED: ++ case PRI_CAUSE_NONSELECTED_USER_CLEARING: + /* We'll send RELEASE with these causes */ + disconnect = 0; ++ break; ++ default: ++ break; + } ++ if (c->cis_call) { ++ disconnect = 0; ++ } ++ ++ c->hangupinitiated = 1; ++ stop_t303(c); ++ + /* All other causes we send with DISCONNECT */ + switch(c->ourcallstate) { + case Q931_CALL_STATE_NULL: + if (c->peercallstate == Q931_CALL_STATE_NULL) + /* free the resources if we receive or send REL_COMPL */ +- q931_destroycall(pri, c->cr); ++ pri_destroycall(ctrl, c); + else if (c->peercallstate == Q931_CALL_STATE_RELEASE_REQUEST) +- q931_release_complete(pri,c,cause); ++ q931_release_complete(ctrl,c,cause); + break; + case Q931_CALL_STATE_CALL_INITIATED: ++ if (c->outboundbroadcast && c->master_call == c && t303_was_running) { ++ //c->fakeclearing = 1; ++ //c->alive = 0; ++ /* We need to fake a received clearing sequence in this case... */ ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "Faking clearing\n"); ++ } ++ pri_create_fake_clearing(c, PRI_MASTER(ctrl)); ++ /* This means that we never got a response from a TEI */ ++ return 0; ++ } + /* we sent SETUP */ + case Q931_CALL_STATE_OVERLAP_SENDING: + /* received SETUP_ACKNOWLEDGE */ +@@ -3221,29 +5365,45 @@ + case Q931_CALL_STATE_OVERLAP_RECEIVING: + /* received SETUP_ACKNOWLEDGE */ + /* send DISCONNECT in general */ +- if (c->peercallstate != Q931_CALL_STATE_NULL && c->peercallstate != Q931_CALL_STATE_DISCONNECT_REQUEST && c->peercallstate != Q931_CALL_STATE_DISCONNECT_INDICATION && c->peercallstate != Q931_CALL_STATE_RELEASE_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART_REQUEST && c->peercallstate != Q931_CALL_STATE_RESTART) { ++ switch (c->peercallstate) { ++ default: + if (disconnect) +- q931_disconnect(pri,c,cause); ++ q931_disconnect(ctrl,c,cause); + else if (release_compl) +- q931_release_complete(pri,c,cause); ++ q931_release_complete(ctrl,c,cause); + else +- q931_release(pri,c,cause); +- } else +- pri_error(pri, "Wierd, doing nothing but this shouldn't happen, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate)); ++ q931_release(ctrl,c,cause); ++ break; ++ case Q931_CALL_STATE_NULL: ++ case Q931_CALL_STATE_DISCONNECT_REQUEST: ++ case Q931_CALL_STATE_DISCONNECT_INDICATION: ++ case Q931_CALL_STATE_RELEASE_REQUEST: ++ case Q931_CALL_STATE_RESTART_REQUEST: ++ case Q931_CALL_STATE_RESTART: ++ pri_error(ctrl, ++ "Wierd, doing nothing but this shouldn't happen, ourstate %s, peerstate %s\n", ++ q931_call_state_str(c->ourcallstate), ++ q931_call_state_str(c->peercallstate)); ++ break; ++ } + break; + case Q931_CALL_STATE_ACTIVE: + /* received CONNECT */ +- q931_disconnect(pri,c,cause); ++ if (c->cis_call) { ++ q931_release(ctrl, c, cause); ++ break; ++ } ++ q931_disconnect(ctrl,c,cause); + break; + case Q931_CALL_STATE_DISCONNECT_REQUEST: + /* sent DISCONNECT */ +- q931_release(pri,c,cause); ++ q931_release(ctrl,c,cause); + break; + case Q931_CALL_STATE_DISCONNECT_INDICATION: + /* received DISCONNECT */ + if (c->peercallstate == Q931_CALL_STATE_DISCONNECT_REQUEST) { + c->alive = 1; +- q931_release(pri,c,cause); ++ q931_release(ctrl,c,cause); + } + break; + case Q931_CALL_STATE_RELEASE_REQUEST: +@@ -3253,75 +5413,129 @@ + case Q931_CALL_STATE_RESTART: + case Q931_CALL_STATE_RESTART_REQUEST: + /* sent RESTART */ +- pri_error(pri, "q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s\n",callstate2str(c->ourcallstate),callstate2str(c->peercallstate)); ++ pri_error(ctrl, ++ "q931_hangup shouldn't be called in this state, ourstate %s, peerstate %s\n", ++ q931_call_state_str(c->ourcallstate), ++ q931_call_state_str(c->peercallstate)); + break; + default: +- pri_error(pri, "We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s\n", +- c->ourcallstate, +- callstate2str(c->ourcallstate), +- callstate2str(c->peercallstate)); ++ pri_error(ctrl, ++ "We're not yet handling hanging up when our state is %d, contact support@digium.com, ourstate %s, peerstate %s\n", ++ c->ourcallstate, ++ q931_call_state_str(c->ourcallstate), ++ q931_call_state_str(c->peercallstate)); + return -1; + } + /* we did handle hangup properly at this point */ + return 0; + } + +-int q931_receive(struct pri *pri, q931_h *h, int len) ++static void initiate_hangup_if_needed(struct pri *pri, q931_call *call, int cause); ++ ++int q931_hangup(struct pri *ctrl, q931_call *call, int cause) + { +- q931_mh *mh; +- q931_call *c; +- q931_ie *ie; +- unsigned int x; +- int y; +- int res; +- int r; +- int mandies[MAX_MAND_IES]; +- int missingmand; +- int codeset, cur_codeset; +- int last_ie[8]; +- struct apdu_event *cur = NULL; ++ int i; + +- memset(last_ie, 0, sizeof(last_ie)); +- if (pri->debug & PRI_DEBUG_Q931_DUMP) +- q931_dump(pri, h, len, 0); +-#ifdef LIBPRI_COUNTERS +- pri->q931_rxcount++; +-#endif +- mh = (q931_mh *)(h->contents + h->crlen); +- if ((h->pd == 0x3) || (h->pd == 0x43)) { +- /* This is the weird maintenance stuff. We majorly +- KLUDGE this by changing byte 4 from a 0xf (SERVICE) +- to a 0x7 (SERVICE ACKNOWLEDGE) */ +- h->raw[h->crlen + 2] -= 0x8; +- q931_xmit(pri, h, len, 1); +- return 0; +- } else if (h->pd != pri->protodisc) { +- pri_error(pri, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd); +- return 0; ++ if (call->master_call->outboundbroadcast) { ++ if (call->master_call == call) { ++ int slaves = 0; ++ ++ /* Master is called with hangup - initiate hangup with slaves */ ++ for (i = 0; i < Q931_MAX_TEI; i++) { ++ if (call->subcalls[i]) { ++ slaves++; ++ if (i == call->master_call->pri_winner) { ++ __q931_hangup(call->subcalls[i]->pri, call->subcalls[i], cause); ++ } else { ++ initiate_hangup_if_needed(call->subcalls[i]->pri, call->subcalls[i], cause); ++ } ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "%s: Hanging up %d, winner %d\n", __FUNCTION__, ++ i, call->master_call->pri_winner); ++ } ++ } ++ } ++ ++ call->hangupinitiated = 1; ++ ++ if ((!slaves && (call->master_call->pri_winner < 0)) || (call->performing_fake_clearing)) { ++ __q931_hangup(ctrl, call, cause); ++ } ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "%s: Slaves %d\n", __FUNCTION__, slaves); ++ } ++ return 0; ++ } else { ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "%s: Slave hangup\n", __FUNCTION__); ++ } ++ return __q931_hangup(ctrl, call, cause); ++ } ++ } else { ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "%s: other hangup\n", __FUNCTION__); ++ } ++ return __q931_hangup(ctrl, call, cause); + } +- c = q931_getcall(pri, q931_cr(h), 0); +- if (!c) { +- pri_error(pri, "Unable to locate call %d\n", q931_cr(h)); ++ return 0; ++} ++ ++static int prepare_to_handle_maintenance_message(struct pri *ctrl, q931_mh *mh, q931_call *c) ++{ ++ if ((!ctrl) || (!mh) || (!c)) { + return -1; + } +- /* Preliminary handling */ ++ /* SERVICE messages are a superset of messages that can take b-channels ++ * or entire d-channels in and out of service */ + switch(mh->msg) { ++ /* the ATT_SERVICE/ATT_SERVICE_ACKNOWLEDGE and NATIONAL_SERVICE/NATIONAL_SERVICE_ACKNOWLEDGE ++ * are mirrors of each other. We only have to check for one type because they are pre-handled ++ * the same way as each other */ ++ case ATT_SERVICE: ++ case ATT_SERVICE_ACKNOWLEDGE: ++ c->channelno = -1; ++ c->slotmap = -1; ++ c->chanflags = 0; ++ c->ds1explicit = 0; ++ c->ds1no = 0; ++ c->cis_call = 0; ++ c->ri = -1; ++ c->changestatus = -1; ++ break; ++ default: ++ pri_error(ctrl, "!! Don't know how to pre-handle maintenance message type '%d'\n", mh->msg); ++ return -1; ++ } ++ return 0; ++} ++ ++static int prepare_to_handle_q931_message(struct pri *ctrl, q931_mh *mh, q931_call *c) ++{ ++ if ((!ctrl) || (!mh) || (!c)) { ++ return -1; ++ } ++ ++ switch(mh->msg) { + case Q931_RESTART: +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "-- Processing Q.931 Restart\n"); ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, "-- Processing Q.931 Restart\n"); + /* Reset information */ + c->channelno = -1; + c->slotmap = -1; + c->chanflags = 0; + c->ds1no = 0; ++ c->ds1explicit = 0; ++ c->cis_call = 0; + c->ri = -1; + break; + case Q931_FACILITY: +- c->callername[0] = '\0'; ++ if (q931_is_dummy_call(c)) { ++ q931_party_address_init(&c->called); ++ } + break; + case Q931_SETUP: +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, "-- Processing Q.931 Call Setup\n"); ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, "-- Processing Q.931 Call Setup\n"); + c->channelno = -1; + c->slotmap = -1; + c->chanflags = 0; +@@ -3334,29 +5548,25 @@ + c->userl2 = -1; + c->userl3 = -1; + c->rateadaption = -1; +- c->calledplan = -1; +- c->callerplan = -1; +- c->callerpres = -1; +- c->callernum[0] = '\0'; +- c->callednum[0] = '\0'; +- c->callername[0] = '\0'; +- c->callerani[0] = '\0'; +- c->callerplanani = -1; +- c->redirectingplan = -1; +- c->redirectingpres = -1; +- c->redirectingreason = -1; +- c->origcalledplan = -1; +- c->origcalledpres = -1; +- c->origredirectingreason = -1; +- c->redirectingnum[0] = '\0'; +- c->origcallednum[0] = '\0'; +- c->redirectingname[0] = '\0'; +- c->origcalledname[0] = '\0'; ++ ++ q931_party_address_init(&c->called); ++ q931_party_id_init(&c->local_id); ++ q931_party_id_init(&c->remote_id); ++ q931_party_redirecting_init(&c->redirecting); ++ ++ /* ++ * Make sure that keypad and overlap digit buffers are empty in ++ * case they are not in the message. ++ */ ++ c->keypad_digits[0] = '\0'; ++ c->overlap_digits[0] = '\0'; ++ + c->useruserprotocoldisc = -1; + c->useruserinfo[0] = '\0'; + c->complete = 0; + c->nonisdn = 0; + c->aoc_units = -1; ++ c->reversecharge = -1; + /* Fall through */ + case Q931_CONNECT: + case Q931_ALERTING: +@@ -3369,8 +5579,7 @@ + c->progressmask = 0; + break; + case Q931_CONNECT_ACKNOWLEDGE: +- if (c->retranstimer) +- pri_schedule_del(pri, c->retranstimer); ++ pri_schedule_del(ctrl, c->retranstimer); + c->retranstimer = 0; + break; + case Q931_RELEASE: +@@ -3379,14 +5588,12 @@ + c->causecode = -1; + c->causeloc = -1; + c->aoc_units = -1; +- if (c->retranstimer) +- pri_schedule_del(pri, c->retranstimer); ++ pri_schedule_del(ctrl, c->retranstimer); + c->retranstimer = 0; + c->useruserinfo[0] = '\0'; + break; + case Q931_RELEASE_COMPLETE: +- if (c->retranstimer) +- pri_schedule_del(pri, c->retranstimer); ++ pri_schedule_del(ctrl, c->retranstimer); + c->retranstimer = 0; + c->useruserinfo[0] = '\0'; + /* Fall through */ +@@ -3394,45 +5601,252 @@ + c->cause = -1; + c->causecode = -1; + c->causeloc = -1; +- c->sugcallstate = -1; ++ c->sugcallstate = Q931_CALL_STATE_NOT_SET; + c->aoc_units = -1; + break; + case Q931_RESTART_ACKNOWLEDGE: + c->channelno = -1; ++ c->ds1no = 0; ++ c->ds1explicit = 0; ++ c->cis_call = 0; + break; + case Q931_INFORMATION: +- c->callednum[0] = '\0'; ++ /* ++ * Make sure that keypad and overlap digit buffers are empty in ++ * case they are not in the message. ++ */ ++ c->keypad_digits[0] = '\0'; ++ c->overlap_digits[0] = '\0'; + break; + case Q931_STATUS_ENQUIRY: + break; + case Q931_SETUP_ACKNOWLEDGE: + break; + case Q931_NOTIFY: ++ q931_party_number_init(&c->redirection_number); + break; +- case Q931_USER_INFORMATION: +- case Q931_SEGMENT: +- case Q931_CONGESTION_CONTROL: + case Q931_HOLD: ++ break; + case Q931_HOLD_ACKNOWLEDGE: ++ break; + case Q931_HOLD_REJECT: ++ c->cause = -1; ++ break; + case Q931_RETRIEVE: ++ c->channelno = 0xFF; ++ c->ds1no = 0; ++ c->ds1explicit = 0; ++ break; + case Q931_RETRIEVE_ACKNOWLEDGE: ++ break; + case Q931_RETRIEVE_REJECT: ++ c->cause = -1; ++ break; ++ case Q931_USER_INFORMATION: ++ case Q931_SEGMENT: ++ case Q931_CONGESTION_CONTROL: + case Q931_RESUME: + case Q931_RESUME_ACKNOWLEDGE: + case Q931_RESUME_REJECT: + case Q931_SUSPEND: + case Q931_SUSPEND_ACKNOWLEDGE: + case Q931_SUSPEND_REJECT: +- pri_error(pri, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); ++ pri_error(ctrl, "!! Not yet handling pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + /* Fall through */ + default: +- pri_error(pri, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); +- q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); ++ pri_error(ctrl, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); ++ q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); + if (c->newcall) +- q931_destroycall(pri,c->cr); ++ pri_destroycall(ctrl, c); + return -1; + } ++ return 0; ++} ++ ++static struct q931_call *q931_get_subcall_winner(struct q931_call *master) ++{ ++ if (master->pri_winner < 0) { ++ return NULL; ++ } else { ++ return master->subcalls[master->pri_winner]; ++ } ++} ++ ++static void initiate_hangup_if_needed(struct pri *pri, q931_call *call, int cause) ++{ ++ if (!call->hangupinitiated) { ++ q931_hangup(pri, call, cause); ++ call->alive = 0; ++ } ++} ++ ++#if 0 ++static int q931_get_subcall_count(struct q931_call *call) ++{ ++ int count = 0; ++ int i; ++ ++ call = call->master_call; ++ for (i = 0; i < Q931_MAX_TEI; i++) { ++ if (call->subcalls[i]) ++ count++; ++ } ++ ++ return count; ++} ++#endif ++ ++static void q931_set_subcall_winner(struct q931_call *subcall) ++{ ++ struct q931_call *realcall = subcall->master_call; ++ int i; ++ ++ /* Set the winner first */ ++ for (i = 0; i < Q931_MAX_TEI; i++) { ++ if (realcall->subcalls[i] && realcall->subcalls[i] == subcall) { ++ realcall->pri_winner = i; ++ } ++ } ++ if (realcall->pri_winner < 0) { ++ pri_error(subcall->pri, "We should always find the winner in the list!\n"); ++ return; ++ } ++ ++ /* Start tear down of calls that were not chosen */ ++ for (i = 0; i < Q931_MAX_TEI; i++) { ++ if (realcall->subcalls[i] && realcall->subcalls[i] != subcall) { ++ initiate_hangup_if_needed(realcall->subcalls[i]->pri, realcall->subcalls[i], ++ PRI_CAUSE_NONSELECTED_USER_CLEARING); ++ } ++ } ++} ++ ++static struct q931_call *q931_get_subcall(struct pri *ctrl, struct q931_call *master_call) ++{ ++ int i; ++ struct q931_call *cur; ++ int firstfree = -1; ++ ++ /* First try to locate our subcall */ ++ for (i = 0; i < Q931_MAX_TEI; i++) { ++ if (master_call->subcalls[i]) { ++ if (master_call->subcalls[i]->pri == ctrl) { ++ return master_call->subcalls[i]; ++ } ++ } else if (firstfree == -1) { ++ firstfree = i; ++ } ++ } ++ if (firstfree < 0) { ++ pri_error(ctrl, "Tried to add more than %d TEIs to call and failed\n", ++ Q931_MAX_TEI); ++ return NULL; ++ } ++ ++ /* Create new subcall. */ ++ cur = malloc(sizeof(*cur)); ++ if (!cur) { ++ pri_error(ctrl, "Unable to allocate call\n"); ++ return NULL; ++ } ++ *cur = *master_call; ++ cur->pri = ctrl; ++ cur->next = NULL; ++ cur->apdus = NULL; ++ cur->bridged_call = NULL; ++ //cur->master_call = master_call; /* We get this assignment for free. */ ++ for (i = 0; i < Q931_MAX_TEI; ++i) { ++ cur->subcalls[i] = NULL; ++ } ++ cur->t303_timer = 0;/* T303 should only be on on the master call */ ++ cur->hold_timer = 0; ++ cur->retranstimer = 0; ++ ++ /* Assume we sent a SETUP and this is the first response to it from this peer. */ ++ cur->ourcallstate = Q931_CALL_STATE_CALL_INITIATED; ++ cur->peercallstate = Q931_CALL_STATE_CALL_PRESENT; ++ ++ master_call->subcalls[firstfree] = cur; ++ ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "Adding subcall %p for TEI %d to call %p at position %d\n", ++ cur, ctrl->tei, master_call, firstfree); ++ } ++ /* Should only get here if the TEI is not found */ ++ return cur; ++} ++ ++int q931_receive(struct pri *ctrl, q931_h *h, int len) ++{ ++ q931_mh *mh; ++ q931_call *c; ++ q931_ie *ie; ++ unsigned int x; ++ int y; ++ int res; ++ int r; ++ int mandies[MAX_MAND_IES]; ++ int missingmand; ++ int codeset, cur_codeset; ++ int last_ie[8]; ++ int cref; ++ ++ memset(last_ie, 0, sizeof(last_ie)); ++ if (ctrl->debug & PRI_DEBUG_Q931_DUMP) ++ q931_dump(ctrl, h, len, 0); ++#ifdef LIBPRI_COUNTERS ++ ctrl->q931_rxcount++; ++#endif ++ mh = (q931_mh *)(h->contents + h->crlen); ++ if ((h->pd != ctrl->protodisc) && (h->pd != MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) && (h->pd != MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) { ++ pri_error(ctrl, "Warning: unknown/inappropriate protocol discriminator received (%02x/%d)\n", h->pd, h->pd); ++ return 0; ++ } ++ if (((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) && (!ctrl->service_message_support)) { ++ /* Real service message support has not been enabled (and is OFF in libpri by default), ++ * so we have to revert to the 'traditional' KLUDGE of changing byte 4 from a 0xf (SERVICE) ++ * to a 0x7 (SERVICE ACKNOWLEDGE) */ ++ /* This is the weird maintenance stuff. We majorly ++ KLUDGE this by changing byte 4 from a 0xf (SERVICE) ++ to a 0x7 (SERVICE ACKNOWLEDGE) */ ++ h->raw[h->crlen + 2] -= 0x8; ++ q931_xmit(ctrl, h, len, 1, 0); ++ return 0; ++ } ++ ++ cref = q931_cr(h); ++ c = q931_getcall(ctrl, cref); ++ if (!c) { ++ pri_error(ctrl, "Unable to locate call %d\n", cref); ++ return -1; ++ } ++ if (c->master_call->outboundbroadcast && ctrl != PRI_MASTER(ctrl)) { ++ c = q931_get_subcall(ctrl, c->master_call); ++ if (!c) { ++ pri_error(ctrl, "Unable to locate subcall for %d\n", cref); ++ return -1; ++ } ++ } ++ ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, ++ "Received message for call %p on %p TEI/SAPI %d/%d, call->pri is %p TEI/SAPI %d/%d\n", ++ c, ++ ctrl, ctrl->tei, ctrl->sapi, ++ c->pri, c->pri->tei, c->pri->sapi); ++ } ++ ++ /* Preliminary handling */ ++ ctrl->facility.count = 0; ++ c->connected_number_in_message = 0; ++ c->redirecting_number_in_message = 0; ++ if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) { ++ prepare_to_handle_maintenance_message(ctrl, mh, c); ++ } else { ++ prepare_to_handle_q931_message(ctrl, mh, c); ++ } ++ q931_clr_subcommands(ctrl); ++ + /* Handle IEs */ + memset(mandies, 0, sizeof(mandies)); + missingmand = 0; +@@ -3453,7 +5867,7 @@ + } + r = ielen(ie); + if (r > len) { +- pri_error(pri, "XXX Message longer than it should be?? XXX\n"); ++ pri_error(ctrl, "XXX Message longer than it should be?? XXX\n"); + return -1; + } + /* Special processing for codeset shifts */ +@@ -3461,16 +5875,16 @@ + case Q931_LOCKING_SHIFT: + y = ie->ie & 7; /* Requested codeset */ + /* Locking shifts couldn't go to lower codeset, and couldn't follows non-locking shifts - verify this */ +- if ((cur_codeset != codeset) && (pri->debug & PRI_DEBUG_Q931_ANOMALY)) +- pri_message(pri, "XXX Locking shift immediately follows non-locking shift (from %d through %d to %d) XXX\n", codeset, cur_codeset, y); ++ if ((cur_codeset != codeset) && (ctrl->debug & PRI_DEBUG_Q931_ANOMALY)) ++ pri_message(ctrl, "XXX Locking shift immediately follows non-locking shift (from %d through %d to %d) XXX\n", codeset, cur_codeset, y); + if (y > 0) { +- if ((y < codeset) && (pri->debug & PRI_DEBUG_Q931_ANOMALY)) +- pri_error(pri, "!! Trying to locked downshift codeset from %d to %d !!\n", codeset, y); ++ if ((y < codeset) && (ctrl->debug & PRI_DEBUG_Q931_ANOMALY)) ++ pri_error(ctrl, "!! Trying to locked downshift codeset from %d to %d !!\n", codeset, y); + codeset = cur_codeset = y; + } + else { + /* Locking shift to codeset 0 is forbidden by all specifications */ +- pri_error(pri, "!! Invalid locking shift to codeset 0 !!\n"); ++ pri_error(ctrl, "!! Invalid locking shift to codeset 0 !!\n"); + } + break; + case Q931_NON_LOCKING_SHIFT: +@@ -3480,24 +5894,24 @@ + /* Sanity check for IE code order */ + if (!(ie->ie & 0x80)) { + if (last_ie[cur_codeset] > ie->ie) { +- if ((pri->debug & PRI_DEBUG_Q931_ANOMALY)) +- pri_message(pri, "XXX Out-of-order IE %d at codeset %d (last was %d)\n", ie->ie, cur_codeset, last_ie[cur_codeset]); ++ if ((ctrl->debug & PRI_DEBUG_Q931_ANOMALY)) ++ pri_message(ctrl, "XXX Out-of-order IE %d at codeset %d (last was %d)\n", ie->ie, cur_codeset, last_ie[cur_codeset]); + } + else + last_ie[cur_codeset] = ie->ie; + } + /* Ignore non-locking shifts for TR41459-based signalling */ +- switch (pri->switchtype) { ++ switch (ctrl->switchtype) { + case PRI_SWITCH_LUCENT5E: + case PRI_SWITCH_ATT4ESS: + if (cur_codeset != codeset) { +- if ((pri->debug & PRI_DEBUG_Q931_DUMP)) +- pri_message(pri, "XXX Ignoring IE %d for temporary codeset %d XXX\n", ie->ie, cur_codeset); ++ if ((ctrl->debug & PRI_DEBUG_Q931_DUMP)) ++ pri_message(ctrl, "XXX Ignoring IE %d for temporary codeset %d XXX\n", ie->ie, cur_codeset); + break; + } + /* Fall through */ + default: +- y = q931_handle_ie(cur_codeset, pri, c, mh->msg, ie); ++ y = q931_handle_ie(cur_codeset, ctrl, c, mh->msg, ie); + /* XXX Applicable to codeset 0 only? XXX */ + if (!cur_codeset && !(ie->ie & 0xf0) && (y < 0)) + mandies[MAX_MAND_IES - 1] = Q931_FULL_IE(cur_codeset, ie->ie); +@@ -3512,33 +5926,562 @@ + for (x=0;x<MAX_MAND_IES;x++) { + if (mandies[x]) { + /* check if there is no channel identification when we're configured as network -> that's not an error */ +- if (((pri->localtype != PRI_NETWORK) || (mh->msg != Q931_SETUP) || (mandies[x] != Q931_CHANNEL_IDENT)) && ++ if (((ctrl->localtype != PRI_NETWORK) || (mh->msg != Q931_SETUP) || (mandies[x] != Q931_CHANNEL_IDENT)) && + ((mh->msg != Q931_PROGRESS) || (mandies[x] != Q931_PROGRESS_INDICATOR))) { +- pri_error(pri, "XXX Missing handling for mandatory IE %d (cs%d, %s) XXX\n", Q931_IE_IE(mandies[x]), Q931_IE_CODESET(mandies[x]), ie2str(mandies[x])); ++ pri_error(ctrl, "XXX Missing handling for mandatory IE %d (cs%d, %s) XXX\n", Q931_IE_IE(mandies[x]), Q931_IE_CODESET(mandies[x]), ie2str(mandies[x])); + missingmand++; + } + } + } +- ++ ++ /* Now handle the facility ie's after all the other ie's were processed. */ ++ q931_handle_facilities(ctrl, c, mh->msg); ++ + /* Post handling */ ++ if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) { ++ res = post_handle_maintenance_message(ctrl, h->pd, mh, c); ++ } else { ++ int allow_event = 1, allow_posthandle = 1; ++ ++ if (c->master_call->outboundbroadcast) { ++ nt_ptmp_handle_q931_message(ctrl, mh, c, &allow_event, &allow_posthandle); ++ } ++ ++ if (allow_posthandle) { ++ res = post_handle_q931_message(ctrl, mh, c, missingmand); ++ ++ if (res == Q931_RES_HAVEEVENT && !allow_event) { ++ res = 0; ++ } ++ } else { ++ res = 0; ++ } ++ } ++ return res; ++} ++ ++static int post_handle_maintenance_message(struct pri *ctrl, int protodisc, struct q931_mh *mh, struct q931_call *c) ++{ ++ /* Do some maintenance stuff */ ++ if (((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) && (mh->msg == ATT_SERVICE)) ++ || ((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2) && (mh->msg == NATIONAL_SERVICE))) { ++ if (c->channelno > 0) { ++ ctrl->ev.e = PRI_EVENT_SERVICE; ++ ctrl->ev.service.channel = q931_encode_channel(c); ++ ctrl->ev.service.changestatus = 0x0f & c->changestatus; ++ } else { ++ switch (0x0f & c->changestatus) { ++ case SERVICE_CHANGE_STATUS_INSERVICE: ++ ctrl->ev.e = PRI_EVENT_DCHAN_UP; ++ q921_dchannel_up(ctrl); ++ break; ++ case SERVICE_CHANGE_STATUS_OUTOFSERVICE: ++ ctrl->ev.e = PRI_EVENT_DCHAN_DOWN; ++ q921_dchannel_down(ctrl); ++ break; ++ default: ++ pri_error(ctrl, "!! Don't know how to handle span service change status '%d'\n", (0x0f & c->changestatus)); ++ return -1; ++ } ++ } ++ maintenance_service_ack(ctrl, c); ++ return Q931_RES_HAVEEVENT; ++ } ++ if (((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) && (mh->msg == ATT_SERVICE_ACKNOWLEDGE)) ++ || ((protodisc == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2) && (mh->msg == NATIONAL_SERVICE_ACKNOWLEDGE))) { ++ if (c->channelno > 0) { ++ ctrl->ev.e = PRI_EVENT_SERVICE_ACK; ++ ctrl->ev.service_ack.channel = q931_encode_channel(c); ++ ctrl->ev.service_ack.changestatus = 0x0f & c->changestatus; ++ } else { ++ switch (0x0f & c->changestatus) { ++ case SERVICE_CHANGE_STATUS_INSERVICE: ++ ctrl->ev.e = PRI_EVENT_DCHAN_UP; ++ q921_dchannel_up(ctrl); ++ break; ++ case SERVICE_CHANGE_STATUS_OUTOFSERVICE: ++ ctrl->ev.e = PRI_EVENT_DCHAN_DOWN; ++ q921_dchannel_down(ctrl); ++ break; ++ default: ++ pri_error(ctrl, "!! Don't know how to handle span service change status '%d'\n", (0x0f & c->changestatus)); ++ return -1; ++ } ++ } ++ return Q931_RES_HAVEEVENT; ++ } ++ ++ pri_error(ctrl, "!! Don't know how to post-handle maintenance message type %d\n", mh->msg); ++ return -1; ++} ++ ++/*! ++ * \internal ++ * \brief Rank the given Q.931 call state for call etablishment. ++ * ++ * \param state Q.931 call state to rank for competing PTMP NT calls. ++ * ++ * \return Call establishment state ranking. ++ */ ++static enum Q931_RANKED_CALL_STATE q931_rank_state(enum Q931_CALL_STATE state) ++{ ++ enum Q931_RANKED_CALL_STATE rank; ++ ++ switch (state) { ++ case Q931_CALL_STATE_CALL_INITIATED: ++ case Q931_CALL_STATE_CALL_PRESENT: ++ rank = Q931_RANKED_CALL_STATE_PRESENT; ++ break; ++ case Q931_CALL_STATE_OVERLAP_SENDING: ++ case Q931_CALL_STATE_OVERLAP_RECEIVING: ++ rank = Q931_RANKED_CALL_STATE_OVERLAP; ++ break; ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ rank = Q931_RANKED_CALL_STATE_PROCEEDING; ++ break; ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ case Q931_CALL_STATE_CONNECT_REQUEST: ++ rank = Q931_RANKED_CALL_STATE_ALERTING; ++ break; ++ case Q931_CALL_STATE_ACTIVE: ++ case Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE: ++ rank = Q931_RANKED_CALL_STATE_CONNECT; ++ break; ++ default: ++ rank = Q931_RANKED_CALL_STATE_OTHER; ++ break; ++ } ++ ++ return rank; ++} ++ ++/*! ++ * \brief Determine if the master will pass an event to the upper layer. ++ * ++ * \param ctrl D channel controller. ++ * \param subcall Q.931 call leg. ++ * \param msg_type Current message type being processed. ++ * ++ * \note This function must parallel nt_ptmp_handle_q931_message(). ++ * ++ * \retval TRUE if the master will pass an event to the upper layer. ++ * \retval FALSE if the event will be blocked. ++ */ ++int q931_master_pass_event(struct pri *ctrl, struct q931_call *subcall, int msg_type) ++{ ++ struct q931_call *winner; ++ struct q931_call *master; ++ enum Q931_RANKED_CALL_STATE master_rank; ++ enum Q931_RANKED_CALL_STATE subcall_rank; ++ int will_pass; /*!< TRUE if the master will pass an event to the upper layer. */ ++ ++ master = subcall->master_call; ++ if (subcall == master) { ++ /* We are the master call so of course the master will pass an event. */ ++ return 1; ++ } ++ ++ winner = q931_get_subcall_winner(master); ++ if (winner && subcall == winner) { ++ /* We are the winner so of course the master will pass an event. */ ++ return 1; ++ } ++ ++ master_rank = q931_rank_state(master->ourcallstate); ++ will_pass = 0; ++ switch (msg_type) { ++ case Q931_SETUP_ACKNOWLEDGE: ++#if 0 /* Overlap dialing in PTMP NT mode not supported at the present time. */ ++ if (master_rank < Q931_RANKED_CALL_STATE_OVERLAP) { ++ will_pass = 1; ++ } ++#endif /* Overlap dialing in PTMP NT mode not supported at the present time. */ ++ break; ++ case Q931_CALL_PROCEEDING: ++ if (master_rank < Q931_RANKED_CALL_STATE_PROCEEDING) { ++ will_pass = 1; ++ } ++ break; ++ case Q931_PROGRESS: ++ /* ++ * We will just ignore this message since there could be multiple devices ++ * competing for this call. Who has access to the B channel at this time ++ * to give in-band signals anyway? ++ */ ++ break; ++ case Q931_ALERTING: ++ if (master_rank < Q931_RANKED_CALL_STATE_ALERTING) { ++ will_pass = 1; ++ } ++ break; ++ case Q931_CONNECT: ++ if (master_rank < Q931_RANKED_CALL_STATE_CONNECT) { ++ /* We are expected to be the winner for the next message. */ ++ will_pass = 1; ++ } ++ break; ++ case Q931_DISCONNECT: ++ case Q931_RELEASE: ++ case Q931_RELEASE_COMPLETE: ++ /* Only deal with the winner. */ ++ break; ++ case Q931_FACILITY: ++ case Q931_NOTIFY: ++ if (!winner) { ++ /* The overlap rank does not count here. */ ++ if (master_rank == Q931_RANKED_CALL_STATE_OVERLAP) { ++ master_rank = Q931_RANKED_CALL_STATE_PRESENT; ++ } ++ subcall_rank = q931_rank_state(subcall->ourcallstate); ++ if (subcall_rank == Q931_RANKED_CALL_STATE_OVERLAP) { ++ subcall_rank = Q931_RANKED_CALL_STATE_PRESENT; ++ } ++ if (master_rank == subcall_rank) { ++ /* ++ * No winner yet but the subcall is as advanced as the master. ++ * Allow the supplementary service event to pass. ++ */ ++ will_pass = 1; ++ } ++ } ++ break; ++ default: ++ /* Only deal with the winner. */ ++ break; ++ } ++ ++ return will_pass; ++} ++ ++/*! ++ * \internal ++ * \brief Handle outboundbroadcast incoming messages for the master_call's state. ++ * ++ * \param ctrl D channel controller. ++ * \param mh Q.931 message type header. ++ * \param subcall Q.931 call leg. ++ * \param allow_event Where to set the allow event to upper layer flag. ++ * \param allow_posthandle Where to set the allow post handle event flag. ++ * ++ * \details ++ * This is where we interact the subcalls state with the master_call's state. ++ * ++ * \note This function must parallel q931_master_pass_event(). ++ * ++ * \return Nothing ++ */ ++static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *subcall, int *allow_event, int *allow_posthandle) ++{ ++ struct q931_call *master = subcall->master_call; ++ struct q931_call *winner = q931_get_subcall_winner(master); ++ enum Q931_RANKED_CALL_STATE master_rank; ++ enum Q931_RANKED_CALL_STATE subcall_rank; ++ enum Q931_CALL_STATE newstate; ++ ++ /* For broadcast calls, we default to not allowing events to keep events received to a minimum ++ * and to allow post processing, since that is where hangup and subcall state handling and other processing is done */ ++ *allow_event = 0; ++ *allow_posthandle = 1; ++ ++ master_rank = q931_rank_state(master->ourcallstate); ++ ++ switch (mh->msg) { ++ case Q931_SETUP_ACKNOWLEDGE: ++#if 0 /* Overlap dialing in PTMP NT mode not supported at the present time. */ ++ if (master_rank < Q931_RANKED_CALL_STATE_OVERLAP) { ++ *allow_event = 1; ++ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_OVERLAP_SENDING); ++ } ++#endif /* Overlap dialing in PTMP NT mode not supported at the present time. */ ++ break; ++ case Q931_CALL_PROCEEDING: ++ if (master_rank < Q931_RANKED_CALL_STATE_PROCEEDING) { ++ *allow_event = 1; ++ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING); ++ } ++ break; ++ case Q931_PROGRESS: ++ /* ++ * We will just ignore this message since there could be multiple devices ++ * competing for this call. Who has access to the B channel at this time ++ * to give in-band signals anyway? ++ */ ++ break; ++ case Q931_ALERTING: ++ if (master_rank < Q931_RANKED_CALL_STATE_ALERTING) { ++ *allow_event = 1; ++ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_CALL_DELIVERED); ++ } ++ break; ++ case Q931_CONNECT: ++ if (master_rank < Q931_RANKED_CALL_STATE_CONNECT) { ++ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_ACTIVE); ++ q931_set_subcall_winner(subcall); ++ *allow_event = 1; ++ } else { ++ /* Call clearing of non selected calls occurs in ++ * q931_set_subcall_winner() - All we need to do is make sure ++ * that this connect is not acknowledged */ ++ *allow_posthandle = 0; ++ } ++ break; ++ case Q931_DISCONNECT: ++ newstate = Q931_CALL_STATE_DISCONNECT_INDICATION; ++ goto process_hangup; ++ case Q931_RELEASE: ++ case Q931_RELEASE_COMPLETE: ++ newstate = Q931_CALL_STATE_NULL; ++process_hangup: ++ if (!winner) { ++ /* If there's not a winner, we just take the cause and pass it up to the ++ * master_call */ ++ master->cause = subcall->cause; ++ } else { ++ /* There *is* a winner */ ++ if (subcall == winner) { ++ /* .. and we're it: */ ++ *allow_event = 1; ++ UPDATE_OURCALLSTATE(ctrl, master, newstate); ++ } ++ } ++ break; ++ case Q931_FACILITY: ++ case Q931_NOTIFY: ++ if (winner) { ++ if (subcall == winner) { ++ /* Only deal with the winner. */ ++ *allow_event = 1; ++ } ++ } else { ++ /* The overlap rank does not count here. */ ++ if (master_rank == Q931_RANKED_CALL_STATE_OVERLAP) { ++ master_rank = Q931_RANKED_CALL_STATE_PRESENT; ++ } ++ subcall_rank = q931_rank_state(subcall->ourcallstate); ++ if (subcall_rank == Q931_RANKED_CALL_STATE_OVERLAP) { ++ subcall_rank = Q931_RANKED_CALL_STATE_PRESENT; ++ } ++ if (master_rank == subcall_rank) { ++ /* ++ * No winner yet but the subcall is as advanced as the master. ++ * Allow the supplementary service event to pass. ++ */ ++ *allow_event = 1; ++ } ++ } ++ break; ++ default: ++ if (winner && subcall == winner) { ++ /* Only deal with the winner. */ ++ *allow_event = 1; ++ } ++ break; ++ } ++} ++ ++/*! ++ * \internal ++ * \brief Fill in the FACILITY event fields. ++ * ++ * \param ctrl D channel controller. ++ * \param call Q.931 call leg. ++ * ++ * \return Nothing ++ */ ++static void q931_fill_facility_event(struct pri *ctrl, struct q931_call *call) ++{ ++ ctrl->ev.e = PRI_EVENT_FACILITY; ++ ctrl->ev.facility.subcmds = &ctrl->subcmds; ++ ctrl->ev.facility.channel = q931_encode_channel(call); ++ ctrl->ev.facility.cref = call->cr; ++ ctrl->ev.facility.call = call->master_call; ++ ctrl->ev.facility.subcall = call; ++ ++ /* Need to do this for backward compatibility with struct pri_event_facname */ ++ libpri_copy_string(ctrl->ev.facility.callingname, call->remote_id.name.str, ++ sizeof(ctrl->ev.facility.callingname)); ++ libpri_copy_string(ctrl->ev.facility.callingnum, call->remote_id.number.str, ++ sizeof(ctrl->ev.facility.callingnum)); ++ ctrl->ev.facility.callingpres = q931_party_id_presentation(&call->remote_id); ++ ctrl->ev.facility.callingplan = call->remote_id.number.plan; ++} ++ ++/*! ++ * \internal ++ * \brief APDU wait for response message timeout. ++ * ++ * \param data Callback data pointer. ++ * ++ * \return Nothing ++ */ ++static void q931_apdu_timeout(void *data) ++{ ++ struct apdu_event *apdu; ++ struct pri *ctrl; ++ struct q931_call *call; ++ ++ apdu = data; ++ call = apdu->call; ++ ctrl = call->pri; ++ ++ q931_clr_subcommands(ctrl); ++ apdu->response.callback(APDU_CALLBACK_REASON_TIMEOUT, ctrl, call, apdu, NULL); ++ if (ctrl->subcmds.counter_subcmd) { ++ q931_fill_facility_event(ctrl, call); ++ ctrl->schedev = 1; ++ } ++ ++ pri_call_apdu_delete(call, apdu); ++} ++ ++/*! ++ * \internal ++ * \brief Find the active call given the held call. ++ * ++ * \param ctrl D channel controller. ++ * \param held_call Held call to help locate a compatible active call. ++ * ++ * \retval master-active-call on success. ++ * \retval NULL on error. ++ */ ++static struct q931_call *q931_find_held_active_call(struct pri *ctrl, struct q931_call *held_call) ++{ ++ struct pri *master; ++ struct q931_call *cur; ++ struct q931_call *winner; ++ struct q931_call *match; ++ ++ match = NULL; ++ master = PRI_MASTER(ctrl); ++ for (cur = *master->callpool; cur; cur = cur->next) { ++ if (cur->hold_state == Q931_HOLD_STATE_IDLE) { ++ /* Found an active call. */ ++ winner = q931_find_winning_call(cur); ++ if (!winner || (BRI_NT_PTMP(ctrl) && winner->pri != held_call->pri)) { ++ /* There is no winner or the active call does not go to the same TEI. */ ++ continue; ++ } ++ switch (winner->ourcallstate) { ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ case Q931_CALL_STATE_CONNECT_REQUEST: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_ACTIVE: ++ break; ++ default: ++ /* Active call not in a good state to transfer. */ ++ continue; ++ } ++ if (q931_party_number_cmp(&winner->remote_id.number, ++ &held_call->remote_id.number)) { ++ /* The remote party number does not match. This is a weak match. */ ++ match = cur; ++ continue; ++ } ++ /* Found an exact match. */ ++ match = cur; ++ break; ++ } ++ } ++ ++ return match; ++} ++ ++/*! ++ * \internal ++ * \brief Find the held call given the active call. ++ * ++ * \param ctrl D channel controller. ++ * \param active_call Active call to help locate a compatible held call. ++ * ++ * \retval master-held-call on success. ++ * \retval NULL on error. ++ */ ++static struct q931_call *q931_find_held_call(struct pri *ctrl, struct q931_call *active_call) ++{ ++ struct pri *master; ++ struct q931_call *cur; ++ struct q931_call *winner; ++ struct q931_call *match; ++ ++ match = NULL; ++ master = PRI_MASTER(ctrl); ++ for (cur = *master->callpool; cur; cur = cur->next) { ++ if (cur->hold_state == Q931_HOLD_STATE_CALL_HELD) { ++ /* Found a held call. */ ++ winner = q931_find_winning_call(cur); ++ if (!winner || (BRI_NT_PTMP(ctrl) && winner->pri != active_call->pri)) { ++ /* There is no winner or the held call does not go to the same TEI. */ ++ continue; ++ } ++ switch (winner->ourcallstate) { ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ case Q931_CALL_STATE_CONNECT_REQUEST: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_ACTIVE: ++ break; ++ default: ++ /* Held call not in a good state to transfer. */ ++ continue; ++ } ++ if (q931_party_number_cmp(&winner->remote_id.number, ++ &active_call->remote_id.number)) { ++ /* The remote party number does not match. This is a weak match. */ ++ match = cur; ++ continue; ++ } ++ /* Found an exact match. */ ++ match = cur; ++ break; ++ } ++ } ++ ++ return match; ++} ++ ++/*! ++ * \internal ++ * \brief Process the decoded information in the Q.931 message. ++ * ++ * \param ctrl D channel controller. ++ * \param mh Q.931 message header. ++ * \param c Q.931 call leg. ++ * \param missingmand Number of missing mandatory ie's. ++ * ++ * \retval 0 if no error or event. ++ * \retval Q931_RES_HAVEEVENT if have an event. ++ * \retval -1 on error. ++ */ ++static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand) ++{ ++ int res; ++ struct apdu_event *cur = NULL; ++ struct pri_subcommand *subcmd; ++ struct q931_call *master_call; ++ + switch(mh->msg) { + case Q931_RESTART: + if (missingmand) { +- q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); +- q931_destroycall(pri, c->cr); ++ q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING); ++ pri_destroycall(ctrl, c); + break; + } +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_RESTART); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RESTART); + c->peercallstate = Q931_CALL_STATE_RESTART_REQUEST; + /* Send back the Restart Acknowledge */ +- restart_ack(pri, c); ++ restart_ack(ctrl, c); + /* Notify user of restart event */ +- pri->ev.e = PRI_EVENT_RESTART; +- pri->ev.restart.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ ctrl->ev.e = PRI_EVENT_RESTART; ++ ctrl->ev.restart.channel = q931_encode_channel(c); + return Q931_RES_HAVEEVENT; + case Q931_SETUP: + if (missingmand) { +- q931_release_complete(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); ++ q931_release_complete(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING); + break; + } + /* Must be new call */ +@@ -3548,185 +6491,279 @@ + if (c->progressmask & PRI_PROG_CALLER_NOT_ISDN) + c->nonisdn = 1; + c->newcall = 0; +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_PRESENT); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_PRESENT); + c->peercallstate = Q931_CALL_STATE_CALL_INITIATED; + /* it's not yet a call since higher level can respond with RELEASE or RELEASE_COMPLETE */ + c->alive = 0; + if (c->transmoderate != TRANS_MODE_64_CIRCUIT) { +- q931_release_complete(pri, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL); ++ q931_release_complete(ctrl, c, PRI_CAUSE_BEARERCAPABILITY_NOTIMPL); + break; + } +- pri->ev.e = PRI_EVENT_RING; +- pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.ring.callingpres = c->callerpres; +- pri->ev.ring.callingplan = c->callerplan; +- pri->ev.ring.callingplanani = c->callerplanani; +- pri->ev.ring.callingplanrdnis = c->redirectingplan; +- pri->ev.ring.callingplanorigcalled = c->origcalledplan; +- pri->ev.ring.ani2 = c->ani2; +- libpri_copy_string(pri->ev.ring.callingani, c->callerani, sizeof(pri->ev.ring.callingani)); +- libpri_copy_string(pri->ev.ring.callingnum, c->callernum, sizeof(pri->ev.ring.callingnum)); +- libpri_copy_string(pri->ev.ring.callingname, c->callername, sizeof(pri->ev.ring.callingname)); +- pri->ev.ring.calledplan = c->calledplan; +- libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr)); +- libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum)); +- libpri_copy_string(pri->ev.ring.origcalledname, c->origcalledname, sizeof(pri->ev.ring.origcalledname)); +- libpri_copy_string(pri->ev.ring.origcallednum, c->origcallednum, sizeof(pri->ev.ring.origcallednum)); +- libpri_copy_string(pri->ev.ring.redirectingnum, c->redirectingnum, sizeof(pri->ev.ring.redirectingnum)); +- libpri_copy_string(pri->ev.ring.redirectingname, c->redirectingname, sizeof(pri->ev.ring.redirectingname)); +- libpri_copy_string(pri->ev.ring.useruserinfo, c->useruserinfo, sizeof(pri->ev.ring.useruserinfo)); ++ ++ if (c->redirecting.from.number.valid && !c->redirecting.count) { ++ /* ++ * This is most likely because the redirecting number came in ++ * with the redirecting ie only and not a DivertingLegInformation2. ++ */ ++ c->redirecting.count = 1; ++ } ++ if (c->redirecting.state == Q931_REDIRECTING_STATE_PENDING_TX_DIV_LEG_3) { ++ /* ++ * Valid for Q.SIG and ETSI PRI/BRI-PTP modes: ++ * Setup the redirecting.to informtion so we can identify ++ * if the user wants to manually supply the COLR for this ++ * redirected to number if further redirects could happen. ++ * ++ * All the user needs to do is set the REDIRECTING(to-pres) ++ * to the COLR and REDIRECTING(to-num) = complete-dialed-number ++ * (i.e. CALLERID(dnid)) to be safe after determining that the ++ * incoming call was redirected by checking if the ++ * REDIRECTING(count) is nonzero. ++ */ ++ c->redirecting.to.number = c->called.number; ++ c->redirecting.to.number.presentation = ++ PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED; ++ } ++ ++ ctrl->ev.e = PRI_EVENT_RING; ++ ctrl->ev.ring.subcmds = &ctrl->subcmds; ++ ctrl->ev.ring.channel = q931_encode_channel(c); ++ ++ /* Calling party information */ ++ ctrl->ev.ring.callingpres = q931_party_id_presentation(&c->remote_id); ++ ctrl->ev.ring.callingplan = c->remote_id.number.plan; ++ if (c->remote_id.number.valid ++ && (c->remote_id.number.presentation == PRES_ALLOWED_NETWORK_NUMBER ++ || c->remote_id.number.presentation == PRES_PROHIB_NETWORK_NUMBER)) { ++ ctrl->ev.ring.callingplanani = c->remote_id.number.plan; ++ libpri_copy_string(ctrl->ev.ring.callingani, c->remote_id.number.str, sizeof(ctrl->ev.ring.callingani)); ++ } else { ++ ctrl->ev.ring.callingplanani = -1; ++ ctrl->ev.ring.callingani[0] = '\0'; ++ } ++ libpri_copy_string(ctrl->ev.ring.callingnum, c->remote_id.number.str, sizeof(ctrl->ev.ring.callingnum)); ++ libpri_copy_string(ctrl->ev.ring.callingname, c->remote_id.name.str, sizeof(ctrl->ev.ring.callingname)); ++ q931_party_id_copy_to_pri(&ctrl->ev.ring.calling, &c->remote_id); ++ /* for backwards compatibility, still need ctrl->ev.ring.callingsubaddr */ ++ if (!c->remote_id.subaddress.type) { /* NSAP: Type = 0 */ ++ libpri_copy_string(ctrl->ev.ring.callingsubaddr, (char *) c->remote_id.subaddress.data, sizeof(ctrl->ev.ring.callingsubaddr)); ++ } else { ++ ctrl->ev.ring.callingsubaddr[0] = '\0'; ++ } ++ ++ ctrl->ev.ring.ani2 = c->ani2; ++ ++ /* Called party information */ ++ ctrl->ev.ring.calledplan = c->called.number.plan; ++ libpri_copy_string(ctrl->ev.ring.callednum, c->called.number.str, sizeof(ctrl->ev.ring.callednum)); ++ q931_party_subaddress_copy_to_pri(&ctrl->ev.ring.called_subaddress, &c->called.subaddress); ++ ++ /* Original called party information (For backward compatibility) */ ++ libpri_copy_string(ctrl->ev.ring.origcalledname, c->redirecting.orig_called.name.str, sizeof(ctrl->ev.ring.origcalledname)); ++ libpri_copy_string(ctrl->ev.ring.origcallednum, c->redirecting.orig_called.number.str, sizeof(ctrl->ev.ring.origcallednum)); ++ ctrl->ev.ring.callingplanorigcalled = c->redirecting.orig_called.number.plan; ++ if (c->redirecting.orig_called.number.valid ++ || c->redirecting.orig_called.name.valid) { ++ ctrl->ev.ring.origredirectingreason = c->redirecting.orig_reason; ++ } else { ++ ctrl->ev.ring.origredirectingreason = -1; ++ } ++ ++ /* Redirecting from party information (For backward compatibility) */ ++ ctrl->ev.ring.callingplanrdnis = c->redirecting.from.number.plan; ++ libpri_copy_string(ctrl->ev.ring.redirectingnum, c->redirecting.from.number.str, sizeof(ctrl->ev.ring.redirectingnum)); ++ libpri_copy_string(ctrl->ev.ring.redirectingname, c->redirecting.from.name.str, sizeof(ctrl->ev.ring.redirectingname)); ++ ++ ctrl->ev.ring.redirectingreason = c->redirecting.reason; ++ ++ libpri_copy_string(ctrl->ev.ring.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.ring.useruserinfo)); + c->useruserinfo[0] = '\0'; +- pri->ev.ring.redirectingreason = c->redirectingreason; +- pri->ev.ring.origredirectingreason = c->origredirectingreason; +- pri->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE); +- pri->ev.ring.cref = c->cr; +- pri->ev.ring.call = c; +- pri->ev.ring.layer1 = c->userl1; +- pri->ev.ring.complete = c->complete; +- pri->ev.ring.ctype = c->transcapability; +- pri->ev.ring.redirectingreason = c->redirectingreason; +- pri->ev.ring.progress = c->progress; +- pri->ev.ring.progressmask = c->progressmask; ++ ++ libpri_copy_string(ctrl->ev.ring.keypad_digits, c->keypad_digits, ++ sizeof(ctrl->ev.ring.keypad_digits)); ++ ++ ctrl->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE); ++ ctrl->ev.ring.cref = c->cr; ++ ctrl->ev.ring.call = c->master_call; ++ ctrl->ev.ring.layer1 = c->userl1; ++ ctrl->ev.ring.complete = c->complete; ++ ctrl->ev.ring.ctype = c->transcapability; ++ ctrl->ev.ring.progress = c->progress; ++ ctrl->ev.ring.progressmask = c->progressmask; ++ ctrl->ev.ring.reversecharge = c->reversecharge; ++ ++ if (c->redirecting.count) { ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (subcmd) { ++ /* Setup redirecting subcommand */ ++ subcmd->cmd = PRI_SUBCMD_REDIRECTING; ++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting, ++ &c->redirecting); ++ } ++ } ++ + return Q931_RES_HAVEEVENT; + case Q931_ALERTING: ++ stop_t303(c); + if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_CALL_DELIVERED); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_DELIVERED); + c->peercallstate = Q931_CALL_STATE_CALL_RECEIVED; +- pri->ev.e = PRI_EVENT_RINGING; +- pri->ev.ringing.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.ringing.cref = c->cr; +- pri->ev.ringing.call = c; +- pri->ev.ringing.progress = c->progress; +- pri->ev.ringing.progressmask = c->progressmask; +- libpri_copy_string(pri->ev.ringing.useruserinfo, c->useruserinfo, sizeof(pri->ev.ringing.useruserinfo)); ++ ctrl->ev.e = PRI_EVENT_RINGING; ++ ctrl->ev.ringing.subcmds = &ctrl->subcmds; ++ ctrl->ev.ringing.channel = q931_encode_channel(c); ++ ctrl->ev.ringing.cref = c->cr; ++ ctrl->ev.ringing.call = c->master_call; ++ ctrl->ev.ringing.progress = c->progress; ++ ctrl->ev.ringing.progressmask = c->progressmask; ++ ++ libpri_copy_string(ctrl->ev.ringing.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.ringing.useruserinfo)); + c->useruserinfo[0] = '\0'; + +- cur = c->apdus; +- while (cur) { ++ for (cur = c->apdus; cur; cur = cur->next) { + if (!cur->sent && cur->message == Q931_FACILITY) { +- q931_facility(pri, c); ++ q931_facility(ctrl, c); + break; + } +- cur = cur->next; + } + + return Q931_RES_HAVEEVENT; + case Q931_CONNECT: ++ stop_t303(c); + if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + if (c->ourcallstate == Q931_CALL_STATE_ACTIVE) { +- q931_status(pri, c, PRI_CAUSE_WRONG_MESSAGE); ++ q931_status(ctrl, c, PRI_CAUSE_WRONG_MESSAGE); + break; + } +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE); + c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST; +- pri->ev.e = PRI_EVENT_ANSWER; +- pri->ev.answer.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.answer.cref = c->cr; +- pri->ev.answer.call = c; +- pri->ev.answer.progress = c->progress; +- pri->ev.answer.progressmask = c->progressmask; +- libpri_copy_string(pri->ev.answer.useruserinfo, c->useruserinfo, sizeof(pri->ev.answer.useruserinfo)); ++ ++ ctrl->ev.e = PRI_EVENT_ANSWER; ++ ctrl->ev.answer.subcmds = &ctrl->subcmds; ++ ctrl->ev.answer.channel = q931_encode_channel(c); ++ ctrl->ev.answer.cref = c->cr; ++ ctrl->ev.answer.call = c->master_call; ++ ctrl->ev.answer.progress = c->progress; ++ ctrl->ev.answer.progressmask = c->progressmask; ++ libpri_copy_string(ctrl->ev.answer.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.answer.useruserinfo)); + c->useruserinfo[0] = '\0'; +- q931_connect_acknowledge(pri, c); +- if (c->justsignalling) { /* Make sure WE release when we initiatie a signalling only connection */ +- q931_release(pri, c, PRI_CAUSE_NORMAL_CLEARING); ++ ++ q931_connect_acknowledge(ctrl, c); ++ ++ if (c->cis_auto_disconnect && c->cis_call) { ++ /* Make sure WE release when we initiate a signalling only connection */ ++ q931_hangup(ctrl, c, PRI_CAUSE_NORMAL_CLEARING); + break; +- } else ++ } else { ++ c->incoming_ct_state = INCOMING_CT_STATE_IDLE; ++ ++ /* Setup connected line subcommand */ ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (subcmd) { ++ subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE; ++ q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &c->remote_id); ++ } ++ + return Q931_RES_HAVEEVENT; ++ } + case Q931_FACILITY: + if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } +- pri->ev.e = PRI_EVENT_FACNAME; +- libpri_copy_string(pri->ev.facname.callingname, c->callername, sizeof(pri->ev.facname.callingname)); +- libpri_copy_string(pri->ev.facname.callingnum, c->callernum, sizeof(pri->ev.facname.callingnum)); +- pri->ev.facname.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.facname.callingpres = c->callerpres; +- pri->ev.facname.callingplan = c->callerplan; +- pri->ev.facname.cref = c->cr; +- pri->ev.facname.call = c; +-#if 0 +- pri_message(pri, "Sending facility event (%s/%s)\n", pri->ev.facname.callingname, pri->ev.facname.callingnum); +-#endif +- return Q931_RES_HAVEEVENT; ++ switch (c->incoming_ct_state) { ++ case INCOMING_CT_STATE_POST_CONNECTED_LINE: ++ c->incoming_ct_state = INCOMING_CT_STATE_IDLE; ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (subcmd) { ++ subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE; ++ q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, &c->remote_id); ++ } ++ break; ++ default: ++ break; ++ } ++ if (ctrl->subcmds.counter_subcmd) { ++ q931_fill_facility_event(ctrl, c); ++ return Q931_RES_HAVEEVENT; ++ } ++ break; + case Q931_PROGRESS: + if (missingmand) { +- q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); +- q931_destroycall(pri, c->cr); ++ q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING); ++ pri_destroycall(ctrl, c); + break; + } +- pri->ev.e = PRI_EVENT_PROGRESS; +- pri->ev.proceeding.cause = c->cause; ++ ctrl->ev.e = PRI_EVENT_PROGRESS; ++ ctrl->ev.proceeding.cause = c->cause; + /* Fall through */ + case Q931_CALL_PROCEEDING: ++ stop_t303(c); ++ ctrl->ev.proceeding.subcmds = &ctrl->subcmds; + if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + if ((c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED) && + (c->ourcallstate != Q931_CALL_STATE_OVERLAP_SENDING) && + (c->ourcallstate != Q931_CALL_STATE_CALL_DELIVERED) && + (c->ourcallstate != Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING)) { +- q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE); ++ q931_status(ctrl,c,PRI_CAUSE_WRONG_MESSAGE); + break; + } +- pri->ev.proceeding.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ ctrl->ev.proceeding.channel = q931_encode_channel(c); + if (mh->msg == Q931_CALL_PROCEEDING) { +- pri->ev.e = PRI_EVENT_PROCEEDING; +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING); ++ ctrl->ev.e = PRI_EVENT_PROCEEDING; ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING); + c->peercallstate = Q931_CALL_STATE_INCOMING_CALL_PROCEEDING; + } +- pri->ev.proceeding.progress = c->progress; +- pri->ev.proceeding.progressmask = c->progressmask; +- pri->ev.proceeding.cref = c->cr; +- pri->ev.proceeding.call = c; ++ ctrl->ev.proceeding.progress = c->progress; ++ ctrl->ev.proceeding.progressmask = c->progressmask; ++ ctrl->ev.proceeding.cref = c->cr; ++ ctrl->ev.proceeding.call = c->master_call; + +- cur = c->apdus; +- while (cur) { ++ for (cur = c->apdus; cur; cur = cur->next) { + if (!cur->sent && cur->message == Q931_FACILITY) { +- q931_facility(pri, c); ++ q931_facility(ctrl, c); + break; + } +- cur = cur->next; + } + return Q931_RES_HAVEEVENT; + case Q931_CONNECT_ACKNOWLEDGE: + if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + if (!(c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) && + !(c->ourcallstate == Q931_CALL_STATE_ACTIVE && +- (pri->localtype == PRI_NETWORK || pri->switchtype == PRI_SWITCH_QSIG))) { +- q931_status(pri,c,PRI_CAUSE_WRONG_MESSAGE); ++ (ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG))) { ++ q931_status(ctrl,c,PRI_CAUSE_WRONG_MESSAGE); + break; + } +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_ACTIVE); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE); + c->peercallstate = Q931_CALL_STATE_ACTIVE; + break; + case Q931_STATUS: + if (missingmand) { +- q931_status(pri, c, PRI_CAUSE_MANDATORY_IE_MISSING); +- q931_destroycall(pri, c->cr); ++ q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING); ++ pri_destroycall(ctrl, c); + break; + } + if (c->newcall) { + if (c->cr & 0x7fff) +- q931_release_complete(pri,c,PRI_CAUSE_WRONG_CALL_STATE); ++ q931_release_complete(ctrl,c,PRI_CAUSE_WRONG_CALL_STATE); + break; + } + /* Do nothing */ + /* Also when the STATUS asks for the call of an unexisting reference send RELEASE_COMPL */ +- if ((pri->debug & PRI_DEBUG_Q931_ANOMALY) && ++ if ((ctrl->debug & PRI_DEBUG_Q931_ANOMALY) && + (c->cause != PRI_CAUSE_INTERWORKING)) +- pri_error(pri, "Received unsolicited status: %s\n", pri_cause2str(c->cause)); ++ pri_error(ctrl, "Received unsolicited status: %s\n", pri_cause2str(c->cause)); + /* Workaround for S-12 ver 7.3 - it responds for invalid/non-implemented IEs at SETUP with null call state */ + #if 0 + if (!c->sugcallstate && (c->ourcallstate != Q931_CALL_STATE_CALL_INITIATED)) { +@@ -3737,25 +6774,28 @@ + + if (!c->sugcallstate) { + #endif +- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.hangup.cause = c->cause; +- pri->ev.hangup.cref = c->cr; +- pri->ev.hangup.call = c; +- pri->ev.hangup.aoc_units = c->aoc_units; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); ++ ctrl->ev.hangup.subcmds = &ctrl->subcmds; ++ ctrl->ev.hangup.channel = q931_encode_channel(c); ++ ctrl->ev.hangup.cause = c->cause; ++ ctrl->ev.hangup.cref = c->cr; ++ ctrl->ev.hangup.call = c->master_call; ++ ctrl->ev.hangup.aoc_units = c->aoc_units; ++ ctrl->ev.hangup.call_held = NULL; ++ ctrl->ev.hangup.call_active = NULL; ++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); + /* Free resources */ +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); + c->peercallstate = Q931_CALL_STATE_NULL; + if (c->alive) { +- pri->ev.e = PRI_EVENT_HANGUP; ++ ctrl->ev.e = PRI_EVENT_HANGUP; + res = Q931_RES_HAVEEVENT; + c->alive = 0; + } else if (c->sendhangupack) { + res = Q931_RES_HAVEEVENT; +- pri->ev.e = PRI_EVENT_HANGUP_ACK; +- q931_hangup(pri, c, c->cause); ++ ctrl->ev.e = PRI_EVENT_HANGUP_ACK; ++ pri_hangup(ctrl, c, c->cause); + } else { +- q931_hangup(pri, c, c->cause); ++ pri_hangup(ctrl, c, c->cause); + res = 0; + } + if (res) +@@ -3763,32 +6803,38 @@ + } + break; + case Q931_RELEASE_COMPLETE: +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); ++ c->hangupinitiated = 1; ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); + c->peercallstate = Q931_CALL_STATE_NULL; +- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.hangup.cause = c->cause; +- pri->ev.hangup.cref = c->cr; +- pri->ev.hangup.call = c; +- pri->ev.hangup.aoc_units = c->aoc_units; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); ++ ctrl->ev.hangup.subcmds = &ctrl->subcmds; ++ ctrl->ev.hangup.channel = q931_encode_channel(c); ++ ctrl->ev.hangup.cause = c->cause; ++ ctrl->ev.hangup.cref = c->cr; ++ ctrl->ev.hangup.call = c->master_call; ++ ctrl->ev.hangup.aoc_units = c->aoc_units; ++ ctrl->ev.hangup.call_held = NULL; ++ ctrl->ev.hangup.call_active = NULL; ++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); + c->useruserinfo[0] = '\0'; + /* Free resources */ + if (c->alive) { +- pri->ev.e = PRI_EVENT_HANGUP; ++ ctrl->ev.e = PRI_EVENT_HANGUP; + res = Q931_RES_HAVEEVENT; + c->alive = 0; + } else if (c->sendhangupack) { + res = Q931_RES_HAVEEVENT; +- pri->ev.e = PRI_EVENT_HANGUP_ACK; +- pri_hangup(pri, c, c->cause); ++ ctrl->ev.e = PRI_EVENT_HANGUP_ACK; ++ pri_hangup(ctrl, c, c->cause); + } else + res = 0; ++ + if (res) + return res; + else +- q931_hangup(pri,c,c->cause); ++ pri_hangup(ctrl,c,c->cause); + break; + case Q931_RELEASE: ++ c->hangupinitiated = 1; + if (missingmand) { + /* Force cause to be mandatory IE missing */ + c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; +@@ -3798,59 +6844,113 @@ + else { + c->peercallstate = Q931_CALL_STATE_RELEASE_REQUEST; + } +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); +- pri->ev.e = PRI_EVENT_HANGUP; +- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.hangup.cause = c->cause; +- pri->ev.hangup.cref = c->cr; +- pri->ev.hangup.call = c; +- pri->ev.hangup.aoc_units = c->aoc_units; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); ++ ctrl->ev.e = PRI_EVENT_HANGUP; ++ ctrl->ev.hangup.subcmds = &ctrl->subcmds; ++ ctrl->ev.hangup.channel = q931_encode_channel(c); ++ ctrl->ev.hangup.cause = c->cause; ++ ctrl->ev.hangup.cref = c->cr; ++ ctrl->ev.hangup.call = c->master_call; ++ ctrl->ev.hangup.aoc_units = c->aoc_units; ++ ctrl->ev.hangup.call_held = NULL; ++ ctrl->ev.hangup.call_active = NULL; ++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); + c->useruserinfo[0] = '\0'; + /* Don't send release complete if they send us release + while we sent it, assume a NULL state */ + if (c->newcall) +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); +- else ++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ else if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call))) ++ return pri_hangup(ctrl, c, -1); ++ else + return Q931_RES_HAVEEVENT; + break; + case Q931_DISCONNECT: ++ c->hangupinitiated = 1; + if (missingmand) { + /* Still let user call release */ + c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; + } + if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_DISCONNECT_INDICATION); ++ ++ /* ++ * Determine if there are any calls that can be proposed for ++ * a transfer of held call on disconnect. ++ */ ++ ctrl->ev.hangup.call_held = NULL; ++ ctrl->ev.hangup.call_active = NULL; ++ switch (c->ourcallstate) { ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ case Q931_CALL_STATE_CONNECT_REQUEST: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_ACTIVE: ++ if (c->master_call->hold_state == Q931_HOLD_STATE_CALL_HELD) { ++ /* Held call is being disconnected first. */ ++ ctrl->ev.hangup.call_held = c->master_call; ++ ctrl->ev.hangup.call_active = q931_find_held_active_call(ctrl, c); ++ } else { ++ /* Active call is being disconnected first. */ ++ if (q931_find_winning_call(c) == c) { ++ /* ++ * Only a normal call or the winning call of a broadcast SETUP ++ * can participate in a transfer of held call on disconnet. ++ */ ++ ctrl->ev.hangup.call_active = c->master_call; ++ ctrl->ev.hangup.call_held = q931_find_held_call(ctrl, c); ++ } ++ } ++ break; ++ default: ++ break; ++ } ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ if (ctrl->ev.hangup.call_held) { ++ pri_message(ctrl, "-- Found held call: %p cref:%d\n", ++ ctrl->ev.hangup.call_held, ctrl->ev.hangup.call_held->cr); ++ } ++ if (ctrl->ev.hangup.call_active) { ++ pri_message(ctrl, "-- Found active call: %p cref:%d\n", ++ ctrl->ev.hangup.call_active, ctrl->ev.hangup.call_active->cr); ++ } ++ if (ctrl->ev.hangup.call_held && ctrl->ev.hangup.call_active) { ++ pri_message(ctrl, "-- Transfer held call on disconnect possible.\n"); ++ } ++ } ++ ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_DISCONNECT_INDICATION); + c->peercallstate = Q931_CALL_STATE_DISCONNECT_REQUEST; + c->sendhangupack = 1; + + /* wait for a RELEASE so that sufficient time has passed + for the inband audio to be heard */ +- if (pri->acceptinbanddisconnect && (c->progressmask & PRI_PROG_INBAND_AVAILABLE)) ++ if (ctrl->acceptinbanddisconnect && (c->progressmask & PRI_PROG_INBAND_AVAILABLE)) + break; + + /* Return such an event */ +- pri->ev.e = PRI_EVENT_HANGUP_REQ; +- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.hangup.cause = c->cause; +- pri->ev.hangup.cref = c->cr; +- pri->ev.hangup.call = c; +- pri->ev.hangup.aoc_units = c->aoc_units; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); ++ ctrl->ev.e = PRI_EVENT_HANGUP_REQ; ++ ctrl->ev.hangup.subcmds = &ctrl->subcmds; ++ ctrl->ev.hangup.channel = q931_encode_channel(c); ++ ctrl->ev.hangup.cause = c->cause; ++ ctrl->ev.hangup.cref = c->cr; ++ ctrl->ev.hangup.call = c->master_call; ++ ctrl->ev.hangup.aoc_units = c->aoc_units; ++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); + c->useruserinfo[0] = '\0'; + if (c->alive) + return Q931_RES_HAVEEVENT; + else +- q931_hangup(pri,c,c->cause); ++ pri_hangup(ctrl,c,c->cause); + break; + case Q931_RESTART_ACKNOWLEDGE: +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); + c->peercallstate = Q931_CALL_STATE_NULL; +- pri->ev.e = PRI_EVENT_RESTART_ACK; +- pri->ev.restartack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); ++ ctrl->ev.e = PRI_EVENT_RESTART_ACK; ++ ctrl->ev.restartack.channel = q931_encode_channel(c); + return Q931_RES_HAVEEVENT; + case Q931_INFORMATION: + /* XXX We're handling only INFORMATION messages that contain +@@ -3858,80 +6958,376 @@ + + the "Complete" msg which is basically an EOF on further digits + XXX */ + if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } + if (c->ourcallstate != Q931_CALL_STATE_OVERLAP_RECEIVING) { +- pri->ev.e = PRI_EVENT_KEYPAD_DIGIT; +- pri->ev.digit.call = c; +- pri->ev.digit.channel = c->channelno | (c->ds1no << 8); +- libpri_copy_string(pri->ev.digit.digits, c->keypad_digits, sizeof(pri->ev.digit.digits)); +- /* Make sure we clear it out before we return */ +- c->keypad_digits[0] = '\0'; ++ ctrl->ev.e = PRI_EVENT_KEYPAD_DIGIT; ++ ctrl->ev.digit.subcmds = &ctrl->subcmds; ++ ctrl->ev.digit.call = c->master_call; ++ ctrl->ev.digit.channel = q931_encode_channel(c); ++ libpri_copy_string(ctrl->ev.digit.digits, c->keypad_digits, sizeof(ctrl->ev.digit.digits)); + return Q931_RES_HAVEEVENT; + } +- pri->ev.e = PRI_EVENT_INFO_RECEIVED; +- pri->ev.ring.call = c; +- pri->ev.ring.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- libpri_copy_string(pri->ev.ring.callednum, c->callednum, sizeof(pri->ev.ring.callednum)); +- libpri_copy_string(pri->ev.ring.callingsubaddr, c->callingsubaddr, sizeof(pri->ev.ring.callingsubaddr)); +- pri->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */ ++ ctrl->ev.e = PRI_EVENT_INFO_RECEIVED; ++ ctrl->ev.ring.subcmds = &ctrl->subcmds; ++ ctrl->ev.ring.call = c->master_call; ++ ctrl->ev.ring.channel = q931_encode_channel(c); ++ libpri_copy_string(ctrl->ev.ring.callednum, c->overlap_digits, sizeof(ctrl->ev.ring.callednum)); ++ ++ q931_party_id_copy_to_pri(&ctrl->ev.ring.calling, &c->remote_id); ++ /* for backwards compatibility, still need ctrl->ev.ring.callingsubaddr */ ++ if (!c->remote_id.subaddress.type) { /* NSAP: Type = 0 */ ++ libpri_copy_string(ctrl->ev.ring.callingsubaddr, (char *) c->remote_id.subaddress.data, sizeof(ctrl->ev.ring.callingsubaddr)); ++ } else { ++ ctrl->ev.ring.callingsubaddr[0] = '\0'; ++ } ++ ++ ctrl->ev.ring.complete = c->complete; /* this covers IE 33 (Sending Complete) */ + return Q931_RES_HAVEEVENT; + case Q931_STATUS_ENQUIRY: + if (c->newcall) { +- q931_release_complete(pri, c, PRI_CAUSE_INVALID_CALL_REFERENCE); ++ q931_release_complete(ctrl, c, PRI_CAUSE_INVALID_CALL_REFERENCE); + } else +- q931_status(pri,c, 0); ++ q931_status(ctrl,c, 0); + break; + case Q931_SETUP_ACKNOWLEDGE: ++ stop_t303(c); + if (c->newcall) { +- q931_release_complete(pri,c,PRI_CAUSE_INVALID_CALL_REFERENCE); ++ q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE); + break; + } +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_OVERLAP_SENDING); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_OVERLAP_SENDING); + c->peercallstate = Q931_CALL_STATE_OVERLAP_RECEIVING; +- pri->ev.e = PRI_EVENT_SETUP_ACK; +- pri->ev.setup_ack.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.setup_ack.call = c; ++ ctrl->ev.e = PRI_EVENT_SETUP_ACK; ++ ctrl->ev.setup_ack.subcmds = &ctrl->subcmds; ++ ctrl->ev.setup_ack.channel = q931_encode_channel(c); ++ ctrl->ev.setup_ack.call = c->master_call; + +- cur = c->apdus; +- while (cur) { ++ for (cur = c->apdus; cur; cur = cur->next) { + if (!cur->sent && cur->message == Q931_FACILITY) { +- q931_facility(pri, c); ++ q931_facility(ctrl, c); + break; + } +- cur = cur->next; + } + + return Q931_RES_HAVEEVENT; + case Q931_NOTIFY: +- pri->ev.e = PRI_EVENT_NOTIFY; +- pri->ev.notify.channel = c->channelno; +- pri->ev.notify.info = c->notify; +- return Q931_RES_HAVEEVENT; +- case Q931_USER_INFORMATION: +- case Q931_SEGMENT: +- case Q931_CONGESTION_CONTROL: ++ res = 0; ++ switch (c->notify) { ++ case PRI_NOTIFY_CALL_DIVERTING: ++ if (c->redirection_number.valid) { ++ c->redirecting.to.number = c->redirection_number; ++ if (c->redirecting.count < PRI_MAX_REDIRECTS) { ++ ++c->redirecting.count; ++ } ++ switch (c->ourcallstate) { ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ /* Call is deflecting after we have seen an ALERTING message */ ++ c->redirecting.reason = PRI_REDIR_FORWARD_ON_NO_REPLY; ++ break; ++ default: ++ /* Call is deflecting for call forwarding unconditional or busy reason. */ ++ c->redirecting.reason = PRI_REDIR_UNKNOWN; ++ break; ++ } ++ ++ /* Setup redirecting subcommand */ ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (subcmd) { ++ subcmd->cmd = PRI_SUBCMD_REDIRECTING; ++ q931_party_redirecting_copy_to_pri(&subcmd->u.redirecting, ++ &c->redirecting); ++ } ++ } ++ ++ if (ctrl->subcmds.counter_subcmd) { ++ q931_fill_facility_event(ctrl, c); ++ res = Q931_RES_HAVEEVENT; ++ } ++ break; ++ case PRI_NOTIFY_TRANSFER_ALERTING: ++ case PRI_NOTIFY_TRANSFER_ACTIVE: ++ if (c->redirection_number.valid ++ && q931_party_number_cmp(&c->remote_id.number, &c->redirection_number)) { ++ /* The remote party information changed. */ ++ c->remote_id.number = c->redirection_number; ++ ++ /* Setup connected line subcommand */ ++ subcmd = q931_alloc_subcommand(ctrl); ++ if (subcmd) { ++ subcmd->cmd = PRI_SUBCMD_CONNECTED_LINE; ++ q931_party_id_copy_to_pri(&subcmd->u.connected_line.id, ++ &c->remote_id); ++ } ++ } ++ ++ if (ctrl->subcmds.counter_subcmd) { ++ q931_fill_facility_event(ctrl, c); ++ res = Q931_RES_HAVEEVENT; ++ } ++ break; ++ default: ++ ctrl->ev.e = PRI_EVENT_NOTIFY; ++ ctrl->ev.notify.subcmds = &ctrl->subcmds; ++ ctrl->ev.notify.channel = q931_encode_channel(c); ++ ctrl->ev.notify.info = c->notify; ++ ctrl->ev.notify.call = c->master_call; ++ res = Q931_RES_HAVEEVENT; ++ break; ++ } ++ return res; + case Q931_HOLD: ++ res = 0; ++ if (!PRI_MASTER(ctrl)->hold_support) { ++ /* ++ * Blocking any calls from getting on HOLD effectively ++ * disables HOLD/RETRIEVE. ++ */ ++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_FACILITY_NOT_IMPLEMENTED); ++ break; ++ } ++ switch (c->ourcallstate) { ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ case Q931_CALL_STATE_CONNECT_REQUEST: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ if (q931_is_ptmp(ctrl)) { ++ /* HOLD request only allowed in these states if point-to-point mode. */ ++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); ++ break; ++ } ++ /* Fall through */ ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_ACTIVE: ++ if (!q931_find_winning_call(c)) { ++ /* ++ * Only the winning call of a broadcast SETUP can do hold since the ++ * call must be answered first. ++ */ ++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); ++ break; ++ } ++ master_call = c->master_call; ++ switch (master_call->hold_state) { ++ case Q931_HOLD_STATE_HOLD_REQ: ++ if (ctrl->localtype == PRI_NETWORK) { ++ /* The network ignores HOLD request on a hold collision. */ ++ break; ++ } ++ /* Fall through */ ++ case Q931_HOLD_STATE_IDLE: ++ ctrl->ev.e = PRI_EVENT_HOLD; ++ ctrl->ev.hold.channel = q931_encode_channel(c); ++ ctrl->ev.hold.call = master_call; ++ ctrl->ev.hold.subcmds = &ctrl->subcmds; ++ res = Q931_RES_HAVEEVENT; ++ ++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_HOLD_IND); ++ ++ /* Stop any T-HOLD timer from possible hold collision. */ ++ pri_schedule_del(ctrl, master_call->hold_timer); ++ master_call->hold_timer = 0; ++ break; ++ default: ++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); ++ break; ++ } ++ break; ++ case Q931_CALL_STATE_DISCONNECT_INDICATION: ++ case Q931_CALL_STATE_RELEASE_REQUEST: ++ /* Ignore HOLD request in these states. */ ++ break; ++ default: ++ q931_send_hold_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); ++ break; ++ } ++ return res; + case Q931_HOLD_ACKNOWLEDGE: ++ res = 0; ++ master_call = c->master_call; ++ switch (master_call->hold_state) { ++ case Q931_HOLD_STATE_HOLD_REQ: ++ ctrl->ev.e = PRI_EVENT_HOLD_ACK; ++ ctrl->ev.hold_ack.channel = q931_encode_channel(c); ++ ctrl->ev.hold_ack.call = master_call; ++ ctrl->ev.hold_ack.subcmds = &ctrl->subcmds; ++ res = Q931_RES_HAVEEVENT; ++ ++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_CALL_HELD); ++ ++ /* Call is now on hold so forget the channel. */ ++ c->channelno = 0;/* No channel */ ++ c->ds1no = 0; ++ c->ds1explicit = 0; ++ c->chanflags = 0; ++ ++ /* Stop T-HOLD timer */ ++ pri_schedule_del(ctrl, master_call->hold_timer); ++ master_call->hold_timer = 0; ++ break; ++ default: ++ /* Ignore response. Response is late or spurrious. */ ++ break; ++ } ++ return res; + case Q931_HOLD_REJECT: ++ res = 0; ++ master_call = c->master_call; ++ switch (master_call->hold_state) { ++ case Q931_HOLD_STATE_HOLD_REQ: ++ if (missingmand) { ++ /* Still, let hold rejection continue. */ ++ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; ++ } ++ ctrl->ev.e = PRI_EVENT_HOLD_REJ; ++ ctrl->ev.hold_rej.channel = q931_encode_channel(c); ++ ctrl->ev.hold_rej.call = master_call; ++ ctrl->ev.hold_rej.cause = c->cause; ++ ctrl->ev.hold_rej.subcmds = &ctrl->subcmds; ++ res = Q931_RES_HAVEEVENT; ++ ++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_IDLE); ++ ++ /* Stop T-HOLD timer */ ++ pri_schedule_del(ctrl, master_call->hold_timer); ++ master_call->hold_timer = 0; ++ break; ++ default: ++ /* Ignore response. Response is late or spurrious. */ ++ break; ++ } ++ return res; + case Q931_RETRIEVE: ++ res = 0; ++ switch (c->ourcallstate) { ++ case Q931_CALL_STATE_CALL_RECEIVED: ++ case Q931_CALL_STATE_CONNECT_REQUEST: ++ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING: ++ if (q931_is_ptmp(ctrl)) { ++ /* RETRIEVE request only allowed in these states if point-to-point mode. */ ++ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); ++ break; ++ } ++ /* Fall through */ ++ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING: ++ case Q931_CALL_STATE_CALL_DELIVERED: ++ case Q931_CALL_STATE_ACTIVE: ++ if (!q931_find_winning_call(c)) { ++ /* ++ * Only the winning call of a broadcast SETUP can do hold since the ++ * call must be answered first. ++ */ ++ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); ++ break; ++ } ++ master_call = c->master_call; ++ switch (master_call->hold_state) { ++ case Q931_HOLD_STATE_RETRIEVE_REQ: ++ if (ctrl->localtype == PRI_NETWORK) { ++ /* The network ignores RETRIEVE request on a retrieve collision. */ ++ break; ++ } ++ /* Fall through */ ++ case Q931_HOLD_STATE_CALL_HELD: ++ ctrl->ev.e = PRI_EVENT_RETRIEVE; ++ ctrl->ev.retrieve.channel = q931_encode_channel(c); ++ ctrl->ev.retrieve.call = master_call; ++ ctrl->ev.retrieve.flexible = !(c->chanflags & FLAG_EXCLUSIVE); ++ ctrl->ev.retrieve.subcmds = &ctrl->subcmds; ++ res = Q931_RES_HAVEEVENT; ++ ++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_RETRIEVE_IND); ++ ++ /* Stop any T-RETRIEVE timer from possible retrieve collision. */ ++ pri_schedule_del(ctrl, master_call->hold_timer); ++ master_call->hold_timer = 0; ++ break; ++ default: ++ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); ++ break; ++ } ++ break; ++ case Q931_CALL_STATE_DISCONNECT_INDICATION: ++ case Q931_CALL_STATE_RELEASE_REQUEST: ++ /* Ignore RETRIEVE request in these states. */ ++ break; ++ default: ++ q931_send_retrieve_rej_msg(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE); ++ break; ++ } ++ return res; + case Q931_RETRIEVE_ACKNOWLEDGE: ++ res = 0; ++ master_call = c->master_call; ++ switch (master_call->hold_state) { ++ case Q931_HOLD_STATE_RETRIEVE_REQ: ++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_IDLE); ++ ++ /* Stop T-RETRIEVE timer */ ++ pri_schedule_del(ctrl, master_call->hold_timer); ++ master_call->hold_timer = 0; ++ ++ ctrl->ev.e = PRI_EVENT_RETRIEVE_ACK; ++ ctrl->ev.retrieve_ack.channel = q931_encode_channel(c); ++ ctrl->ev.retrieve_ack.call = master_call; ++ ctrl->ev.retrieve_ack.subcmds = &ctrl->subcmds; ++ res = Q931_RES_HAVEEVENT; ++ break; ++ default: ++ /* Ignore response. Response is late or spurrious. */ ++ break; ++ } ++ return res; + case Q931_RETRIEVE_REJECT: ++ res = 0; ++ master_call = c->master_call; ++ switch (master_call->hold_state) { ++ case Q931_HOLD_STATE_RETRIEVE_REQ: ++ UPDATE_HOLD_STATE(ctrl, master_call, Q931_HOLD_STATE_CALL_HELD); ++ ++ /* Call is still on hold so forget the channel. */ ++ c->channelno = 0;/* No channel */ ++ c->ds1no = 0; ++ c->ds1explicit = 0; ++ c->chanflags = 0; ++ ++ /* Stop T-RETRIEVE timer */ ++ pri_schedule_del(ctrl, master_call->hold_timer); ++ master_call->hold_timer = 0; ++ ++ if (missingmand) { ++ /* Still, let retrive rejection continue. */ ++ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING; ++ } ++ ctrl->ev.e = PRI_EVENT_RETRIEVE_REJ; ++ ctrl->ev.retrieve_rej.channel = q931_encode_channel(c); ++ ctrl->ev.retrieve_rej.call = master_call; ++ ctrl->ev.retrieve_rej.cause = c->cause; ++ ctrl->ev.retrieve_rej.subcmds = &ctrl->subcmds; ++ res = Q931_RES_HAVEEVENT; ++ break; ++ default: ++ /* Ignore response. Response is late or spurrious. */ ++ break; ++ } ++ return res; ++ case Q931_USER_INFORMATION: ++ case Q931_SEGMENT: ++ case Q931_CONGESTION_CONTROL: + case Q931_RESUME: + case Q931_RESUME_ACKNOWLEDGE: + case Q931_RESUME_REJECT: + case Q931_SUSPEND: + case Q931_SUSPEND_ACKNOWLEDGE: + case Q931_SUSPEND_REJECT: +- pri_error(pri, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); ++ pri_error(ctrl, "!! Not yet handling post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); + /* Fall through */ + default: +- +- pri_error(pri, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); +- q931_status(pri,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); ++ pri_error(ctrl, "!! Don't know how to post-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg); ++ q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST); + if (c->newcall) +- q931_destroycall(pri,c->cr); ++ pri_destroycall(ctrl, c); + return -1; + } + return 0; +@@ -3941,40 +7337,46 @@ + static int pri_internal_clear(void *data) + { + struct q931_call *c = data; +- struct pri *pri = c->pri; ++ struct pri *ctrl = c->pri; + int res; + +- if (c->retranstimer) +- pri_schedule_del(pri, c->retranstimer); ++ pri_schedule_del(ctrl, c->retranstimer); + c->retranstimer = 0; + c->useruserinfo[0] = '\0'; +- c->cause = -1; ++ //c->cause = -1; + c->causecode = -1; + c->causeloc = -1; +- c->sugcallstate = -1; ++ c->sugcallstate = Q931_CALL_STATE_NOT_SET; + c->aoc_units = -1; + +- UPDATE_OURCALLSTATE(pri, c, Q931_CALL_STATE_NULL); ++ UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL); + c->peercallstate = Q931_CALL_STATE_NULL; +- pri->ev.hangup.channel = c->channelno | (c->ds1no << 8) | (c->ds1explicit << 16); +- pri->ev.hangup.cause = c->cause; +- pri->ev.hangup.cref = c->cr; +- pri->ev.hangup.call = c; +- pri->ev.hangup.aoc_units = c->aoc_units; +- libpri_copy_string(pri->ev.hangup.useruserinfo, c->useruserinfo, sizeof(pri->ev.hangup.useruserinfo)); ++ q931_clr_subcommands(ctrl); ++ ctrl->ev.hangup.subcmds = &ctrl->subcmds; ++ ctrl->ev.hangup.channel = q931_encode_channel(c); ++ ctrl->ev.hangup.cause = c->cause; ++ ctrl->ev.hangup.cref = c->cr; ++ ctrl->ev.hangup.call = c->master_call; ++ ctrl->ev.hangup.aoc_units = c->aoc_units; ++ ctrl->ev.hangup.call_held = NULL; ++ ctrl->ev.hangup.call_active = NULL; ++ libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo)); + ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) { ++ pri_message(ctrl, "clearing, alive %d, hangupack %d\n", c->alive, c->sendhangupack); ++ } + /* Free resources */ + if (c->alive) { +- pri->ev.e = PRI_EVENT_HANGUP; ++ ctrl->ev.e = PRI_EVENT_HANGUP; + res = Q931_RES_HAVEEVENT; + c->alive = 0; + } else if (c->sendhangupack) { + res = Q931_RES_HAVEEVENT; +- pri->ev.e = PRI_EVENT_HANGUP_ACK; +- q931_hangup(pri, c, c->cause); ++ ctrl->ev.e = PRI_EVENT_HANGUP_ACK; ++ pri_hangup(ctrl, c, c->cause); + } else { + res = 0; +- q931_hangup(pri, c, c->cause); ++ pri_hangup(ctrl, c, c->cause); + } + + return res; +@@ -3984,94 +7386,97 @@ + static void pri_dl_down_timeout(void *data) + { + struct q931_call *c = data; +- struct pri *pri = c->pri; +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, DBGHEAD "Timed out waiting for data link re-establishment\n", DBGINFO); ++ struct pri *ctrl = c->pri; ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, DBGHEAD "Timed out waiting for data link re-establishment\n", DBGINFO); + + c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER; + if (pri_internal_clear(c) == Q931_RES_HAVEEVENT) +- pri->schedev = 1; ++ ctrl->schedev = 1; + } + + /* Handle Layer 2 down event for a non active call. */ + static void pri_dl_down_cancelcall(void *data) + { + struct q931_call *c = data; +- struct pri *pri = c->pri; +- if (pri->debug & PRI_DEBUG_Q931_STATE) +- pri_message(pri, DBGHEAD "Cancel non active call after data link failure\n", DBGINFO); ++ struct pri *ctrl = c->pri; ++ if (ctrl->debug & PRI_DEBUG_Q931_STATE) ++ pri_message(ctrl, DBGHEAD "Cancel non active call after data link failure\n", DBGINFO); + + c->cause = PRI_CAUSE_DESTINATION_OUT_OF_ORDER; + if (pri_internal_clear(c) == Q931_RES_HAVEEVENT) +- pri->schedev = 1; ++ ctrl->schedev = 1; + } + + /* Receive an indication from Layer 2 */ +-void q931_dl_indication(struct pri *pri, int event) ++void q931_dl_indication(struct pri *ctrl, int event) + { + q931_call *cur = NULL; + + /* Just return if T309 is not enabled. */ +- if (!pri || pri->timers[PRI_TIMER_T309] < 0) ++ if (!ctrl || ctrl->timers[PRI_TIMER_T309] < 0) + return; + + switch (event) { + case PRI_EVENT_DCHAN_DOWN: +- pri_message(pri, DBGHEAD "link is DOWN\n", DBGINFO); +- cur = *pri->callpool; ++ pri_message(ctrl, DBGHEAD "link is DOWN\n", DBGINFO); ++ cur = *ctrl->callpool; + while(cur) { + if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE) { + /* For a call in Active state, activate T309 only if there is no timer already running. */ + if (!cur->retranstimer) { +- pri_message(pri, DBGHEAD "activate T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno); +- cur->retranstimer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T309], pri_dl_down_timeout, cur); ++ pri_message(ctrl, DBGHEAD "activate T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno); ++ cur->retranstimer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T309], pri_dl_down_timeout, cur); + } + } else if (cur->ourcallstate != Q931_CALL_STATE_NULL) { + /* For a call that is not in Active state, schedule internal clearing of the call 'ASAP' (delay 0). */ +- pri_message(pri, DBGHEAD "cancel call %d on channel %d in state %d (%s)\n", DBGINFO, +- cur->cr, cur->channelno, cur->ourcallstate, callstate2str(cur->ourcallstate)); +- if (cur->retranstimer) +- pri_schedule_del(pri, cur->retranstimer); +- cur->retranstimer = pri_schedule_event(pri, 0, pri_dl_down_cancelcall, cur); ++ pri_message(ctrl, DBGHEAD "cancel call %d on channel %d in state %d (%s)\n", DBGINFO, ++ cur->cr, cur->channelno, cur->ourcallstate, ++ q931_call_state_str(cur->ourcallstate)); ++ pri_schedule_del(ctrl, cur->retranstimer); ++ cur->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall, cur); + } + cur = cur->next; + } + break; + case PRI_EVENT_DCHAN_UP: +- pri_message(pri, DBGHEAD "link is UP\n", DBGINFO); +- cur = *pri->callpool; ++ pri_message(ctrl, DBGHEAD "link is UP\n", DBGINFO); ++ cur = *ctrl->callpool; + while(cur) { + if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE && cur->retranstimer) { +- pri_message(pri, DBGHEAD "cancel T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno); +- pri_schedule_del(pri, cur->retranstimer); ++ pri_message(ctrl, DBGHEAD "cancel T309 for call %d on channel %d\n", DBGINFO, cur->cr, cur->channelno); ++ pri_schedule_del(ctrl, cur->retranstimer); + cur->retranstimer = 0; +- q931_status(pri, cur, PRI_CAUSE_NORMAL_UNSPECIFIED); ++ q931_status(ctrl, cur, PRI_CAUSE_NORMAL_UNSPECIFIED); + } else if (cur->ourcallstate != Q931_CALL_STATE_NULL && + cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_REQUEST && + cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_INDICATION && + cur->ourcallstate != Q931_CALL_STATE_RELEASE_REQUEST) { + + /* The STATUS message sent here is not required by Q.931, but it may help anyway. */ +- q931_status(pri, cur, PRI_CAUSE_NORMAL_UNSPECIFIED); ++ q931_status(ctrl, cur, PRI_CAUSE_NORMAL_UNSPECIFIED); + } + cur = cur->next; + } + break; + default: +- pri_message(pri, DBGHEAD "unexpected event %d.\n", DBGINFO, event); ++ pri_message(ctrl, DBGHEAD "unexpected event %d.\n", DBGINFO, event); + } + } + +-int q931_call_getcrv(struct pri *pri, q931_call *call, int *callmode) ++int q931_call_getcrv(struct pri *ctrl, q931_call *call, int *callmode) + { + if (callmode) + *callmode = call->cr & 0x7; + return ((call->cr & 0x7fff) >> 3); + } + +-int q931_call_setcrv(struct pri *pri, q931_call *call, int crv, int callmode) ++int q931_call_setcrv(struct pri *ctrl, q931_call *call, int crv, int callmode) + { +- call->cr = (crv << 3) & 0x7fff; +- call->cr |= (callmode & 0x7); ++ /* Do not allow changing the dummy call reference */ ++ if (!q931_is_dummy_call(call)) { ++ call->cr = (crv << 3) & 0x7fff; ++ call->cr |= (callmode & 0x7); ++ } + return 0; + } +Index: asn1.h +=================================================================== +--- a/asn1.h (.../tags/1.4.10.2) (revision 0) ++++ b/asn1.h (.../branches/1.4) (revision 1357) +@@ -0,0 +1,257 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief ASN.1 definitions and prototypes ++ * ++ * \details ++ * This file contains all ASN.1 primitive data structures and ++ * definitions needed for ROSE component encoding and decoding. ++ * ++ * ROSE - Remote Operations Service Element ++ * ASN.1 - Abstract Syntax Notation 1 ++ * APDU - Application Protocol Data Unit ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++#ifndef _LIBPRI_ASN1_H ++#define _LIBPRI_ASN1_H ++ ++#include <string.h> ++#include <sys/types.h> ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ------------------------------------------------------------------- */ ++ ++/*! ASN.1 Identifier Octet - Tag class bits */ ++#define ASN1_CLASS_MASK 0xc0 ++#define ASN1_CLASS_UNIVERSAL 0x00 /*!< Universal primitive data types */ ++#define ASN1_CLASS_APPLICATION 0x40 /*!< Application wide data tag */ ++#define ASN1_CLASS_CONTEXT_SPECIFIC 0x80 /*!< Context specifc data tag */ ++#define ASN1_CLASS_PRIVATE 0xc0 /*!< Private organization data tag */ ++ ++/*! ASN.1 Identifier Octet - Primitive/Constructor bit */ ++#define ASN1_PC_MASK 0x20 ++#define ASN1_PC_PRIMITIVE 0x00 ++#define ASN1_PC_CONSTRUCTED 0x20 ++ ++/*! ASN.1 Identifier Octet - Universal data types */ ++#define ASN1_TYPE_MASK 0x1f ++#define ASN1_TYPE_INDEF_TERM 0x00 /* 0 */ ++#define ASN1_TYPE_BOOLEAN 0x01 /* 1 */ ++#define ASN1_TYPE_INTEGER 0x02 /* 2 */ ++#define ASN1_TYPE_BIT_STRING 0x03 /* 3 */ ++#define ASN1_TYPE_OCTET_STRING 0x04 /* 4 */ ++#define ASN1_TYPE_NULL 0x05 /* 5 */ ++#define ASN1_TYPE_OBJECT_IDENTIFIER 0x06 /* 6 */ ++#define ASN1_TYPE_OBJECT_DESCRIPTOR 0x07 /* 7 */ ++#define ASN1_TYPE_EXTERN 0x08 /* 8 */ ++#define ASN1_TYPE_REAL 0x09 /* 9 */ ++#define ASN1_TYPE_ENUMERATED 0x0a /* 10 */ ++#define ASN1_TYPE_EMBEDDED_PDV 0x0b /* 11 */ ++#define ASN1_TYPE_UTF8_STRING 0x0c /* 12 */ ++#define ASN1_TYPE_RELATIVE_OID 0x0d /* 13 */ ++/* 0x0e & 0x0f are reserved for future ASN.1 editions */ ++#define ASN1_TYPE_SEQUENCE 0x10 /* 16 */ ++#define ASN1_TYPE_SET 0x11 /* 17 */ ++#define ASN1_TYPE_NUMERIC_STRING 0x12 /* 18 */ ++#define ASN1_TYPE_PRINTABLE_STRING 0x13 /* 19 */ ++#define ASN1_TYPE_TELETEX_STRING 0x14 /* 20 */ ++#define ASN1_TYPE_VIDEOTEX_STRING 0x15 /* 21 */ ++#define ASN1_TYPE_IA5_STRING 0x16 /* 22 */ ++#define ASN1_TYPE_UTC_TIME 0x17 /* 23 */ ++#define ASN1_TYPE_GENERALIZED_TIME 0x18 /* 24 */ ++#define ASN1_TYPE_GRAPHIC_STRING 0x19 /* 25 */ ++#define ASN1_TYPE_VISIBLE_STRING 0x1a /* 26 */ ++#define ASN1_TYPE_ISO646_STRING 0x1a /* 26 */ ++#define ASN1_TYPE_GENERAL_STRING 0x1b /* 27 */ ++#define ASN1_TYPE_UNIVERSAL_STRING 0x1c /* 28 */ ++#define ASN1_TYPE_CHAR_STRING 0x1d /* 29 */ ++#define ASN1_TYPE_BMP_STRING 0x1e /* 30 */ ++#define ASN1_TYPE_EXTENSION 0x1f /* 31 */ ++ ++#define ASN1_TAG_SEQUENCE (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_SEQUENCE) ++#define ASN1_TAG_SET (ASN1_CLASS_UNIVERSAL | ASN1_PC_CONSTRUCTED | ASN1_TYPE_SET) ++ ++#define ASN1_INDEF_TERM (ASN1_CLASS_UNIVERSAL | ASN1_PC_PRIMITIVE | ASN1_TYPE_INDEF_TERM) ++#define ASN1_INDEF_TERM_LEN 2 ++ ++struct asn1_oid { ++ /*! \brief Number of subidentifier values in OID list */ ++ u_int16_t num_values; ++ ++ /*! ++ * \brief OID subidentifier value list ++ * \note The first value is really the first two OID subidentifiers. ++ * They are compressed using this formula: ++ * First_Value = (First_Subidentifier * 40) + Second_Subidentifier ++ */ ++ u_int16_t value[10]; ++}; ++ ++#define ASN1_CALL(new_pos, do_it) \ ++ do \ ++ { \ ++ (new_pos) = (do_it); \ ++ if (!(new_pos)) { \ ++ return NULL; \ ++ } \ ++ } while (0) ++ ++/*! \brief Determine the ending position of the set or sequence to verify the length. */ ++#define ASN1_END_SETUP(component_end, offset, length, pos, end) \ ++ do { \ ++ if ((length) < 0) { \ ++ (offset) = ASN1_INDEF_TERM_LEN; \ ++ (component_end) = (end); \ ++ } else { \ ++ (offset) = 0; \ ++ (component_end) = (pos) + (length); \ ++ } \ ++ } while (0) ++ ++/*! \brief Account for the indefinite length terminator of the set or sequence. */ ++#define ASN1_END_FIXUP(ctrl, pos, offset, component_end, end) \ ++ do { \ ++ if (offset) { \ ++ ASN1_CALL((pos), asn1_dec_indef_end_fixup((ctrl), (pos), (end))); \ ++ } else if ((pos) != (component_end)) { \ ++ if ((ctrl)->debug & PRI_DEBUG_APDU) { \ ++ pri_message((ctrl), \ ++ " Skipping unused constructed component octets!\n"); \ ++ } \ ++ (pos) = (component_end); \ ++ } \ ++ } while (0) ++ ++#define ASN1_DID_NOT_EXPECT_TAG(ctrl, tag) \ ++ do { \ ++ if ((ctrl)->debug & PRI_DEBUG_APDU) { \ ++ pri_message((ctrl), " Did not expect: %s\n", asn1_tag2str(tag)); \ ++ } \ ++ } while (0) ++ ++#define ASN1_CHECK_TAG(ctrl, actual_tag, match_tag, expected_tag) \ ++ do { \ ++ if ((match_tag) != (expected_tag)) { \ ++ ASN1_DID_NOT_EXPECT_TAG((ctrl), (actual_tag)); \ ++ return NULL; \ ++ } \ ++ } while (0) ++ ++ ++const unsigned char *asn1_dec_tag(const unsigned char *tag_pos, const unsigned char *end, ++ unsigned *tag); ++const unsigned char *asn1_dec_length(const unsigned char *len_pos, ++ const unsigned char *end, int *length); ++const unsigned char *asn1_dec_indef_end_fixup(struct pri *ctrl, const unsigned char *pos, ++ const unsigned char *end); ++ ++const unsigned char *asn1_dec_boolean(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, int32_t *value); ++const unsigned char *asn1_dec_int(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, int32_t *value); ++const unsigned char *asn1_dec_null(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end); ++const unsigned char *asn1_dec_oid(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, struct asn1_oid *oid); ++const unsigned char *asn1_dec_string_bin(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size, ++ unsigned char *str, size_t *str_len); ++const unsigned char *asn1_dec_string_max(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, size_t buf_size, ++ unsigned char *str, size_t *str_len); ++ ++const char *asn1_tag2str(unsigned tag); ++void asn1_dump(struct pri *ctrl, const unsigned char *start_asn1, ++ const unsigned char *end); ++ ++ ++#define ASN1_LEN_FORM_SHORT 1 /*!< Hint that the final length will be less than 128 octets */ ++#define ASN1_LEN_FORM_LONG_U8 2 /*!< Hint that the final length will be less than 256 octets */ ++#define ASN1_LEN_FORM_LONG_U16 3 /*!< Hint that the final length will be less than 65536 octets */ ++#define ASN1_LEN_INIT(len_pos, end, form_hint) \ ++ do { \ ++ if ((end) < (len_pos) + (form_hint)) { \ ++ return NULL; \ ++ } \ ++ *(len_pos) = (form_hint); \ ++ (len_pos) += (form_hint); \ ++ } while (0) ++ ++#define ASN1_LEN_FIXUP(len_pos, component_end, end) \ ++ ASN1_CALL((component_end), asn1_enc_length_fixup((len_pos), (component_end), (end))) ++ ++/*! \brief Use to begin encoding explicit tags, SET, and SEQUENCE constructed groupings. */ ++#define ASN1_CONSTRUCTED_BEGIN(len_pos_save, pos, end, tag) \ ++ do { \ ++ if ((end) < (pos) + (1 + ASN1_LEN_FORM_SHORT)) { \ ++ return NULL; \ ++ } \ ++ *(pos)++ = (tag) | ASN1_PC_CONSTRUCTED; \ ++ (len_pos_save) = (pos); \ ++ *(pos) = ASN1_LEN_FORM_SHORT; \ ++ (pos) += ASN1_LEN_FORM_SHORT; \ ++ } while (0) ++ ++/*! \brief Use to end encoding explicit tags, SET, and SEQUENCE constructed groupings. */ ++#define ASN1_CONSTRUCTED_END(len_pos, component_end, end) \ ++ ASN1_CALL((component_end), asn1_enc_length_fixup((len_pos), (component_end), (end))) ++ ++#define ASN1_ENC_ERROR(ctrl, msg) \ ++ pri_error((ctrl), "%s error: %s\n", __FUNCTION__, (msg)) ++ ++unsigned char *asn1_enc_length(unsigned char *len_pos, unsigned char *end, ++ size_t str_len); ++unsigned char *asn1_enc_length_fixup(unsigned char *len_pos, ++ unsigned char *component_end, unsigned char *end); ++ ++unsigned char *asn1_enc_boolean(unsigned char *pos, unsigned char *end, unsigned tag, ++ int32_t value); ++unsigned char *asn1_enc_int(unsigned char *pos, unsigned char *end, unsigned tag, ++ int32_t value); ++unsigned char *asn1_enc_null(unsigned char *pos, unsigned char *end, unsigned tag); ++unsigned char *asn1_enc_oid(unsigned char *pos, unsigned char *end, unsigned tag, ++ const struct asn1_oid *oid); ++unsigned char *asn1_enc_string_bin(unsigned char *pos, unsigned char *end, unsigned tag, ++ const unsigned char *str, size_t str_len); ++unsigned char *asn1_enc_string_max(unsigned char *pos, unsigned char *end, unsigned tag, ++ const unsigned char *str, size_t max_len); ++ ++/* ------------------------------------------------------------------- */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _LIBPRI_ASN1_H */ ++/* ------------------------------------------------------------------- */ ++/* end asn1.h */ + +Property changes on: asn1.h +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: rose.c +=================================================================== +--- a/rose.c (.../tags/1.4.10.2) (revision 0) ++++ b/rose.c (.../branches/1.4) (revision 1357) +@@ -0,0 +1,2464 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief Remote Operations Service Element (ROSE) main controlling functions ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++ ++#include <stdio.h> ++ ++#include "compat.h" ++#include "libpri.h" ++#include "pri_internal.h" ++#include "rose.h" ++#include "rose_internal.h" ++#include "asn1.h" ++#include "pri_facility.h" ++ ++ ++#define ROSE_TAG_COMPONENT_INVOKE (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1) ++#define ROSE_TAG_COMPONENT_RESULT (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2) ++#define ROSE_TAG_COMPONENT_ERROR (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3) ++#define ROSE_TAG_COMPONENT_REJECT (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4) ++ ++/*! \brief Structure to convert a code value to a string */ ++struct rose_code_strings { ++ /*! \brief Code value to convert to a string */ ++ int code; ++ /*! \brief String equivalent of the associated code value */ ++ const char *name; ++}; ++ ++/*! \brief ROSE invoke/result message conversion table entry. */ ++struct rose_convert_msg { ++ /*! \brief library encoded operation-value */ ++ enum rose_operation operation; ++ /*! ++ * \brief OID prefix values to use when encoding/decoding the operation-value OID ++ * \note NULL if operation-value is a localValue. ++ */ ++ const struct asn1_oid *oid_prefix; ++ /*! \brief Last OID value or localValue for the encoded operation-value */ ++ u_int16_t value; ++ ++ /*! ++ * \brief Encode the ROSE invoke operation-value arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ * ++ * \note The function pointer is NULL if there are no arguments to encode. ++ */ ++ unsigned char *(*encode_invoke_args)(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args); ++ /*! ++ * \brief Encode the ROSE result operation-value arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ * ++ * \note The function pointer is NULL if there are no arguments to encode. ++ */ ++ unsigned char *(*encode_result_args)(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args); ++ ++ /*! ++ * \brief Decode the ROSE invoke operation-value arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ * ++ * \note The function pointer is NULL if there are no arguments to decode. ++ */ ++ const unsigned char *(*decode_invoke_args)(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args); ++ /*! ++ * \brief Decode the ROSE result operation-value arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ * ++ * \note The function pointer is NULL if there are no arguments to decode. ++ */ ++ const unsigned char *(*decode_result_args)(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args); ++}; ++ ++/*! \brief ROSE error code conversion table entry. */ ++struct rose_convert_error { ++ /*! \brief library encoded error-value */ ++ enum rose_error_code code; ++ /*! ++ * \brief OID prefix values to use when encoding/decoding the error-value OID ++ * \note NULL if error-value is a localValue. ++ */ ++ const struct asn1_oid *oid_prefix; ++ /*! \brief Last OID value or localValue for the encoded error-value */ ++ u_int16_t value; ++ ++ /*! ++ * \brief Encode the ROSE error parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ * ++ * \note The function pointer is NULL if there are no arguments to encode. ++ */ ++ unsigned char *(*encode_error_args)(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_error_args *args); ++ ++ /*! ++ * \brief Decode the ROSE error parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ * ++ * \note The function pointer is NULL if there are no arguments to decode. ++ */ ++ const unsigned char *(*decode_error_args)(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ union rose_msg_error_args *args); ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * Note the first value in oid.values[] is really the first two ++ * OID subidentifiers. They are compressed using this formula: ++ * First_Value = (First_Subidentifier * 40) + Second_Subidentifier ++ */ ++ ++/*! \brief ETSI Explicit Call Transfer OID prefix. */ ++static const struct asn1_oid rose_etsi_ect = { ++/* *INDENT-OFF* */ ++ /* {ccitt(0) identified-organization(4) etsi(0) 369 operations-and-errors(1)} */ ++ 4, { 4, 0, 369, 1 } ++/* *INDENT-ON* */ ++}; ++ ++/*! \brief ETSI specific invoke/result encode/decode message table */ ++static const struct rose_convert_msg rose_etsi_msgs[] = { ++/* *INDENT-OFF* */ ++/* ++ * operation, oid_prefix, value, ++ * encode_invoke_args, encode_result_args, ++ * decode_invoke_args, decode_result_args ++ */ ++ /* ++ * localValue's from Diversion-Operations ++ * {ccitt identified-organization etsi(0) 207 operations-and-errors(1)} ++ */ ++ { ++ ROSE_ETSI_ActivationDiversion, NULL, 7, ++ rose_enc_etsi_ActivationDiversion_ARG, NULL, ++ rose_dec_etsi_ActivationDiversion_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_DeactivationDiversion, NULL, 8, ++ rose_enc_etsi_DeactivationDiversion_ARG,NULL, ++ rose_dec_etsi_DeactivationDiversion_ARG,NULL ++ }, ++ { ++ ROSE_ETSI_ActivationStatusNotificationDiv, NULL, 9, ++ rose_enc_etsi_ActivationStatusNotificationDiv_ARG,NULL, ++ rose_dec_etsi_ActivationStatusNotificationDiv_ARG,NULL ++ }, ++ { ++ ROSE_ETSI_DeactivationStatusNotificationDiv,NULL, 10, ++ rose_enc_etsi_DeactivationStatusNotificationDiv_ARG,NULL, ++ rose_dec_etsi_DeactivationStatusNotificationDiv_ARG,NULL ++ }, ++ { ++ ROSE_ETSI_InterrogationDiversion, NULL, 11, ++ rose_enc_etsi_InterrogationDiversion_ARG,rose_enc_etsi_InterrogationDiversion_RES, ++ rose_dec_etsi_InterrogationDiversion_ARG,rose_dec_etsi_InterrogationDiversion_RES ++ }, ++ { ++ ROSE_ETSI_DiversionInformation, NULL, 12, ++ rose_enc_etsi_DiversionInformation_ARG, NULL, ++ rose_dec_etsi_DiversionInformation_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_CallDeflection, NULL, 13, ++ rose_enc_etsi_CallDeflection_ARG, NULL, ++ rose_dec_etsi_CallDeflection_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_CallRerouting, NULL, 14, ++ rose_enc_etsi_CallRerouting_ARG, NULL, ++ rose_dec_etsi_CallRerouting_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_DivertingLegInformation2, NULL, 15, ++ rose_enc_etsi_DivertingLegInformation2_ARG,NULL, ++ rose_dec_etsi_DivertingLegInformation2_ARG,NULL ++ }, ++ { ++ ROSE_ETSI_InterrogateServedUserNumbers, NULL, 17, ++ NULL, rose_enc_etsi_InterrogateServedUserNumbers_RES, ++ NULL, rose_dec_etsi_InterrogateServedUserNumbers_RES ++ }, ++ { ++ ROSE_ETSI_DivertingLegInformation1, NULL, 18, ++ rose_enc_etsi_DivertingLegInformation1_ARG,NULL, ++ rose_dec_etsi_DivertingLegInformation1_ARG,NULL ++ }, ++ { ++ ROSE_ETSI_DivertingLegInformation3, NULL, 19, ++ rose_enc_etsi_DivertingLegInformation3_ARG,NULL, ++ rose_dec_etsi_DivertingLegInformation3_ARG,NULL ++ }, ++ ++ /* ++ * localValue's from Advice-of-Charge-Operations ++ * {ccitt identified-organization etsi (0) 182 operations-and-errors (1)} ++ * ++ * Advice-Of-Charge-at-call-Setup(AOCS) ++ * Advice-Of-Charge-During-the-call(AOCD) ++ * Advice-Of-Charge-at-the-End-of-the-call(AOCE) ++ */ ++ { ++ ROSE_ETSI_ChargingRequest, NULL, 30, ++ rose_enc_etsi_ChargingRequest_ARG, rose_enc_etsi_ChargingRequest_RES, ++ rose_dec_etsi_ChargingRequest_ARG, rose_dec_etsi_ChargingRequest_RES ++ }, ++ { ++ ROSE_ETSI_AOCSCurrency, NULL, 31, ++ rose_enc_etsi_AOCSCurrency_ARG, NULL, ++ rose_dec_etsi_AOCSCurrency_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_AOCSSpecialArr, NULL, 32, ++ rose_enc_etsi_AOCSSpecialArr_ARG, NULL, ++ rose_dec_etsi_AOCSSpecialArr_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_AOCDCurrency, NULL, 33, ++ rose_enc_etsi_AOCDCurrency_ARG, NULL, ++ rose_dec_etsi_AOCDCurrency_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_AOCDChargingUnit, NULL, 34, ++ rose_enc_etsi_AOCDChargingUnit_ARG, NULL, ++ rose_dec_etsi_AOCDChargingUnit_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_AOCECurrency, NULL, 35, ++ rose_enc_etsi_AOCECurrency_ARG, NULL, ++ rose_dec_etsi_AOCECurrency_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_AOCEChargingUnit, NULL, 36, ++ rose_enc_etsi_AOCEChargingUnit_ARG, NULL, ++ rose_dec_etsi_AOCEChargingUnit_ARG, NULL ++ }, ++ ++ /* ++ * localValue's from Explicit-Call-Transfer-Operations-and-Errors ++ * {ccitt identified-organization etsi(0) 369 operations-and-errors(1)} ++ */ ++ { ++ ROSE_ETSI_EctExecute, NULL, 6, ++ NULL, NULL, ++ NULL, NULL ++ }, ++ ++ /* ++ * globalValue's (OIDs) from Explicit-Call-Transfer-Operations-and-Errors ++ * {ccitt identified-organization etsi(0) 369 operations-and-errors(1)} ++ */ ++ { ++ ROSE_ETSI_ExplicitEctExecute, &rose_etsi_ect, 1, ++ rose_enc_etsi_ExplicitEctExecute_ARG, NULL, ++ rose_dec_etsi_ExplicitEctExecute_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_RequestSubaddress, &rose_etsi_ect, 2, ++ NULL, NULL, ++ NULL, NULL ++ }, ++ { ++ ROSE_ETSI_SubaddressTransfer, &rose_etsi_ect, 3, ++ rose_enc_etsi_SubaddressTransfer_ARG, NULL, ++ rose_dec_etsi_SubaddressTransfer_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_EctLinkIdRequest, &rose_etsi_ect, 4, ++ NULL, rose_enc_etsi_EctLinkIdRequest_RES, ++ NULL, rose_dec_etsi_EctLinkIdRequest_RES ++ }, ++ { ++ ROSE_ETSI_EctInform, &rose_etsi_ect, 5, ++ rose_enc_etsi_EctInform_ARG, NULL, ++ rose_dec_etsi_EctInform_ARG, NULL ++ }, ++ { ++ ROSE_ETSI_EctLoopTest, &rose_etsi_ect, 6, ++ rose_enc_etsi_EctLoopTest_ARG, rose_enc_etsi_EctLoopTest_RES, ++ rose_dec_etsi_EctLoopTest_ARG, rose_dec_etsi_EctLoopTest_RES ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++/*! \brief ETSI specific error-value converion table */ ++static const struct rose_convert_error rose_etsi_errors[] = { ++/* *INDENT-OFF* */ ++/* ++ * error-code, oid_prefix, value ++ * encode_error_args, decode_error_args ++ */ ++ /* ++ * localValue Errors from General-Errors ++ * {ccitt identified-organization etsi(0) 196 general-errors(2)} ++ */ ++ { ++ ROSE_ERROR_Gen_NotSubscribed, NULL, 0, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_NotAvailable, NULL, 3, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_NotImplemented, NULL, 4, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_InvalidServedUserNr, NULL, 6, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_InvalidCallState, NULL, 7, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_BasicServiceNotProvided, NULL, 8, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_NotIncomingCall, NULL, 9, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed,NULL, 10, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_ResourceUnavailable, NULL, 11, ++ NULL, NULL ++ }, ++ ++ /* ++ * localValue Errors from Diversion-Operations ++ * {ccitt identified-organization etsi(0) 207 operations-and-errors(1)} ++ */ ++ { ++ ROSE_ERROR_Div_InvalidDivertedToNr, NULL, 12, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Div_SpecialServiceNr, NULL, 14, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Div_DiversionToServedUserNr, NULL, 15, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Div_IncomingCallAccepted, NULL, 23, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Div_NumberOfDiversionsExceeded, NULL, 24, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Div_NotActivated, NULL, 46, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Div_RequestAlreadyAccepted, NULL, 48, ++ NULL, NULL ++ }, ++ ++ /* ++ * localValue Errors from Advice-of-Charge-Operations ++ * {ccitt identified-organization etsi (0) 182 operations-and-errors (1)} ++ */ ++ { ++ ROSE_ERROR_AOC_NoChargingInfoAvailable, NULL, 26, ++ NULL, NULL ++ }, ++ ++ /* ++ * globalValue Errors (OIDs) from Explicit-Call-Transfer-Operations-and-Errors ++ * {ccitt identified-organization etsi(0) 369 operations-and-errors(1)} ++ */ ++ { ++ ROSE_ERROR_ECT_LinkIdNotAssignedByNetwork, &rose_etsi_ect, 21, ++ NULL, NULL ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/*! \brief Q.SIG specific invoke/result encode/decode message table */ ++static const struct rose_convert_msg rose_qsig_msgs[] = { ++/* *INDENT-OFF* */ ++/* ++ * operation, oid_prefix, value, ++ * encode_invoke_args, encode_result_args, ++ * decode_invoke_args, decode_result_args ++ */ ++ /* ++ * localValue's from Q.SIG Name-Operations ++ * { iso(1) standard(0) pss1-name(13868) name-operations(0) } ++ */ ++ { ++ ROSE_QSIG_CallingName, NULL, 0, ++ rose_enc_qsig_CallingName_ARG, NULL, ++ rose_dec_qsig_CallingName_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_CalledName, NULL, 1, ++ rose_enc_qsig_CalledName_ARG, NULL, ++ rose_dec_qsig_CalledName_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_ConnectedName, NULL, 2, ++ rose_enc_qsig_ConnectedName_ARG, NULL, ++ rose_dec_qsig_ConnectedName_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_BusyName, NULL, 3, ++ rose_enc_qsig_BusyName_ARG, NULL, ++ rose_dec_qsig_BusyName_ARG, NULL ++ }, ++ ++ /* ++ * localValue's from Q.SIG SS-AOC-Operations ++ * { iso(1) standard(0) pss1-advice-of-charge(15050) advice-of-charge-operations(0) } ++ */ ++ { ++ ROSE_QSIG_ChargeRequest, NULL, 59, ++ rose_enc_qsig_ChargeRequest_ARG, rose_enc_qsig_ChargeRequest_RES, ++ rose_dec_qsig_ChargeRequest_ARG, rose_dec_qsig_ChargeRequest_RES ++ }, ++ { ++ ROSE_QSIG_GetFinalCharge, NULL, 60, ++ rose_enc_qsig_DummyArg_ARG, NULL, ++ rose_dec_qsig_DummyArg_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_AocFinal, NULL, 61, ++ rose_enc_qsig_AocFinal_ARG, NULL, ++ rose_dec_qsig_AocFinal_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_AocInterim, NULL, 62, ++ rose_enc_qsig_AocInterim_ARG, NULL, ++ rose_dec_qsig_AocInterim_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_AocRate, NULL, 63, ++ rose_enc_qsig_AocRate_ARG, NULL, ++ rose_dec_qsig_AocRate_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_AocComplete, NULL, 64, ++ rose_enc_qsig_AocComplete_ARG, rose_enc_qsig_AocComplete_RES, ++ rose_dec_qsig_AocComplete_ARG, rose_dec_qsig_AocComplete_RES ++ }, ++ { ++ ROSE_QSIG_AocDivChargeReq, NULL, 65, ++ rose_enc_qsig_AocDivChargeReq_ARG, NULL, ++ rose_dec_qsig_AocDivChargeReq_ARG, NULL ++ }, ++ ++ /* ++ * localValue's from Q.SIG Call-Transfer-Operations ++ * { iso(1) standard(0) pss1-call-transfer(13869) call-transfer-operations(0) } ++ */ ++ { ++ ROSE_QSIG_CallTransferIdentify, NULL, 7, ++ rose_enc_qsig_DummyArg_ARG, rose_enc_qsig_CallTransferIdentify_RES, ++ rose_dec_qsig_DummyArg_ARG, rose_dec_qsig_CallTransferIdentify_RES ++ }, ++ { ++ ROSE_QSIG_CallTransferAbandon, NULL, 8, ++ rose_enc_qsig_DummyArg_ARG, NULL, ++ rose_dec_qsig_DummyArg_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_CallTransferInitiate, NULL, 9, ++ rose_enc_qsig_CallTransferInitiate_ARG, rose_enc_qsig_DummyRes_RES, ++ rose_dec_qsig_CallTransferInitiate_ARG, rose_dec_qsig_DummyRes_RES ++ }, ++ { ++ ROSE_QSIG_CallTransferSetup, NULL, 10, ++ rose_enc_qsig_CallTransferSetup_ARG, rose_enc_qsig_DummyRes_RES, ++ rose_dec_qsig_CallTransferSetup_ARG, rose_dec_qsig_DummyRes_RES ++ }, ++ { ++ ROSE_QSIG_CallTransferActive, NULL, 11, ++ rose_enc_qsig_CallTransferActive_ARG, NULL, ++ rose_dec_qsig_CallTransferActive_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_CallTransferComplete, NULL, 12, ++ rose_enc_qsig_CallTransferComplete_ARG, NULL, ++ rose_dec_qsig_CallTransferComplete_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_CallTransferUpdate, NULL, 13, ++ rose_enc_qsig_CallTransferUpdate_ARG, NULL, ++ rose_dec_qsig_CallTransferUpdate_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_SubaddressTransfer, NULL, 14, ++ rose_enc_qsig_SubaddressTransfer_ARG, NULL, ++ rose_dec_qsig_SubaddressTransfer_ARG, NULL ++ }, ++ ++ /* ++ * NOTE: I do not have the specification needed to fully support this ++ * message. Fortunately, all I have to do for this message is to switch ++ * it to the bridged call leg for 2BCT support. ++ */ ++ { ++ ROSE_QSIG_PathReplacement, NULL, 4, ++ NULL, NULL, ++ NULL, NULL ++ }, ++ ++ /* ++ * localValue's from Q.SIG Call-Diversion-Operations ++ * { iso(1) standard(0) pss1-call-diversion(13873) call-diversion-operations(0) } ++ */ ++ { ++ ROSE_QSIG_ActivateDiversionQ, NULL, 15, ++ rose_enc_qsig_ActivateDiversionQ_ARG, rose_enc_qsig_DummyRes_RES, ++ rose_dec_qsig_ActivateDiversionQ_ARG, rose_dec_qsig_DummyRes_RES ++ }, ++ { ++ ROSE_QSIG_DeactivateDiversionQ, NULL, 16, ++ rose_enc_qsig_DeactivateDiversionQ_ARG, rose_enc_qsig_DummyRes_RES, ++ rose_dec_qsig_DeactivateDiversionQ_ARG, rose_dec_qsig_DummyRes_RES ++ }, ++ { ++ ROSE_QSIG_InterrogateDiversionQ, NULL, 17, ++ rose_enc_qsig_InterrogateDiversionQ_ARG,rose_enc_qsig_InterrogateDiversionQ_RES, ++ rose_dec_qsig_InterrogateDiversionQ_ARG,rose_dec_qsig_InterrogateDiversionQ_RES ++ }, ++ { ++ ROSE_QSIG_CheckRestriction, NULL, 18, ++ rose_enc_qsig_CheckRestriction_ARG, rose_enc_qsig_DummyRes_RES, ++ rose_dec_qsig_CheckRestriction_ARG, rose_dec_qsig_DummyRes_RES ++ }, ++ { ++ ROSE_QSIG_CallRerouting, NULL, 19, ++ rose_enc_qsig_CallRerouting_ARG, rose_enc_qsig_DummyRes_RES, ++ rose_dec_qsig_CallRerouting_ARG, rose_dec_qsig_DummyRes_RES ++ }, ++ { ++ ROSE_QSIG_DivertingLegInformation1, NULL, 20, ++ rose_enc_qsig_DivertingLegInformation1_ARG,NULL, ++ rose_dec_qsig_DivertingLegInformation1_ARG,NULL ++ }, ++ { ++ ROSE_QSIG_DivertingLegInformation2, NULL, 21, ++ rose_enc_qsig_DivertingLegInformation2_ARG,NULL, ++ rose_dec_qsig_DivertingLegInformation2_ARG,NULL ++ }, ++ { ++ ROSE_QSIG_DivertingLegInformation3, NULL, 22, ++ rose_enc_qsig_DivertingLegInformation3_ARG,NULL, ++ rose_dec_qsig_DivertingLegInformation3_ARG,NULL ++ }, ++ { ++ ROSE_QSIG_CfnrDivertedLegFailed, NULL, 23, ++ rose_enc_qsig_DummyArg_ARG, NULL, ++ rose_dec_qsig_DummyArg_ARG, NULL ++ }, ++ ++ /* ++ * localValue's from Q.SIG SS-MWI-Operations ++ * { iso(1) standard(0) pss1-message-waiting-indication(15506) message-waiting-operations(0) } ++ */ ++ { ++ ROSE_QSIG_MWIActivate, NULL, 80, ++ rose_enc_qsig_MWIActivate_ARG, rose_enc_qsig_DummyRes_RES, ++ rose_dec_qsig_MWIActivate_ARG, rose_dec_qsig_DummyRes_RES ++ }, ++ { ++ ROSE_QSIG_MWIDeactivate, NULL, 81, ++ rose_enc_qsig_MWIDeactivate_ARG, rose_enc_qsig_DummyRes_RES, ++ rose_dec_qsig_MWIDeactivate_ARG, rose_dec_qsig_DummyRes_RES ++ }, ++ { ++ ROSE_QSIG_MWIInterrogate, NULL, 82, ++ rose_enc_qsig_MWIInterrogate_ARG, rose_enc_qsig_MWIInterrogate_RES, ++ rose_dec_qsig_MWIInterrogate_ARG, rose_dec_qsig_MWIInterrogate_RES ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++/*! \brief Q.SIG specific error-value converion table */ ++static const struct rose_convert_error rose_qsig_errors[] = { ++/* *INDENT-OFF* */ ++/* ++ * error-code, oid_prefix, value ++ * encode_error_args, decode_error_args ++ */ ++ /* ++ * localValue Errors from General-Error-List ++ * {ccitt identified-organization q 950 general-error-list(1)} ++ */ ++ { ++ ROSE_ERROR_Gen_NotSubscribed, NULL, 0, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_RejectedByNetwork, NULL, 1, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_RejectedByUser, NULL, 2, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_NotAvailable, NULL, 3, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_InsufficientInformation, NULL, 5, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_InvalidServedUserNr, NULL, 6, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_InvalidCallState, NULL, 7, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_BasicServiceNotProvided, NULL, 8, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_NotIncomingCall, NULL, 9, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed,NULL, 10, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_ResourceUnavailable, NULL, 11, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_CallFailure, NULL, 25, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_ProceduralError, NULL, 43, ++ NULL, NULL ++ }, ++ ++ /* ++ * From various Q.SIG specifications. ++ * We will ignore the manufacturer specific extension information. ++ */ ++ { ++ ROSE_ERROR_QSIG_Unspecified, NULL, 1008, ++ NULL, NULL ++ }, ++ ++ /* ++ * localValue Errors from Q.SIG SS-AOC-Operations ++ * { iso(1) standard(0) pss1-advice-of-charge(15050) advice-of-charge-operations(0) } ++ */ ++ { ++ ROSE_ERROR_QSIG_AOC_FreeOfCharge, NULL, 1016, ++ NULL, NULL ++ }, ++ ++ /* ++ * localValue's from Q.SIG Call-Transfer-Operations ++ * { iso(1) standard(0) pss1-call-transfer(13869) call-transfer-operations(0) } ++ */ ++ { ++ ROSE_ERROR_QSIG_CT_InvalidReroutingNumber, NULL, 1004, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_QSIG_CT_UnrecognizedCallIdentity,NULL, 1005, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_QSIG_CT_EstablishmentFailure, NULL, 1006, ++ NULL, NULL ++ }, ++ ++ /* ++ * localValue's from Q.SIG Call-Diversion-Operations ++ * { iso(1) standard(0) pss1-call-diversion(13873) call-diversion-operations(0) } ++ */ ++ { ++ ROSE_ERROR_Div_InvalidDivertedToNr, NULL, 12, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Div_SpecialServiceNr, NULL, 14, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Div_DiversionToServedUserNr, NULL, 15, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Div_NumberOfDiversionsExceeded, NULL, 24, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_QSIG_Div_TemporarilyUnavailable, NULL, 1000, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_QSIG_Div_NotAuthorized, NULL, 1007, ++ NULL, NULL ++ }, ++ ++ /* ++ * localValue's from Q.SIG SS-MWI-Operations ++ * { iso(1) standard(0) pss1-message-waiting-indication(15506) message-waiting-operations(0) } ++ */ ++ { ++ ROSE_ERROR_QSIG_InvalidMsgCentreId, NULL, 1018, ++ NULL, NULL ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/*! \brief DMS-100 specific invoke/result encode/decode message table */ ++static const struct rose_convert_msg rose_dms100_msgs[] = { ++/* *INDENT-OFF* */ ++/* ++ * operation, oid_prefix, value, ++ * encode_invoke_args, encode_result_args, ++ * decode_invoke_args, decode_result_args ++ */ ++ { ++ ROSE_DMS100_RLT_OperationInd, NULL, ROSE_DMS100_RLT_OPERATION_IND, ++ NULL, rose_enc_dms100_RLT_OperationInd_RES, ++ NULL, rose_dec_dms100_RLT_OperationInd_RES ++ }, ++ { ++ ROSE_DMS100_RLT_ThirdParty, NULL, ROSE_DMS100_RLT_THIRD_PARTY, ++ rose_enc_dms100_RLT_ThirdParty_ARG, NULL, ++ rose_dec_dms100_RLT_ThirdParty_ARG, NULL ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++/*! \brief DMS-100 specific error-value converion table */ ++static const struct rose_convert_error rose_dms100_errors[] = { ++/* *INDENT-OFF* */ ++/* ++ * error-code, oid_prefix, value ++ * encode_error_args, decode_error_args ++ */ ++ { ++ ROSE_ERROR_DMS100_RLT_BridgeFail, NULL, 0x10, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_DMS100_RLT_CallIDNotFound, NULL, 0x11, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_DMS100_RLT_NotAllowed, NULL, 0x12, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_DMS100_RLT_SwitchEquipCongs, NULL, 0x13, ++ NULL, NULL ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * Note the first value in oid.values[] is really the first two ++ * OID subidentifiers. They are compressed using this formula: ++ * First_Value = (First_Subidentifier * 40) + Second_Subidentifier ++ */ ++ ++static const struct asn1_oid rose_ni2_oid = { ++/* *INDENT-OFF* */ ++ /* { iso(1) member-body(2) usa(840) ansi-t1(10005) operations(0) } */ ++ 4, { 42, 840, 10005, 0 } ++/* *INDENT-ON* */ ++}; ++ ++/*! \brief NI2 specific invoke/result encode/decode message table */ ++static const struct rose_convert_msg rose_ni2_msgs[] = { ++/* *INDENT-OFF* */ ++/* ++ * operation, oid_prefix, value, ++ * encode_invoke_args, encode_result_args, ++ * decode_invoke_args, decode_result_args ++ */ ++ /* NI2 seems to have pirated several Q.SIG messages */ ++ /* ++ * localValue's from Q.SIG Name-Operations ++ * { iso(1) standard(0) pss1-name(13868) name-operations(0) } ++ */ ++ { ++ ROSE_QSIG_CallingName, NULL, 0, ++ rose_enc_qsig_CallingName_ARG, NULL, ++ rose_dec_qsig_CallingName_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_CalledName, NULL, 1, ++ rose_enc_qsig_CalledName_ARG, NULL, ++ rose_dec_qsig_CalledName_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_ConnectedName, NULL, 2, ++ rose_enc_qsig_ConnectedName_ARG, NULL, ++ rose_dec_qsig_ConnectedName_ARG, NULL ++ }, ++ { ++ ROSE_QSIG_BusyName, NULL, 3, ++ rose_enc_qsig_BusyName_ARG, NULL, ++ rose_dec_qsig_BusyName_ARG, NULL ++ }, ++ ++ { ++ ROSE_NI2_InformationFollowing, &rose_ni2_oid, 4, ++ rose_enc_ni2_InformationFollowing_ARG, NULL, ++ rose_dec_ni2_InformationFollowing_ARG, NULL ++ }, ++ ++ /* Also used by PRI_SWITCH_ATT4ESS and PRI_SWITCH_LUCENT5E */ ++ { ++ ROSE_NI2_InitiateTransfer, &rose_ni2_oid, 8, ++ rose_enc_ni2_InitiateTransfer_ARG, NULL, ++ rose_dec_ni2_InitiateTransfer_ARG, NULL ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++/*! \brief NI2 specific error-value converion table */ ++static const struct rose_convert_error rose_ni2_errors[] = { ++/* *INDENT-OFF* */ ++/* ++ * error-code, oid_prefix, value ++ * encode_error_args, decode_error_args ++ */ ++ /* ++ * localValue Errors from General-Error-List ++ * {ccitt identified-organization q 950 general-error-list(1)} ++ */ ++ { ++ ROSE_ERROR_Gen_NotSubscribed, NULL, 0, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_RejectedByNetwork, NULL, 1, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_RejectedByUser, NULL, 2, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_NotAvailable, NULL, 3, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_InsufficientInformation, NULL, 5, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_InvalidServedUserNr, NULL, 6, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_InvalidCallState, NULL, 7, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_BasicServiceNotProvided, NULL, 8, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_NotIncomingCall, NULL, 9, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed,NULL, 10, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_ResourceUnavailable, NULL, 11, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_CallFailure, NULL, 25, ++ NULL, NULL ++ }, ++ { ++ ROSE_ERROR_Gen_ProceduralError, NULL, 43, ++ NULL, NULL ++ }, ++/* *INDENT-ON* */ ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++/*! ++ * \internal ++ * \brief Convert the given code value to a string. ++ * ++ * \param code Code value to convert to a string. ++ * \param arr Array to convert the code to a string. ++ * \param num_elements Number of elements in the conversion array. ++ * ++ * \retval String version of the given code value. ++ */ ++static const char *rose_code2str(int code, const struct rose_code_strings *arr, ++ unsigned num_elements) ++{ ++ static char invalid_code[40]; ++ ++ unsigned index; ++ ++ for (index = 0; index < num_elements; ++index) { ++ if (arr[index].code == code) { ++ return arr[index].name; ++ } ++ } ++ ++ snprintf(invalid_code, sizeof(invalid_code), "Invalid code:%d 0x%X", code, code); ++ return invalid_code; ++} ++ ++/*! ++ * \brief Convert the given operation-value to a string. ++ * ++ * \param operation Operation-value to convert to a string. ++ * ++ * \retval String version of the given operation-value. ++ */ ++const char *rose_operation2str(enum rose_operation operation) ++{ ++ static const struct rose_code_strings arr[] = { ++/* *INDENT-OFF* */ ++ { ROSE_None, "ROSE_None" }, ++ { ROSE_Unknown, "ROSE_Unknown" }, ++ ++ { ROSE_ETSI_ActivationDiversion, "ROSE_ETSI_ActivationDiversion" }, ++ { ROSE_ETSI_DeactivationDiversion, "ROSE_ETSI_DeactivationDiversion" }, ++ { ROSE_ETSI_ActivationStatusNotificationDiv,"ROSE_ETSI_ActivationStatusNotificationDiv" }, ++ { ROSE_ETSI_DeactivationStatusNotificationDiv,"ROSE_ETSI_DeactivationStatusNotificationDiv" }, ++ { ROSE_ETSI_InterrogationDiversion, "ROSE_ETSI_InterrogationDiversion" }, ++ { ROSE_ETSI_DiversionInformation, "ROSE_ETSI_DiversionInformation" }, ++ { ROSE_ETSI_CallDeflection, "ROSE_ETSI_CallDeflection" }, ++ { ROSE_ETSI_CallRerouting, "ROSE_ETSI_CallRerouting" }, ++ { ROSE_ETSI_DivertingLegInformation2, "ROSE_ETSI_DivertingLegInformation2" }, ++ { ROSE_ETSI_InterrogateServedUserNumbers, "ROSE_ETSI_InterrogateServedUserNumbers" }, ++ { ROSE_ETSI_DivertingLegInformation1, "ROSE_ETSI_DivertingLegInformation1" }, ++ { ROSE_ETSI_DivertingLegInformation3, "ROSE_ETSI_DivertingLegInformation3" }, ++ ++ { ROSE_ETSI_EctExecute, "ROSE_ETSI_EctExecute" }, ++ { ROSE_ETSI_ExplicitEctExecute, "ROSE_ETSI_ExplicitEctExecute" }, ++ { ROSE_ETSI_RequestSubaddress, "ROSE_ETSI_RequestSubaddress" }, ++ { ROSE_ETSI_SubaddressTransfer, "ROSE_ETSI_SubaddressTransfer" }, ++ { ROSE_ETSI_EctLinkIdRequest, "ROSE_ETSI_EctLinkIdRequest" }, ++ { ROSE_ETSI_EctInform, "ROSE_ETSI_EctInform" }, ++ { ROSE_ETSI_EctLoopTest, "ROSE_ETSI_EctLoopTest" }, ++ ++ { ROSE_ETSI_ChargingRequest, "ROSE_ETSI_ChargingRequest" }, ++ { ROSE_ETSI_AOCSCurrency, "ROSE_ETSI_AOCSCurrency" }, ++ { ROSE_ETSI_AOCSSpecialArr, "ROSE_ETSI_AOCSSpecialArr" }, ++ { ROSE_ETSI_AOCDCurrency, "ROSE_ETSI_AOCDCurrency" }, ++ { ROSE_ETSI_AOCDChargingUnit, "ROSE_ETSI_AOCDChargingUnit" }, ++ { ROSE_ETSI_AOCECurrency, "ROSE_ETSI_AOCECurrency" }, ++ { ROSE_ETSI_AOCEChargingUnit, "ROSE_ETSI_AOCEChargingUnit" }, ++ ++ { ROSE_QSIG_CallingName, "ROSE_QSIG_CallingName" }, ++ { ROSE_QSIG_CalledName, "ROSE_QSIG_CalledName" }, ++ { ROSE_QSIG_ConnectedName, "ROSE_QSIG_ConnectedName" }, ++ { ROSE_QSIG_BusyName, "ROSE_QSIG_BusyName" }, ++ ++ { ROSE_QSIG_ChargeRequest, "ROSE_QSIG_ChargeRequest" }, ++ { ROSE_QSIG_GetFinalCharge, "ROSE_QSIG_GetFinalCharge" }, ++ { ROSE_QSIG_AocFinal, "ROSE_QSIG_AocFinal" }, ++ { ROSE_QSIG_AocInterim, "ROSE_QSIG_AocInterim" }, ++ { ROSE_QSIG_AocRate, "ROSE_QSIG_AocRate" }, ++ { ROSE_QSIG_AocComplete, "ROSE_QSIG_AocComplete" }, ++ { ROSE_QSIG_AocDivChargeReq, "ROSE_QSIG_AocDivChargeReq" }, ++ ++ { ROSE_QSIG_CallTransferIdentify, "ROSE_QSIG_CallTransferIdentify" }, ++ { ROSE_QSIG_CallTransferAbandon, "ROSE_QSIG_CallTransferAbandon" }, ++ { ROSE_QSIG_CallTransferInitiate, "ROSE_QSIG_CallTransferInitiate" }, ++ { ROSE_QSIG_CallTransferSetup, "ROSE_QSIG_CallTransferSetup" }, ++ { ROSE_QSIG_CallTransferActive, "ROSE_QSIG_CallTransferActive" }, ++ { ROSE_QSIG_CallTransferComplete, "ROSE_QSIG_CallTransferComplete" }, ++ { ROSE_QSIG_CallTransferUpdate, "ROSE_QSIG_CallTransferUpdate" }, ++ { ROSE_QSIG_SubaddressTransfer, "ROSE_QSIG_SubaddressTransfer" }, ++ ++ { ROSE_QSIG_PathReplacement, "ROSE_QSIG_PathReplacement" }, ++ ++ { ROSE_QSIG_ActivateDiversionQ, "ROSE_QSIG_ActivateDiversionQ" }, ++ { ROSE_QSIG_DeactivateDiversionQ, "ROSE_QSIG_DeactivateDiversionQ" }, ++ { ROSE_QSIG_InterrogateDiversionQ, "ROSE_QSIG_InterrogateDiversionQ" }, ++ { ROSE_QSIG_CheckRestriction, "ROSE_QSIG_CheckRestriction" }, ++ { ROSE_QSIG_CallRerouting, "ROSE_QSIG_CallRerouting" }, ++ { ROSE_QSIG_DivertingLegInformation1, "ROSE_QSIG_DivertingLegInformation1" }, ++ { ROSE_QSIG_DivertingLegInformation2, "ROSE_QSIG_DivertingLegInformation2" }, ++ { ROSE_QSIG_DivertingLegInformation3, "ROSE_QSIG_DivertingLegInformation3" }, ++ { ROSE_QSIG_CfnrDivertedLegFailed, "ROSE_QSIG_CfnrDivertedLegFailed" }, ++ ++ { ROSE_QSIG_MWIActivate, "ROSE_QSIG_MWIActivate" }, ++ { ROSE_QSIG_MWIDeactivate, "ROSE_QSIG_MWIDeactivate" }, ++ { ROSE_QSIG_MWIInterrogate, "ROSE_QSIG_MWIInterrogate" }, ++ ++ { ROSE_DMS100_RLT_OperationInd, "ROSE_DMS100_RLT_OperationInd" }, ++ { ROSE_DMS100_RLT_ThirdParty, "ROSE_DMS100_RLT_ThirdParty" }, ++ ++ { ROSE_NI2_InformationFollowing, "ROSE_NI2_InformationFollowing" }, ++ { ROSE_NI2_InitiateTransfer, "ROSE_NI2_InitiateTransfer" }, ++/* *INDENT-ON* */ ++ }; ++ ++ return rose_code2str(operation, arr, ARRAY_LEN(arr)); ++} ++ ++/*! ++ * \brief Convert the given error-value to a string. ++ * ++ * \param code Error-value to convert to a string. ++ * ++ * \retval String version of the given error-value. ++ */ ++const char *rose_error2str(enum rose_error_code code) ++{ ++ static const struct rose_code_strings arr[] = { ++/* *INDENT-OFF* */ ++ { ROSE_ERROR_None, "No error occurred" }, ++ { ROSE_ERROR_Unknown, "Unknown error-value code" }, ++ ++ { ROSE_ERROR_Gen_NotSubscribed, "General: Not Subscribed" }, ++ { ROSE_ERROR_Gen_NotAvailable, "General: Not Available" }, ++ { ROSE_ERROR_Gen_NotImplemented, "General: Not Implemented" }, ++ { ROSE_ERROR_Gen_InvalidServedUserNr, "General: Invalid Served User Number" }, ++ { ROSE_ERROR_Gen_InvalidCallState, "General: Invalid Call State" }, ++ { ROSE_ERROR_Gen_BasicServiceNotProvided, "General: Basic Service Not Provided" }, ++ { ROSE_ERROR_Gen_NotIncomingCall, "General: Not Incoming Call" }, ++ { ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed,"General: Supplementary Service Interaction Not Allowed" }, ++ { ROSE_ERROR_Gen_ResourceUnavailable, "General: Resource Unavailable" }, ++ ++ /* Additional Q.950 General-Errors for Q.SIG */ ++ { ROSE_ERROR_Gen_RejectedByNetwork, "General: Rejected By Network" }, ++ { ROSE_ERROR_Gen_RejectedByUser, "General: Rejected By User" }, ++ { ROSE_ERROR_Gen_InsufficientInformation, "General: Insufficient Information" }, ++ { ROSE_ERROR_Gen_CallFailure, "General: Call Failure" }, ++ { ROSE_ERROR_Gen_ProceduralError, "General: Procedural Error" }, ++ ++ { ROSE_ERROR_Div_InvalidDivertedToNr, "Diversion: Invalid Diverted To Number" }, ++ { ROSE_ERROR_Div_SpecialServiceNr, "Diversion: Special Service Number" }, ++ { ROSE_ERROR_Div_DiversionToServedUserNr, "Diversion: Diversion To Served User Number" }, ++ { ROSE_ERROR_Div_IncomingCallAccepted, "Diversion: Incoming Call Accepted" }, ++ { ROSE_ERROR_Div_NumberOfDiversionsExceeded, "Diversion: Number Of Diversions Exceeded" }, ++ { ROSE_ERROR_Div_NotActivated, "Diversion: Not Activated" }, ++ { ROSE_ERROR_Div_RequestAlreadyAccepted, "Diversion: Request Already Accepted" }, ++ ++ { ROSE_ERROR_AOC_NoChargingInfoAvailable, "AOC: No Charging Info Available" }, ++ ++ { ROSE_ERROR_ECT_LinkIdNotAssignedByNetwork, "ECT: Link ID Not Assigned By Network" }, ++ ++ /* Q.SIG specific errors */ ++ { ROSE_ERROR_QSIG_Unspecified, "Unspecified" }, ++ ++ { ROSE_ERROR_QSIG_AOC_FreeOfCharge, "AOC: FreeOfCharge" }, ++ ++ { ROSE_ERROR_QSIG_CT_InvalidReroutingNumber, "CT: Invalid Rerouting Number" }, ++ { ROSE_ERROR_QSIG_CT_UnrecognizedCallIdentity,"CT: Unrecognized Call Identity" }, ++ { ROSE_ERROR_QSIG_CT_EstablishmentFailure, "CT: Establishment Failure" }, ++ ++ { ROSE_ERROR_QSIG_Div_TemporarilyUnavailable, "Diversion: Temporarily Unavailable" }, ++ { ROSE_ERROR_QSIG_Div_NotAuthorized, "Diversion: Not Authorized" }, ++ ++ { ROSE_ERROR_QSIG_InvalidMsgCentreId, "MWI: Invalid Message Center ID" }, ++ ++ /* DMS-100 specific errors */ ++ { ROSE_ERROR_DMS100_RLT_BridgeFail, "RLT: Bridge Fail" }, ++ { ROSE_ERROR_DMS100_RLT_CallIDNotFound, "RLT: Call ID Not Found" }, ++ { ROSE_ERROR_DMS100_RLT_NotAllowed, "RLT: Not Allowed" }, ++ { ROSE_ERROR_DMS100_RLT_SwitchEquipCongs, "RLT: Switch Equip Congs" }, ++/* *INDENT-ON* */ ++ }; ++ ++ return rose_code2str(code, arr, ARRAY_LEN(arr)); ++} ++ ++/*! ++ * \brief Convert the given reject problem-value to a string. ++ * ++ * \param code Reject problem-value to convert to a string. ++ * ++ * \retval String version of the given reject problem-value. ++ */ ++const char *rose_reject2str(enum rose_reject_code code) ++{ ++ static const struct rose_code_strings arr[] = { ++/* *INDENT-OFF* */ ++ { ROSE_REJECT_None, "No reject occurred" }, ++ { ROSE_REJECT_Unknown, "Unknown reject code" }, ++ ++ { ROSE_REJECT_Gen_UnrecognizedComponent, "General: Unrecognized Component" }, ++ { ROSE_REJECT_Gen_MistypedComponent, "General: Mistyped Component" }, ++ { ROSE_REJECT_Gen_BadlyStructuredComponent, "General: Badly Structured Component" }, ++ ++ { ROSE_REJECT_Inv_DuplicateInvocation, "Invoke: Duplicate Invocation" }, ++ { ROSE_REJECT_Inv_UnrecognizedOperation, "Invoke: Unrecognized Operation" }, ++ { ROSE_REJECT_Inv_MistypedArgument, "Invoke: Mistyped Argument" }, ++ { ROSE_REJECT_Inv_ResourceLimitation, "Invoke: Resource Limitation" }, ++ { ROSE_REJECT_Inv_InitiatorReleasing, "Invoke: Initiator Releasing" }, ++ { ROSE_REJECT_Inv_UnrecognizedLinkedID, "Invoke: Unrecognized Linked ID" }, ++ { ROSE_REJECT_Inv_LinkedResponseUnexpected, "Invoke: Linked Response Unexpected" }, ++ { ROSE_REJECT_Inv_UnexpectedChildOperation, "Invoke: Unexpected Child Operation" }, ++ ++ { ROSE_REJECT_Res_UnrecognizedInvocation, "Result: Unrecognized Invocation" }, ++ { ROSE_REJECT_Res_ResultResponseUnexpected, "Result: Result Response Unexpected" }, ++ { ROSE_REJECT_Res_MistypedResult, "Result: Mistyped Result" }, ++ ++ { ROSE_REJECT_Err_UnrecognizedInvocation, "Error: Unrecognized Invocation" }, ++ { ROSE_REJECT_Err_ErrorResponseUnexpected, "Error: Error Response Unexpected" }, ++ { ROSE_REJECT_Err_UnrecognizedError, "Error: Unrecognized Error" }, ++ { ROSE_REJECT_Err_UnexpectedError, "Error: Unexpected Error" }, ++ { ROSE_REJECT_Err_MistypedParameter, "Error: Mistyped Parameter" }, ++/* *INDENT-ON* */ ++ }; ++ ++ return rose_code2str(code, arr, ARRAY_LEN(arr)); ++} ++ ++/*! ++ * \internal ++ * \brief Find an operation message conversion entry using the operation code. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param operation Library operation-value code. ++ * ++ * \retval Message conversion entry on success. ++ * \retval NULL on error. ++ */ ++static const struct rose_convert_msg *rose_find_msg_by_op_code(struct pri *ctrl, ++ enum rose_operation operation) ++{ ++ const struct rose_convert_msg *found; ++ const struct rose_convert_msg *table; ++ size_t num_entries; ++ size_t index; ++ ++ /* Determine which message conversion table to use */ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_T1: ++ case PRI_SWITCH_EUROISDN_E1: ++ table = rose_etsi_msgs; ++ num_entries = ARRAY_LEN(rose_etsi_msgs); ++ break; ++ case PRI_SWITCH_QSIG: ++ table = rose_qsig_msgs; ++ num_entries = ARRAY_LEN(rose_qsig_msgs); ++ break; ++ case PRI_SWITCH_DMS100: ++ table = rose_dms100_msgs; ++ num_entries = ARRAY_LEN(rose_dms100_msgs); ++ break; ++ case PRI_SWITCH_ATT4ESS: ++ case PRI_SWITCH_LUCENT5E: ++ case PRI_SWITCH_NI2: ++ table = rose_ni2_msgs; ++ num_entries = ARRAY_LEN(rose_ni2_msgs); ++ break; ++ default: ++ return NULL; ++ } ++ ++ /* Search for the table entry */ ++ found = NULL; ++ for (index = 0; index < num_entries; ++index) { ++ if (table[index].operation == operation) { ++ found = &table[index]; ++ break; ++ } ++ } ++ ++ return found; ++} ++ ++/*! ++ * \internal ++ * \brief Find an operation message conversion entry using the ++ * operation-value OID value or localValue. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param oid Search for the full OID if not NULL. ++ * \param local Search for the localValue if OID is NULL. ++ * ++ * \retval Message conversion entry on success. ++ * \retval NULL on error. ++ */ ++static const struct rose_convert_msg *rose_find_msg_by_op_val(struct pri *ctrl, ++ const struct asn1_oid *oid, unsigned local) ++{ ++ const struct rose_convert_msg *found; ++ const struct rose_convert_msg *table; ++ size_t num_entries; ++ size_t index; ++ int sub_index; ++ ++ /* Determine which message conversion table to use */ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_T1: ++ case PRI_SWITCH_EUROISDN_E1: ++ table = rose_etsi_msgs; ++ num_entries = ARRAY_LEN(rose_etsi_msgs); ++ break; ++ case PRI_SWITCH_QSIG: ++ table = rose_qsig_msgs; ++ num_entries = ARRAY_LEN(rose_qsig_msgs); ++ break; ++ case PRI_SWITCH_DMS100: ++ table = rose_dms100_msgs; ++ num_entries = ARRAY_LEN(rose_dms100_msgs); ++ break; ++ case PRI_SWITCH_ATT4ESS: ++ case PRI_SWITCH_LUCENT5E: ++ case PRI_SWITCH_NI2: ++ table = rose_ni2_msgs; ++ num_entries = ARRAY_LEN(rose_ni2_msgs); ++ break; ++ default: ++ return NULL; ++ } ++ ++ /* Search for the table entry */ ++ found = NULL; ++ if (oid) { ++ /* Search for an OID entry */ ++ local = oid->value[oid->num_values - 1]; ++ for (index = 0; index < num_entries; ++index) { ++ if (table[index].value == local && table[index].oid_prefix ++ && table[index].oid_prefix->num_values == oid->num_values - 1) { ++ /* Now lets match the OID prefix subidentifiers */ ++ for (sub_index = oid->num_values - 2; 0 <= sub_index; --sub_index) { ++ if (oid->value[sub_index] ++ != table[index].oid_prefix->value[sub_index]) { ++ break; ++ } ++ } ++ if (sub_index == -1) { ++ /* All of the OID subidentifiers matched */ ++ found = &table[index]; ++ break; ++ } ++ } ++ } ++ } else { ++ /* Search for a localValue entry */ ++ for (index = 0; index < num_entries; ++index) { ++ if (table[index].value == local && !table[index].oid_prefix) { ++ found = &table[index]; ++ break; ++ } ++ } ++ } ++ ++ return found; ++} ++ ++/*! ++ * \internal ++ * \brief Find an error conversion entry using the error code. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param code Library error-value code. ++ * ++ * \retval Error conversion entry on success. ++ * \retval NULL on error. ++ */ ++static const struct rose_convert_error *rose_find_error_by_op_code(struct pri *ctrl, ++ enum rose_error_code code) ++{ ++ const struct rose_convert_error *found; ++ const struct rose_convert_error *table; ++ size_t num_entries; ++ size_t index; ++ ++ /* Determine which error conversion table to use */ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_T1: ++ case PRI_SWITCH_EUROISDN_E1: ++ table = rose_etsi_errors; ++ num_entries = ARRAY_LEN(rose_etsi_errors); ++ break; ++ case PRI_SWITCH_QSIG: ++ table = rose_qsig_errors; ++ num_entries = ARRAY_LEN(rose_qsig_errors); ++ break; ++ case PRI_SWITCH_DMS100: ++ table = rose_dms100_errors; ++ num_entries = ARRAY_LEN(rose_dms100_errors); ++ break; ++ case PRI_SWITCH_ATT4ESS: ++ case PRI_SWITCH_LUCENT5E: ++ case PRI_SWITCH_NI2: ++ table = rose_ni2_errors; ++ num_entries = ARRAY_LEN(rose_ni2_errors); ++ break; ++ default: ++ return NULL; ++ } ++ ++ /* Search for the table entry */ ++ found = NULL; ++ for (index = 0; index < num_entries; ++index) { ++ if (table[index].code == code) { ++ found = &table[index]; ++ break; ++ } ++ } ++ ++ return found; ++} ++ ++/*! ++ * \internal ++ * \brief Find an error conversion entry using the ++ * error-value OID value or localValue. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param oid Search for the full OID if not NULL. ++ * \param local Search for the localValue if OID is NULL. ++ * ++ * \retval Error conversion entry on success. ++ * \retval NULL on error. ++ */ ++static const struct rose_convert_error *rose_find_error_by_op_val(struct pri *ctrl, ++ const struct asn1_oid *oid, unsigned local) ++{ ++ const struct rose_convert_error *found; ++ const struct rose_convert_error *table; ++ size_t num_entries; ++ size_t index; ++ int sub_index; ++ ++ /* Determine which error conversion table to use */ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_T1: ++ case PRI_SWITCH_EUROISDN_E1: ++ table = rose_etsi_errors; ++ num_entries = ARRAY_LEN(rose_etsi_errors); ++ break; ++ case PRI_SWITCH_QSIG: ++ table = rose_qsig_errors; ++ num_entries = ARRAY_LEN(rose_qsig_errors); ++ break; ++ case PRI_SWITCH_DMS100: ++ table = rose_dms100_errors; ++ num_entries = ARRAY_LEN(rose_dms100_errors); ++ break; ++ case PRI_SWITCH_ATT4ESS: ++ case PRI_SWITCH_LUCENT5E: ++ case PRI_SWITCH_NI2: ++ table = rose_ni2_errors; ++ num_entries = ARRAY_LEN(rose_ni2_errors); ++ break; ++ default: ++ return NULL; ++ } ++ ++ /* Search for the table entry */ ++ found = NULL; ++ if (oid) { ++ /* Search for an OID entry */ ++ local = oid->value[oid->num_values - 1]; ++ for (index = 0; index < num_entries; ++index) { ++ if (table[index].value == local && table[index].oid_prefix ++ && table[index].oid_prefix->num_values == oid->num_values - 1) { ++ /* Now lets match the OID prefix subidentifiers */ ++ for (sub_index = oid->num_values - 2; 0 <= sub_index; --sub_index) { ++ if (oid->value[sub_index] ++ != table[index].oid_prefix->value[sub_index]) { ++ break; ++ } ++ } ++ if (sub_index == -1) { ++ /* All of the OID subidentifiers matched */ ++ found = &table[index]; ++ break; ++ } ++ } ++ } ++ } else { ++ /* Search for a localValue entry */ ++ for (index = 0; index < num_entries; ++index) { ++ if (table[index].value == local && !table[index].oid_prefix) { ++ found = &table[index]; ++ break; ++ } ++ } ++ } ++ ++ return found; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the Facility ie component operation-value. ++ * ++ * \param pos Starting position to encode the operation-value. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param oid_prefix Encode as an OID if not NULL. ++ * \param local Encode as a localValue if oid_prefix is NULL ++ * else it is the last OID subidentifier. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_operation_value(unsigned char *pos, unsigned char *end, ++ const struct asn1_oid *oid_prefix, unsigned local) ++{ ++ struct asn1_oid oid; ++ ++ if (oid_prefix) { ++ if (ARRAY_LEN(oid_prefix->value) <= oid_prefix->num_values) { ++ return NULL; ++ } ++ oid = *oid_prefix; ++ oid.value[oid.num_values++] = local; ++ return asn1_enc_oid(pos, end, ASN1_TYPE_OBJECT_IDENTIFIER, &oid); ++ } else { ++ return asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, local); ++ } ++} ++ ++/*! \brief Mapped to rose_enc_operation_value() */ ++#define rose_enc_error_value(pos, end, oid_prefix, local) \ ++ rose_enc_operation_value(pos, end, oid_prefix, local) ++ ++/*! ++ * \brief Encode the invoke component for a ROSE message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 message. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param msg ROSE invoke message to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_encode_invoke(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rose_msg_invoke *msg) ++{ ++ const struct rose_convert_msg *convert; ++ unsigned char *seq_len; ++ ++ convert = rose_find_msg_by_op_code(ctrl, msg->operation); ++ if (!convert) { ++ return NULL; ++ } ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ROSE_TAG_COMPONENT_INVOKE); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, msg->invoke_id)); ++ if (msg->linked_id_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0, ++ msg->linked_id)); ++ } ++ ASN1_CALL(pos, rose_enc_operation_value(pos, end, convert->oid_prefix, ++ convert->value)); ++ ++ if (convert->encode_invoke_args) { ++ ASN1_CALL(pos, convert->encode_invoke_args(ctrl, pos, end, &msg->args)); ++ } ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the result component for a ROSE message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 message. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param msg ROSE result message to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_encode_result(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rose_msg_result *msg) ++{ ++ const struct rose_convert_msg *convert; ++ unsigned char *seq_len; ++ unsigned char *op_seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ROSE_TAG_COMPONENT_RESULT); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, msg->invoke_id)); ++ ++ if (msg->operation != ROSE_None) { ++ convert = rose_find_msg_by_op_code(ctrl, msg->operation); ++ if (!convert) { ++ return NULL; ++ } ++ ++ ASN1_CONSTRUCTED_BEGIN(op_seq_len, pos, end, ASN1_TYPE_SEQUENCE); ++ ++ ASN1_CALL(pos, rose_enc_operation_value(pos, end, convert->oid_prefix, ++ convert->value)); ++ ++ if (convert->encode_result_args) { ++ ASN1_CALL(pos, convert->encode_result_args(ctrl, pos, end, &msg->args)); ++ } ++ ++ ASN1_CONSTRUCTED_END(op_seq_len, pos, end); ++ } ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the error component for a ROSE message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 message. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param msg ROSE error message to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_encode_error(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rose_msg_error *msg) ++{ ++ const struct rose_convert_error *convert; ++ unsigned char *seq_len; ++ ++ convert = rose_find_error_by_op_code(ctrl, msg->code); ++ if (!convert) { ++ return NULL; ++ } ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ROSE_TAG_COMPONENT_ERROR); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, msg->invoke_id)); ++ ASN1_CALL(pos, rose_enc_error_value(pos, end, convert->oid_prefix, convert->value)); ++ if (convert->encode_error_args) { ++ ASN1_CALL(pos, convert->encode_error_args(ctrl, pos, end, &msg->args)); ++ } ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the reject component for a ROSE message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 message. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param msg ROSE reject message to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_encode_reject(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rose_msg_reject *msg) ++{ ++ unsigned char *seq_len; ++ unsigned tag; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ROSE_TAG_COMPONENT_REJECT); ++ ++ /* Encode Invoke ID */ ++ if (msg->invoke_id_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, msg->invoke_id)); ++ } else { ++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_TYPE_NULL)); ++ } ++ ++ /* Encode the reject problem */ ++ switch (msg->code & ~0xFF) { ++ case ROSE_REJECT_BASE(ROSE_REJECT_BASE_General): ++ tag = ASN1_CLASS_CONTEXT_SPECIFIC | 0; ++ break; ++ case ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke): ++ tag = ASN1_CLASS_CONTEXT_SPECIFIC | 1; ++ break; ++ case ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result): ++ tag = ASN1_CLASS_CONTEXT_SPECIFIC | 2; ++ break; ++ case ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error): ++ tag = ASN1_CLASS_CONTEXT_SPECIFIC | 3; ++ break; ++ default: ++ return NULL; ++ } ++ ASN1_CALL(pos, asn1_enc_int(pos, end, tag, msg->code & 0xFF)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the ROSE message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 message. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param msg ROSE message to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ * ++ * \note This function only encodes the ROSE contents. It does not include ++ * the protocol profile, NFE, NPP, and interpretation octets defined in ++ * a facility ie that may precede the ROSE contents. These header octets ++ * may already be stored in the encompassing buffer before the starting ++ * position given here. ++ */ ++unsigned char *rose_encode(struct pri *ctrl, unsigned char *pos, unsigned char *end, ++ const struct rose_message *msg) ++{ ++ switch (msg->type) { ++ case ROSE_COMP_TYPE_INVOKE: ++ pos = rose_encode_invoke(ctrl, pos, end, &msg->component.invoke); ++ break; ++ case ROSE_COMP_TYPE_RESULT: ++ pos = rose_encode_result(ctrl, pos, end, &msg->component.result); ++ break; ++ case ROSE_COMP_TYPE_ERROR: ++ pos = rose_encode_error(ctrl, pos, end, &msg->component.error); ++ break; ++ case ROSE_COMP_TYPE_REJECT: ++ pos = rose_encode_reject(ctrl, pos, end, &msg->component.reject); ++ break; ++ default: ++ pos = NULL; ++ break; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the NetworkFacilityExtension type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param nfe Network Facility Extension information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *fac_enc_nfe(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct facNetworkFacilityExtension *nfe) ++{ ++ unsigned char *seq_len; ++ unsigned char *explicit_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 10); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0, ++ nfe->source_entity)); ++ if (nfe->source_number.length) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &nfe->source_number)); ++ ASN1_CONSTRUCTED_END(explicit_len, pos, end); ++ } ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, ++ nfe->destination_entity)); ++ if (nfe->destination_number.length) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(explicit_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &nfe->destination_number)); ++ ASN1_CONSTRUCTED_END(explicit_len, pos, end); ++ } ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the facility extension header. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param header Facility extension information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *fac_enc_extension_header(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct fac_extension_header *header) ++{ ++ if (header->nfe_present) { ++ ASN1_CALL(pos, fac_enc_nfe(ctrl, pos, end, &header->nfe)); ++ } ++ if (header->npp_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 18, ++ header->npp)); ++ } ++ if (header->interpretation_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 11, ++ header->interpretation)); ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the facility ie contents header. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode the facility ie contents. ++ * \param end End of facility ie contents encoding data buffer. ++ * \param header Facility extension header data to encode (NULL if none). ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *facility_encode_header(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct fac_extension_header *header) ++{ ++ /* Make sure we have some room. */ ++ if (end < pos + 2) { ++ return NULL; ++ } ++ ++ switch (ctrl->switchtype) { ++ case PRI_SWITCH_EUROISDN_T1: ++ case PRI_SWITCH_EUROISDN_E1: ++ *pos++ = 0x80 | Q932_PROTOCOL_ROSE; ++ header = NULL; ++ break; ++ case PRI_SWITCH_QSIG: ++ *pos++ = 0x80 | Q932_PROTOCOL_EXTENSIONS; ++ break; ++ case PRI_SWITCH_DMS100: ++ *pos++ = Q932_PROTOCOL_ROSE; /* DON'T set the EXT bit yet. */ ++ *pos++ = 0x80 | ROSE_DMS100_RLT_SERVICE_ID; ++ header = NULL; ++ break; ++ case PRI_SWITCH_ATT4ESS: ++ case PRI_SWITCH_LUCENT5E: ++ case PRI_SWITCH_NI2: ++ if (header) { ++ *pos++ = 0x80 | Q932_PROTOCOL_EXTENSIONS; ++ } else { ++ *pos++ = 0x80 | Q932_PROTOCOL_ROSE; ++ } ++ break; ++ default: ++ return NULL; ++ } ++ ++ if (header) { ++ ASN1_CALL(pos, fac_enc_extension_header(ctrl, pos, end, header)); ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the ROSE invoke message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param msg ROSE invoke message data to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_decode_invoke(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, struct rose_msg_invoke *msg) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ const struct rose_convert_msg *convert; ++ struct asn1_oid oid; ++ unsigned local; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "INVOKE Component %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "invokeId", tag, pos, seq_end, &value)); ++ msg->invoke_id = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | 0)) { ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "linkedId", tag, pos, seq_end, &value)); ++ msg->linked_id = value; ++ msg->linked_id_present = 1; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ } else { ++ msg->linked_id_present = 0; ++ } ++ ++ /* Decode operation-value */ ++ switch (tag) { ++ case ASN1_TYPE_INTEGER: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "operationValue", tag, pos, seq_end, &value)); ++ local = value; ++ oid.num_values = 0; ++ break; ++ case ASN1_TYPE_OBJECT_IDENTIFIER: ++ ASN1_CALL(pos, asn1_dec_oid(ctrl, "operationValue", tag, pos, seq_end, &oid)); ++ local = 0; ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ convert = rose_find_msg_by_op_val(ctrl, (oid.num_values == 0) ? NULL : &oid, local); ++ if (convert) { ++ msg->operation = convert->operation; ++ } else { ++ msg->operation = ROSE_Unknown; ++ } ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " operationValue = %s\n", rose_operation2str(msg->operation)); ++ } ++ ++ /* Decode any expected invoke arguments */ ++ if (convert && convert->decode_invoke_args) { ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, convert->decode_invoke_args(ctrl, tag, pos, seq_end, &msg->args)); ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the ROSE result message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param msg ROSE result message data to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_decode_result(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, struct rose_msg_result *msg) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ int op_seq_offset; ++ const unsigned char *seq_end; ++ const unsigned char *op_seq_end; ++ const struct rose_convert_msg *convert; ++ struct asn1_oid oid; ++ unsigned local; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "RESULT Component %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "invokeId", tag, pos, seq_end, &value)); ++ msg->invoke_id = value; ++ ++ /* Decode optional operation sequence */ ++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " operation %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(op_seq_end, op_seq_offset, length, pos, seq_end); ++ ++ /* Decode operation-value */ ++ ASN1_CALL(pos, asn1_dec_tag(pos, op_seq_end, &tag)); ++ switch (tag) { ++ case ASN1_TYPE_INTEGER: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "operationValue", tag, pos, op_seq_end, ++ &value)); ++ local = value; ++ oid.num_values = 0; ++ break; ++ case ASN1_TYPE_OBJECT_IDENTIFIER: ++ ASN1_CALL(pos, asn1_dec_oid(ctrl, "operationValue", tag, pos, op_seq_end, ++ &oid)); ++ local = 0; ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ convert = ++ rose_find_msg_by_op_val(ctrl, (oid.num_values == 0) ? NULL : &oid, local); ++ if (convert) { ++ msg->operation = convert->operation; ++ } else { ++ msg->operation = ROSE_Unknown; ++ } ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " operationValue = %s\n", ++ rose_operation2str(msg->operation)); ++ } ++ ++ /* Decode any expected result arguments */ ++ if (convert && convert->decode_result_args) { ++ ASN1_CALL(pos, asn1_dec_tag(pos, op_seq_end, &tag)); ++ ASN1_CALL(pos, convert->decode_result_args(ctrl, tag, pos, op_seq_end, ++ &msg->args)); ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, op_seq_offset, op_seq_end, seq_end); ++ } else { ++ msg->operation = ROSE_None; ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the ROSE error message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param msg ROSE error message data to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_decode_error(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, struct rose_msg_error *msg) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ const struct rose_convert_error *convert; ++ struct asn1_oid oid; ++ unsigned local; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "ERROR Component %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "invokeId", tag, pos, seq_end, &value)); ++ msg->invoke_id = value; ++ ++ /* Decode error-value */ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag) { ++ case ASN1_TYPE_INTEGER: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "errorValue", tag, pos, seq_end, &value)); ++ local = value; ++ oid.num_values = 0; ++ break; ++ case ASN1_TYPE_OBJECT_IDENTIFIER: ++ ASN1_CALL(pos, asn1_dec_oid(ctrl, "errorValue", tag, pos, seq_end, &oid)); ++ local = 0; ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ convert = ++ rose_find_error_by_op_val(ctrl, (oid.num_values == 0) ? NULL : &oid, local); ++ if (convert) { ++ msg->code = convert->code; ++ } else { ++ msg->code = ROSE_ERROR_Unknown; ++ } ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " errorValue = %s\n", rose_error2str(msg->code)); ++ } ++ ++ /* Decode any expected error parameters */ ++ if (convert && convert->decode_error_args) { ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, convert->decode_error_args(ctrl, tag, pos, seq_end, &msg->args)); ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the ROSE reject message. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param msg ROSE reject message data to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_decode_reject(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, struct rose_msg_reject *msg) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, "REJECT Component %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ /* Invoke ID choice */ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag) { ++ case ASN1_TYPE_INTEGER: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "invokeId", tag, pos, seq_end, &value)); ++ msg->invoke_id = value; ++ msg->invoke_id_present = 1; ++ break; ++ case ASN1_TYPE_NULL: ++ ASN1_CALL(pos, asn1_dec_null(ctrl, "invokeId", tag, pos, seq_end)); ++ msg->invoke_id_present = 0; ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ ++ /* Problem choice */ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "problemGeneral", tag, pos, seq_end, &value)); ++ msg->code = ROSE_REJECT_BASE(ROSE_REJECT_BASE_General) | (value & 0xFF); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "problemInvoke", tag, pos, seq_end, &value)); ++ msg->code = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) | (value & 0xFF); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "problemResult", tag, pos, seq_end, &value)); ++ msg->code = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result) | (value & 0xFF); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "problemError", tag, pos, seq_end, &value)); ++ msg->code = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) | (value & 0xFF); ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " problem = %s\n", rose_reject2str(msg->code)); ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the ROSE message into the given buffer. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position of the ASN.1 component. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param msg Decoded ROSE message contents. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ * ++ * \note This function only decodes the ROSE contents. It does not check ++ * for the protocol profile, NFE, NPP, and interpretation octets defined in ++ * a facility ie that may preceed the ROSE contents. These header octets ++ * may already have been consumed from the encompasing buffer before the ++ * buffer given here. ++ */ ++const unsigned char *rose_decode(struct pri *ctrl, const unsigned char *pos, ++ const unsigned char *end, struct rose_message *msg) ++{ ++ unsigned tag; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag)); ++ switch (tag) { ++ case ROSE_TAG_COMPONENT_INVOKE: ++ msg->type = ROSE_COMP_TYPE_INVOKE; ++ ASN1_CALL(pos, rose_decode_invoke(ctrl, tag, pos, end, &msg->component.invoke)); ++ break; ++ case ROSE_TAG_COMPONENT_RESULT: ++ msg->type = ROSE_COMP_TYPE_RESULT; ++ ASN1_CALL(pos, rose_decode_result(ctrl, tag, pos, end, &msg->component.result)); ++ break; ++ case ROSE_TAG_COMPONENT_ERROR: ++ msg->type = ROSE_COMP_TYPE_ERROR; ++ ASN1_CALL(pos, rose_decode_error(ctrl, tag, pos, end, &msg->component.error)); ++ break; ++ case ROSE_TAG_COMPONENT_REJECT: ++ msg->type = ROSE_COMP_TYPE_REJECT; ++ ASN1_CALL(pos, rose_decode_reject(ctrl, tag, pos, end, &msg->component.reject)); ++ break; ++ default: ++ msg->type = ROSE_COMP_TYPE_INVALID; ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ ++ if (pos < end) { ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %u byte(s) of trailing data not consumed.\n", ++ (unsigned) (end - pos)); ++ } ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the NetworkFacilityExtension argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param nfe Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *fac_dec_nfe(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, ++ struct facNetworkFacilityExtension *nfe) ++{ ++ int length; ++ int seq_offset; ++ int explicit_offset; ++ const unsigned char *seq_end; ++ const unsigned char *explicit_end; ++ const unsigned char *save_pos; ++ int32_t value; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s NetworkFacilityExtension %s\n", name, asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 0); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "sourceEntity", tag, pos, seq_end, &value)); ++ nfe->source_entity = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1)) { ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "sourceEntityAddress", tag, pos, ++ seq_end, &nfe->source_number)); ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ } else { ++ nfe->source_number.length = 0; ++ } ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "destinationEntity", tag, pos, seq_end, &value)); ++ nfe->destination_entity = value; ++ ++ nfe->destination_number.length = 0; ++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3)) { ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "destinationEntityAddress", tag, ++ pos, seq_end, &nfe->destination_number)); ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ } else { ++ pos = save_pos; ++ } ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the extension header argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param pos Starting position of the ASN.1 component. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param header Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *fac_dec_extension_header(struct pri *ctrl, const unsigned char *pos, ++ const unsigned char *end, struct fac_extension_header *header) ++{ ++ int32_t value; ++ unsigned tag; ++ const unsigned char *save_pos; ++ ++ /* ++ * For simplicity we are not checking the order of ++ * the optional header components. ++ */ ++ header->nfe_present = 0; ++ header->npp_present = 0; ++ header->interpretation_present = 0; ++ while (pos < end) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, end, &tag)); ++ switch (tag) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 10: ++ ASN1_CALL(pos, fac_dec_nfe(ctrl, "nfe", tag, pos, end, &header->nfe)); ++ header->nfe_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 18: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "networkProtocolProfile", tag, pos, end, ++ &value)); ++ header->npp = value; ++ header->npp_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 11: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "interpretation", tag, pos, end, &value)); ++ header->interpretation = value; ++ header->interpretation_present = 1; ++ break; ++ default: ++ pos = save_pos; ++ goto cancel_options; ++ } ++ } ++cancel_options:; ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the facility ie contents header. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param pos Starting position of the facility ie contents. ++ * \param end End of facility ie contents. ++ * \param header Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success (ROSE message). ++ * \retval NULL on error. ++ */ ++const unsigned char *facility_decode_header(struct pri *ctrl, const unsigned char *pos, ++ const unsigned char *end, struct fac_extension_header *header) ++{ ++ /* Make sure we have enough room for the protocol profile ie octet(s) */ ++ if (end < pos + 2) { ++ return NULL; ++ } ++ switch (*pos & Q932_PROTOCOL_MASK) { ++ case Q932_PROTOCOL_ROSE: ++ case Q932_PROTOCOL_EXTENSIONS: ++ break; ++ default: ++ return NULL; ++ } ++ if (!(*pos & 0x80)) { ++ /* DMS-100 Service indicator octet - Just ignore for now */ ++ ++pos; ++ } ++ ++pos; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ asn1_dump(ctrl, pos, end); ++ } ++ ++ pos = fac_dec_extension_header(ctrl, pos, end, header); ++ return pos; ++} ++ ++/*! ++ * \brief Decode the facility ie contents for debug purposes. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param buf Buffer containing the facility ie contents. ++ * \param length Length of facility ie contents. ++ * ++ * \return Nothing ++ * ++ * \note Should only be called if PRI_DEBUG_APDU is enabled. Otherwise, ++ * it it does nothing useful. ++ */ ++void facility_decode_dump(struct pri *ctrl, const unsigned char *buf, size_t length) ++{ ++ const unsigned char *pos; ++ const unsigned char *end; ++ union { ++ struct fac_extension_header header; ++ struct rose_message rose; ++ } discard; ++ ++ end = buf + length; ++ pos = facility_decode_header(ctrl, buf, end, &discard.header); ++ while (pos && pos < end) { ++ pos = rose_decode(ctrl, pos, end, &discard.rose); ++ } ++} ++ ++/* ------------------------------------------------------------------- */ ++/* end rose.c */ + +Property changes on: rose.c +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: rose_other.c +=================================================================== +--- a/rose_other.c (.../tags/1.4.10.2) (revision 0) ++++ b/rose_other.c (.../branches/1.4) (revision 1357) +@@ -0,0 +1,277 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief Switch type operations for: NI2, 4ESS, 5ESS, DMS-100 ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++ ++#include "compat.h" ++#include "libpri.h" ++#include "pri_internal.h" ++#include "rose.h" ++#include "rose_internal.h" ++#include "asn1.h" ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++/*! ++ * \brief Encode the DMS-100 RLT_OperationInd result facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_result_args *args) ++{ ++ return asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0, ++ args->dms100.RLT_OperationInd.call_id); ++} ++ ++/*! ++ * \brief Encode the DMS-100 RLT_ThirdParty invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseDms100RLTThirdParty_ARG *rlt_thirdparty; ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ rlt_thirdparty = &args->dms100.RLT_ThirdParty; ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0, ++ rlt_thirdparty->call_id)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, ++ rlt_thirdparty->reason)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the DMS-100 RLT_OperationInd result argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_dms100_RLT_OperationInd_RES(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_result_args *args) ++{ ++ int32_t value; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 0); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "callId", tag, pos, end, &value)); ++ args->dms100.RLT_OperationInd.call_id = value; ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the DMS-100 RLT_ThirdParty invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_dms100_RLT_ThirdParty_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ struct roseDms100RLTThirdParty_ARG *rlt_third_party; ++ ++ rlt_third_party = &args->dms100.RLT_ThirdParty; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " RLT_ThirdParty %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 0); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "callId", tag, pos, seq_end, &value)); ++ rlt_third_party->call_id = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 1); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "reason", tag, pos, seq_end, &value)); ++ rlt_third_party->reason = value; ++ ++ /* Fixup will skip over any OPTIONAL information */ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the NI2 InformationFollowing invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_ni2_InformationFollowing_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ /* Encode the unknown enumeration value. */ ++ return asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ args->ni2.InformationFollowing.value); ++} ++ ++/*! ++ * \brief Encode the NI2 InitiateTransfer invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseNi2InitiateTransfer_ARG *initiate_transfer; ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ initiate_transfer = &args->ni2.InitiateTransfer; ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, ++ initiate_transfer->call_reference)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the NI2 InformationFollowing invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_ni2_InformationFollowing_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "unknown", tag, pos, end, &value)); ++ args->ni2.InformationFollowing.value = value; ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the NI2 InitiateTransfer invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_ni2_InitiateTransfer_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ struct roseNi2InitiateTransfer_ARG *initiate_transfer; ++ ++ initiate_transfer = &args->ni2.InitiateTransfer; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " InitiateTransfer %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "callReference", tag, pos, seq_end, &value)); ++ initiate_transfer->call_reference = value; ++ ++ /* Fixup will skip over any OPTIONAL information */ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/* ------------------------------------------------------------------- */ ++/* end rose_other.c */ + +Property changes on: rose_other.c +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: pri_q931.h +=================================================================== +--- a/pri_q931.h (.../tags/1.4.10.2) (revision 1357) ++++ b/pri_q931.h (.../branches/1.4) (revision 1357) +@@ -30,44 +30,6 @@ + #ifndef _PRI_Q931_H + #define _PRI_Q931_H + +-typedef enum q931_state { +- /* User states */ +- U0_NULL_STATE, +- U1_CALL_INITIATED, +- U2_OVERLAP_SENDING, +- U3_OUTGOING_CALL_PROCEEDING, +- U4_CALL_DELIVERED, +- U6_CALL_PRESENT, +- U7_CALL_RECEIVED, +- U8_CONNECT_REQUEST, +- U9_INCOMING_CALL_PROCEEDING, +- U10_ACTIVE, +- U11_DISCONNECT_REQUEST, +- U12_DISCONNECT_INDICATION, +- U15_SUSPEND_REQUEST, +- U17_RESUME_REQUEST, +- U19_RELEASE_REQUEST, +- U25_OVERLAP_RECEIVING, +- /* Network states */ +- N0_NULL_STATE, +- N1_CALL_INITIATED, +- N2_OVERLAP_SENDING, +- N3_OUTGOING_CALL_PROCEEDING, +- N4_CALL_DELIVERED, +- N6_CALL_PRESENT, +- N7_CALL_RECEIVED, +- N8_CONNECT_REQUEST, +- N9_INCOMING_CALL_PROCEEDING, +- N10_ACTIVE, +- N11_DISCONNECT_REQUEST, +- N12_DISCONNECT_INDICATION, +- N15_SUSPEND_REQUEST, +- N17_RESUME_REQUEST, +- N19_RELEASE_REQUEST, +- N22_CALL_ABORT, +- N25_OVERLAP_RECEIVING +-} q931_state; +- + typedef enum q931_mode { + UNKNOWN_MODE, + CIRCUIT_MODE, +@@ -79,13 +41,13 @@ + u_int8_t pd; /* Protocol Discriminator */ + #if __BYTE_ORDER == __BIG_ENDIAN + u_int8_t x0:4; +- u_int8_t crlen:4; ++ u_int8_t crlen:4;/*!< Call reference length */ + #else +- u_int8_t crlen:4; ++ u_int8_t crlen:4;/*!< Call reference length */ + u_int8_t x0:4; + #endif + u_int8_t contents[0]; +- u_int8_t crv[3]; ++ u_int8_t crv[3];/*!< Call reference value */ + } __attribute__ ((packed)) q931_h; + + +@@ -113,6 +75,10 @@ + + #define Q931_PROTOCOL_DISCRIMINATOR 0x08 + #define GR303_PROTOCOL_DISCRIMINATOR 0x4f ++/* AT&T Maintenance Protocol Discriminator */ ++#define MAINTENANCE_PROTOCOL_DISCRIMINATOR_1 0x03 ++/* National Maintenance Protocol Discriminator */ ++#define MAINTENANCE_PROTOCOL_DISCRIMINATOR_2 0x43 + + /* Q.931 / National ISDN Message Types */ + +@@ -157,9 +123,17 @@ + #define Q931_SUSPEND_REJECT 0x21 + + /* Maintenance messages (codeset 0 only) */ +-#define NATIONAL_SERVICE 0x0f +-#define NATIONAL_SERVICE_ACKNOWLEDGE 0x07 ++#define ATT_SERVICE 0x0f ++#define ATT_SERVICE_ACKNOWLEDGE 0x07 ++#define NATIONAL_SERVICE 0x07 ++#define NATIONAL_SERVICE_ACKNOWLEDGE 0x0f + ++#define SERVICE_CHANGE_STATUS_INSERVICE 0 ++#define SERVICE_CHANGE_STATUS_LOOPBACK 1 /* not supported */ ++#define SERVICE_CHANGE_STATUS_OUTOFSERVICE 2 ++#define SERVICE_CHANGE_STATUS_REQCONTINUITYCHECK 3 /* not supported */ ++#define SERVICE_CHANGE_STATUS_SHUTDOWN 4 /* not supported */ ++ + /* Special codeset 0 IE */ + #define NATIONAL_CHANGE_STATUS 0x1 + +@@ -168,10 +142,11 @@ + #define Q931_NON_LOCKING_SHIFT 0x98 + #define Q931_BEARER_CAPABILITY 0x04 + #define Q931_CAUSE 0x08 +-#define Q931_CALL_STATE 0x14 ++#define Q931_IE_CALL_STATE 0x14 + #define Q931_CHANNEL_IDENT 0x18 + #define Q931_PROGRESS_INDICATOR 0x1e + #define Q931_NETWORK_SPEC_FAC 0x20 ++#define Q931_CALLING_PARTY_CATEGORY (0x32 | Q931_CODESET(5)) + #define Q931_INFORMATION_RATE 0x40 + #define Q931_TRANSIT_DELAY 0x42 + #define Q931_TRANS_DELAY_SELECT 0x43 +@@ -200,8 +175,9 @@ + #define Q931_IE_SEGMENTED_MSG 0x00 + #define Q931_IE_CHANGE_STATUS 0x01 + #define Q931_IE_ORIGINATING_LINE_INFO (0x01 | Q931_CODESET(6)) +-#define Q931_IE_CONNECTED_ADDR 0x0C +-#define Q931_IE_CONNECTED_NUM 0x4C ++#define Q931_IE_CONNECTED_ADDR 0x0c ++#define Q931_IE_CONNECTED_NUM 0x4c ++#define Q931_IE_CONNECTED_SUBADDR 0x4d + #define Q931_IE_CALL_IDENTITY 0x10 + #define Q931_IE_FACILITY 0x1c + #define Q931_IE_ENDPOINT_ID 0x26 +@@ -224,31 +200,255 @@ + #define Q931_IE_ESCAPE_FOR_EXT 0x7F + + +-/* Call state stuff */ +-#define Q931_CALL_STATE_NULL 0 +-#define Q931_CALL_STATE_CALL_INITIATED 1 +-#define Q931_CALL_STATE_OVERLAP_SENDING 2 +-#define Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING 3 +-#define Q931_CALL_STATE_CALL_DELIVERED 4 +-#define Q931_CALL_STATE_CALL_PRESENT 6 +-#define Q931_CALL_STATE_CALL_RECEIVED 7 +-#define Q931_CALL_STATE_CONNECT_REQUEST 8 +-#define Q931_CALL_STATE_INCOMING_CALL_PROCEEDING 9 +-#define Q931_CALL_STATE_ACTIVE 10 +-#define Q931_CALL_STATE_DISCONNECT_REQUEST 11 +-#define Q931_CALL_STATE_DISCONNECT_INDICATION 12 +-#define Q931_CALL_STATE_SUSPEND_REQUEST 15 +-#define Q931_CALL_STATE_RESUME_REQUEST 17 +-#define Q931_CALL_STATE_RELEASE_REQUEST 19 +-#define Q931_CALL_STATE_OVERLAP_RECEIVING 25 +-#define Q931_CALL_STATE_RESTART_REQUEST 61 +-#define Q931_CALL_STATE_RESTART 62 ++/*! Q.931 call states */ ++enum Q931_CALL_STATE { ++ /*! ++ * \details ++ * null state (U0): ++ * No call exists. ++ * \details ++ * null state (N0): ++ * No call exists. ++ */ ++ Q931_CALL_STATE_NULL = 0, ++ /*! ++ * \details ++ * call initiated (U1): ++ * This state exists for an outgoing call, when the user requests ++ * call establishment from the network. ++ * \details ++ * call initiated (N1): ++ * This state exists for an outgoing call when the network has received ++ * a call establishment request but has not yet responded. ++ */ ++ Q931_CALL_STATE_CALL_INITIATED = 1, ++ /*! ++ * \details ++ * overlap sending (U2): ++ * This state exists for an outgoing call when the user has ++ * received acknowledgement of the call establishment request which ++ * permits the user to send additional call information to the network ++ * in overlap mode. ++ * \details ++ * overlap sending (N2): ++ * This state exists for an outgoing call when the network has acknowledged ++ * the call establishment request and is prepared to receive additional ++ * call information (if any) in overlap mode. ++ */ ++ Q931_CALL_STATE_OVERLAP_SENDING = 2, ++ /*! ++ * \details ++ * outgoing call proceeding (U3): ++ * This state exists for an outgoing call when the user has ++ * received acknowledgement that the network has received all ++ * call information necessary to effect call establishment. ++ * \details ++ * outgoing call proceeding (N3): ++ * This state exists for an outgoing call when the network has sent ++ * acknowledgement that the network has received all call information ++ * necessary to effect call establishment. ++ */ ++ Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING = 3, ++ /*! ++ * \details ++ * call delivered (U4): ++ * This state exists for an outgoing call when the calling user has ++ * received an indication that remote user alerting has been initiated. ++ * \details ++ * call delivered (N4): ++ * This state exists for an outgoing call when the network has indicated ++ * that remote user alerting has been initiated. ++ */ ++ Q931_CALL_STATE_CALL_DELIVERED = 4, ++ /*! ++ * \details ++ * call present (U6): ++ * This state exists for an incoming call when the user has received a ++ * call establishment request but has not yet responded. ++ * \details ++ * call present (N6): ++ * This state exists for an incoming call when the network has sent a ++ * call establishment request but has not yet received a satisfactory ++ * response. ++ */ ++ Q931_CALL_STATE_CALL_PRESENT = 6, ++ /*! ++ * \details ++ * call received (U7): ++ * This state exists for an incoming call when the user has indicated ++ * alerting but has not yet answered. ++ * \details ++ * call received (N7): ++ * This state exists for an incoming call when the network has received ++ * an indication that the user is alerting but has not yet received an ++ * answer. ++ */ ++ Q931_CALL_STATE_CALL_RECEIVED = 7, ++ /*! ++ * \details ++ * connect request (U8): ++ * This state exists for an incoming call when the user has answered ++ * the call and is waiting to be awarded the call. ++ * \details ++ * connect request (N8): ++ * This state exists for an incoming call when the network has received ++ * an answer but the network has not yet awarded the call. ++ */ ++ Q931_CALL_STATE_CONNECT_REQUEST = 8, ++ /*! ++ * \details ++ * incoming call proceeding (U9): ++ * This state exists for an incoming call when the user has sent ++ * acknowledgement that the user has received all call information ++ * necessary to effect call establishment. ++ * \details ++ * incoming call proceeding (N9): ++ * This state exists for an incoming call when the network has received ++ * acknowledgement that the user has received all call information ++ * necessary to effect call establishment. ++ */ ++ Q931_CALL_STATE_INCOMING_CALL_PROCEEDING = 9, ++ /*! ++ * \details ++ * active (U10): ++ * This state exists for an incoming call when the user has received ++ * an acknowledgement from the network that the user has been awarded ++ * the call. This state exists for an outgoing call when the user has ++ * received an indication that the remote user has answered the call. ++ * \details ++ * active (N10): ++ * This state exists for an incoming call when the network has awarded ++ * the call to the called user. This state exists for an outgoing call ++ * when the network has indicated that the remote user has answered ++ * the call. ++ */ ++ Q931_CALL_STATE_ACTIVE = 10, ++ /*! ++ * \details ++ * disconnect request (U11): ++ * This state exists when the user has requested the network to clear ++ * the end-to-end connection (if any) and is waiting for a response. ++ * \details ++ * disconnect request (N11): ++ * This state exists when the network has received a request from the ++ * user to clear the end-to-end connection (if any). ++ */ ++ Q931_CALL_STATE_DISCONNECT_REQUEST = 11, ++ /*! ++ * \details ++ * disconnect indication (U12): ++ * This state exists when the user has received an invitation to ++ * disconnect because the network has disconnected the end-to-end ++ * connection (if any). ++ * \details ++ * disconnect indication (N12): ++ * This state exists when the network has disconnected the end-to-end ++ * connection (if any) and has sent an invitation to disconnect the ++ * user-network connection. ++ */ ++ Q931_CALL_STATE_DISCONNECT_INDICATION = 12, ++ /*! ++ * \details ++ * suspend request (U15): ++ * This state exists when the user has requested the network to suspend ++ * the call and is waiting for a response. ++ * \details ++ * suspend request (N15): ++ * This state exists when the network has received a request to suspend ++ * the call but has not yet responded. ++ */ ++ Q931_CALL_STATE_SUSPEND_REQUEST = 15, ++ /*! ++ * \details ++ * resume request (U17): ++ * This state exists when the user has requested the network to resume ++ * a previously suspended call and is waiting for a response. ++ * \details ++ * resume request (N17): ++ * This state exists when the network has received a request to resume ++ * a previously suspended call but has not yet responded. ++ */ ++ Q931_CALL_STATE_RESUME_REQUEST = 17, ++ /*! ++ * \details ++ * release request (U19): ++ * This state exists when the user has requested the network to release ++ * and is waiting for a response. ++ * \details ++ * release request (N19): ++ * This state exists when the network has requested the user to release ++ * and is waiting for a response. ++ */ ++ Q931_CALL_STATE_RELEASE_REQUEST = 19, ++ /*! ++ * \details ++ * call abort (N22): ++ * This state exists for an incoming call for the point-to-multipoint ++ * configuration when the call is being cleared before any user has been ++ * awarded the call. ++ */ ++ Q931_CALL_STATE_CALL_ABORT = 22, ++ /*! ++ * \details ++ * overlap receiving (U25): ++ * This state exists for an incoming call when the user has acknowledged ++ * the call establishment request from the network and is prepared to ++ * receive additional call information (if any) in overlap mode. ++ * \details ++ * overlap receiving (N25): ++ * This state exists for an incoming call when the network has received ++ * acknowledgement of the call establishment request which permits the ++ * network to send additional call information (if any) in the overlap ++ * mode. ++ */ ++ Q931_CALL_STATE_OVERLAP_RECEIVING = 25, ++ /*! ++ * \details ++ * call independent service (U31): (From Q.932) ++ * This state exists when a call independent supplementary service ++ * signalling connection is established. ++ * \details ++ * call independent service (N31): (From Q.932) ++ * This state exists when a call independent supplementary service ++ * signalling connection is established. ++ */ ++ Q931_CALL_STATE_CALL_INDEPENDENT_SERVICE = 31, ++ Q931_CALL_STATE_RESTART_REQUEST = 61, ++ Q931_CALL_STATE_RESTART = 62, ++ /*! ++ * \details ++ * Call state has not been set. ++ * Call state does not exist. ++ * Call state not initialized. ++ * Call state internal use only. ++ */ ++ Q931_CALL_STATE_NOT_SET = 0xFF, ++}; + ++/*! Q.931 call establishment state ranking for competing calls in PTMP NT mode. */ ++enum Q931_RANKED_CALL_STATE { ++ /*! Call is present but has no response yet. */ ++ Q931_RANKED_CALL_STATE_PRESENT, ++ /*! Call is collecting digits. */ ++ Q931_RANKED_CALL_STATE_OVERLAP, ++ /*! Call routing is happening. */ ++ Q931_RANKED_CALL_STATE_PROCEEDING, ++ /*! Called party is being alerted of the call. */ ++ Q931_RANKED_CALL_STATE_ALERTING, ++ /*! Call is connected. A winner has been declared. */ ++ Q931_RANKED_CALL_STATE_CONNECT, ++ /*! Call is in some non-call establishment state (likely disconnecting). */ ++ Q931_RANKED_CALL_STATE_OTHER, ++}; + + /* EuroISDN */ + #define Q931_SENDING_COMPLETE 0xa1 + ++extern int maintenance_service(struct pri *pri, int span, int channel, int changestatus); + ++extern int maintenance_service_ack(struct pri *pri, q931_call *call); ++ ++ + /* Q.SIG specific */ + #define QSIG_IE_TRANSIT_COUNT 0x31 + +@@ -268,7 +468,7 @@ + + extern int q931_information(struct pri *pri, q931_call *call, char digit); + +-extern int q931_keypad_facility(struct pri *pri, q931_call *call, char *digits); ++extern int q931_keypad_facility(struct pri *pri, q931_call *call, const char *digits); + + extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn); + +@@ -291,8 +491,16 @@ + extern int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req); + extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx); + +-extern void __q931_destroycall(struct pri *pri, q931_call *c); ++void q931_destroycall(struct pri *pri, q931_call *c); + + extern void q931_dl_indication(struct pri *pri, int event); + ++int q931_send_hold(struct pri *ctrl, struct q931_call *call); ++int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call); ++int q931_send_hold_rej(struct pri *ctrl, struct q931_call *call, int cause); ++ ++int q931_send_retrieve(struct pri *ctrl, struct q931_call *call, int channel); ++int q931_send_retrieve_ack(struct pri *ctrl, struct q931_call *call, int channel); ++int q931_send_retrieve_rej(struct pri *ctrl, struct q931_call *call, int cause); ++ + #endif +Index: rose_qsig_diversion.c +=================================================================== +--- a/rose_qsig_diversion.c (.../tags/1.4.10.2) (revision 0) ++++ b/rose_qsig_diversion.c (.../branches/1.4) (revision 1357) +@@ -0,0 +1,1390 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief Q.SIG ROSE Call-Diversion-Operations ++ * ++ * Call-Diversion-Operations ECMA-174 Annex F Table F.1 ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++ ++#include "compat.h" ++#include "libpri.h" ++#include "pri_internal.h" ++#include "rose.h" ++#include "rose_internal.h" ++#include "asn1.h" ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++/*! ++ * \internal ++ * \brief Encode the IntResult type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param int_result Forwarding record information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_IntResult(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, unsigned tag, const struct roseQsigForwardingRecord *int_result) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &int_result->served_user_number)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ int_result->basic_service)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, int_result->procedure)); ++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE, ++ &int_result->diverted_to)); ++ if (int_result->remote_enabled) { ++ /* Not the DEFAULT value */ ++ ASN1_CALL(pos, asn1_enc_boolean(pos, end, ASN1_TYPE_BOOLEAN, ++ int_result->remote_enabled)); ++ } ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the IntResultList type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SET unless the caller implicitly ++ * tags it otherwise. ++ * \param int_result_list Forwarding record list information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_IntResultList(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, unsigned tag, ++ const struct roseQsigForwardingList *int_result_list) ++{ ++ unsigned index; ++ unsigned char *set_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(set_len, pos, end, tag); ++ ++ for (index = 0; index < int_result_list->num_records; ++index) { ++ ASN1_CALL(pos, rose_enc_qsig_IntResult(ctrl, pos, end, ASN1_TAG_SEQUENCE, ++ &int_result_list->list[index])); ++ } ++ ++ ASN1_CONSTRUCTED_END(set_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the ActivateDiversionQ invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigActivateDiversionQ_ARG *activate_diversion_q; ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ activate_diversion_q = &args->qsig.ActivateDiversionQ; ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ activate_diversion_q->procedure)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ activate_diversion_q->basic_service)); ++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE, ++ &activate_diversion_q->diverted_to)); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &activate_diversion_q->served_user_number)); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &activate_diversion_q->activating_user_number)); ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the DeactivateDiversionQ invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigDeactivateDiversionQ_ARG *deactivate_diversion_q; ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ deactivate_diversion_q = &args->qsig.DeactivateDiversionQ; ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ deactivate_diversion_q->procedure)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ deactivate_diversion_q->basic_service)); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &deactivate_diversion_q->served_user_number)); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &deactivate_diversion_q->deactivating_user_number)); ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the InterrogateDiversionQ invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigInterrogateDiversionQ_ARG *interrogate_diversion_q; ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ interrogate_diversion_q = &args->qsig.InterrogateDiversionQ; ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ interrogate_diversion_q->procedure)); ++ if (interrogate_diversion_q->basic_service) { ++ /* Not the DEFAULT value */ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ interrogate_diversion_q->basic_service)); ++ } ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &interrogate_diversion_q->served_user_number)); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &interrogate_diversion_q->interrogating_user_number)); ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the InterrogateDiversionQ result facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_InterrogateDiversionQ_RES(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_result_args *args) ++{ ++ return rose_enc_qsig_IntResultList(ctrl, pos, end, ASN1_TAG_SET, ++ &args->qsig.InterrogateDiversionQ); ++} ++ ++/*! ++ * \brief Encode the CheckRestriction invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigCheckRestriction_ARG *check_restriction; ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ check_restriction = &args->qsig.CheckRestriction; ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &check_restriction->served_user_number)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ check_restriction->basic_service)); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &check_restriction->diverted_to_number)); ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the CallRerouting invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigCallRerouting_ARG *call_rerouting; ++ unsigned char *seq_len; ++ unsigned char *exp_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ call_rerouting = &args->qsig.CallRerouting; ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ call_rerouting->rerouting_reason)); ++ if (call_rerouting->original_rerouting_reason_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0, ++ call_rerouting->original_rerouting_reason)); ++ } ++ ASN1_CALL(pos, rose_enc_Address(ctrl, pos, end, ASN1_TAG_SEQUENCE, ++ &call_rerouting->called)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, ++ call_rerouting->diversion_counter)); ++ ASN1_CALL(pos, rose_enc_Q931ie(ctrl, pos, end, ASN1_CLASS_APPLICATION | 0, ++ &call_rerouting->q931ie)); ++ ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1); ++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end, ++ &call_rerouting->last_rerouting)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, ++ call_rerouting->subscription_option)); ++ ++ if (call_rerouting->calling_subaddress.length) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3); ++ ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end, ++ &call_rerouting->calling_subaddress)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4); ++ ASN1_CALL(pos, rose_enc_PresentedNumberScreened(ctrl, pos, end, ++ &call_rerouting->calling)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ ++ if (call_rerouting->calling_name_present) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 5); ++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end, ++ &call_rerouting->calling_name)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ if (call_rerouting->original_called_present) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 6); ++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end, ++ &call_rerouting->original_called)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ if (call_rerouting->redirecting_name_present) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 7); ++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end, ++ &call_rerouting->redirecting_name)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ if (call_rerouting->original_called_name_present) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 8); ++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end, ++ &call_rerouting->original_called_name)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the DivertingLegInformation1 invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_DivertingLegInformation1_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigDivertingLegInformation1_ARG *diverting_leg_information_1; ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ diverting_leg_information_1 = &args->qsig.DivertingLegInformation1; ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ diverting_leg_information_1->diversion_reason)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ diverting_leg_information_1->subscription_option)); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, ++ &diverting_leg_information_1->nominated_number)); ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the DivertingLegInformation2 invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_DivertingLegInformation2_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigDivertingLegInformation2_ARG *diverting_leg_information_2; ++ unsigned char *seq_len; ++ unsigned char *exp_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ diverting_leg_information_2 = &args->qsig.DivertingLegInformation2; ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, ++ diverting_leg_information_2->diversion_counter)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ diverting_leg_information_2->diversion_reason)); ++ if (diverting_leg_information_2->original_diversion_reason_present) { ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0, ++ diverting_leg_information_2->original_diversion_reason)); ++ } ++ ++ if (diverting_leg_information_2->diverting_present) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1); ++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end, ++ &diverting_leg_information_2->diverting)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ if (diverting_leg_information_2->original_called_present) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2); ++ ASN1_CALL(pos, rose_enc_PresentedNumberUnscreened(ctrl, pos, end, ++ &diverting_leg_information_2->original_called)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ if (diverting_leg_information_2->redirecting_name_present) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3); ++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end, ++ &diverting_leg_information_2->redirecting_name)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ if (diverting_leg_information_2->original_called_name_present) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4); ++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end, ++ &diverting_leg_information_2->original_called_name)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the DivertingLegInformation3 invoke facility ie arguments. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param args Arguments to encode in the buffer. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_qsig_DivertingLegInformation3_ARG(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, const union rose_msg_invoke_args *args) ++{ ++ const struct roseQsigDivertingLegInformation3_ARG *diverting_leg_information_3; ++ unsigned char *seq_len; ++ unsigned char *exp_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ diverting_leg_information_3 = &args->qsig.DivertingLegInformation3; ++ ASN1_CALL(pos, asn1_enc_boolean(pos, end, ASN1_TYPE_BOOLEAN, ++ diverting_leg_information_3->presentation_allowed_indicator)); ++ ++ if (diverting_leg_information_3->redirection_name_present) { ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(exp_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0); ++ ASN1_CALL(pos, rose_enc_qsig_Name(ctrl, pos, end, ++ &diverting_leg_information_3->redirection_name)); ++ ASN1_CONSTRUCTED_END(exp_len, pos, end); ++ } ++ ++ /* No extension to encode */ ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the IntResult argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param int_result Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_dec_qsig_IntResult(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct roseQsigForwardingRecord *int_result) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ const unsigned char *save_pos; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s IntResult %s\n", name, asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end, ++ &int_result->served_user_number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); ++ int_result->basic_service = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value)); ++ int_result->procedure = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ ASN1_CALL(pos, rose_dec_Address(ctrl, "divertedToAddress", tag, pos, seq_end, ++ &int_result->diverted_to)); ++ ++ /* ++ * A sequence specifies an ordered list of component types. ++ * However, for simplicity we are not checking the order of ++ * the remaining optional components. ++ */ ++ int_result->remote_enabled = 0; /* DEFAULT FALSE */ ++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag & ~ASN1_PC_MASK) { ++ case ASN1_TYPE_BOOLEAN: ++ /* Must not be constructed but we will not check for it for simplicity. */ ++ ASN1_CALL(pos, asn1_dec_boolean(ctrl, "remoteEnabled", tag, pos, seq_end, ++ &value)); ++ int_result->remote_enabled = value; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " extension %s\n", asn1_tag2str(tag)); ++ } ++ /* Fixup will skip over the manufacturer extension information */ ++ default: ++ pos = save_pos; ++ goto cancel_options; ++ } ++ } ++cancel_options:; ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the IntResultList argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param int_result_list Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_dec_qsig_IntResultList(struct pri *ctrl, ++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct roseQsigForwardingList *int_result_list) ++{ ++ int length; ++ int set_offset; ++ const unsigned char *set_end; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s IntResultList %s\n", name, asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(set_end, set_offset, length, pos, end); ++ ++ int_result_list->num_records = 0; ++ while (pos < set_end && *pos != ASN1_INDEF_TERM) { ++ if (int_result_list->num_records < ARRAY_LEN(int_result_list->list)) { ++ ASN1_CALL(pos, asn1_dec_tag(pos, set_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ ASN1_CALL(pos, rose_dec_qsig_IntResult(ctrl, "listEntry", tag, pos, set_end, ++ &int_result_list->list[int_result_list->num_records])); ++ ++int_result_list->num_records; ++ } else { ++ /* Too many records */ ++ return NULL; ++ } ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, set_offset, set_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG ActivateDiversionQ invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_ActivateDiversionQ_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ struct roseQsigActivateDiversionQ_ARG *activate_diversion_q; ++ ++ activate_diversion_q = &args->qsig.ActivateDiversionQ; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " ActivateDiversionQ %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value)); ++ activate_diversion_q->procedure = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); ++ activate_diversion_q->basic_service = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ ASN1_CALL(pos, rose_dec_Address(ctrl, "divertedToAddress", tag, pos, seq_end, ++ &activate_diversion_q->diverted_to)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end, ++ &activate_diversion_q->served_user_number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "activatingUserNr", tag, pos, seq_end, ++ &activate_diversion_q->activating_user_number)); ++ ++ /* Fixup will skip over any OPTIONAL manufacturer extension information */ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG DeactivateDiversionQ invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_DeactivateDiversionQ_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ struct roseQsigDeactivateDiversionQ_ARG *deactivate_diversion_q; ++ ++ deactivate_diversion_q = &args->qsig.DeactivateDiversionQ; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " DeactivateDiversionQ %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value)); ++ deactivate_diversion_q->procedure = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); ++ deactivate_diversion_q->basic_service = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end, ++ &deactivate_diversion_q->served_user_number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "deactivatingUserNr", tag, pos, seq_end, ++ &deactivate_diversion_q->deactivating_user_number)); ++ ++ /* Fixup will skip over any OPTIONAL manufacturer extension information */ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG InterrogateDiversionQ invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ struct roseQsigInterrogateDiversionQ_ARG *interrogate_diversion_q; ++ ++ interrogate_diversion_q = &args->qsig.InterrogateDiversionQ; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " InterrogateDiversionQ %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "procedure", tag, pos, seq_end, &value)); ++ interrogate_diversion_q->procedure = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ if (tag == ASN1_TYPE_ENUMERATED) { ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); ++ interrogate_diversion_q->basic_service = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ } else { ++ interrogate_diversion_q->basic_service = 0; /* allServices */ ++ } ++ ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end, ++ &interrogate_diversion_q->served_user_number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "interrogatingUserNr", tag, pos, seq_end, ++ &interrogate_diversion_q->interrogating_user_number)); ++ ++ /* Fixup will skip over any OPTIONAL manufacturer extension information */ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG InterrogateDiversionQ result argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_InterrogateDiversionQ_RES(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_result_args *args) ++{ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SET); ++ return rose_dec_qsig_IntResultList(ctrl, "InterrogateDiversionQ", tag, pos, end, ++ &args->qsig.InterrogateDiversionQ); ++} ++ ++/*! ++ * \brief Decode the Q.SIG CheckRestriction invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_CheckRestriction_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ struct roseQsigCheckRestriction_ARG *check_restriction; ++ ++ check_restriction = &args->qsig.CheckRestriction; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " CheckRestriction %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "servedUserNr", tag, pos, seq_end, ++ &check_restriction->served_user_number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "basicService", tag, pos, seq_end, &value)); ++ check_restriction->basic_service = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "divertedToNr", tag, pos, seq_end, ++ &check_restriction->diverted_to_number)); ++ ++ /* Fixup will skip over any OPTIONAL manufacturer extension information */ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG CallRerouting invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_CallRerouting_ARG(struct pri *ctrl, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ int explicit_offset; ++ const unsigned char *explicit_end; ++ const unsigned char *seq_end; ++ const unsigned char *save_pos; ++ struct roseQsigCallRerouting_ARG *call_rerouting; ++ ++ call_rerouting = &args->qsig.CallRerouting; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " CallRerouting %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "reroutingReason", tag, pos, seq_end, &value)); ++ call_rerouting->rerouting_reason = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | 0)) { ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "originalReroutingReason", tag, pos, seq_end, ++ &value)); ++ call_rerouting->original_rerouting_reason = value; ++ call_rerouting->original_rerouting_reason_present = 1; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ } else { ++ call_rerouting->original_rerouting_reason_present = 0; ++ } ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ ASN1_CALL(pos, rose_dec_Address(ctrl, "calledAddress", tag, pos, seq_end, ++ &call_rerouting->called)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionCounter", tag, pos, seq_end, &value)); ++ call_rerouting->diversion_counter = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_CLASS_APPLICATION | 0); ++ ASN1_CALL(pos, rose_dec_Q931ie(ctrl, "pSS1InfoElement", tag, pos, seq_end, ++ &call_rerouting->q931ie, sizeof(call_rerouting->q931ie_contents))); ++ ++ /* Remove EXPLICIT tag */ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "lastReroutingNr", tag, pos, ++ explicit_end, &call_rerouting->last_rerouting)); ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_CLASS_CONTEXT_SPECIFIC | 2); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "subscriptionOption", tag, pos, seq_end, &value)); ++ call_rerouting->subscription_option = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ if (tag == (ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3)) { ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "callingPartySubaddress", tag, pos, ++ explicit_end, &call_rerouting->calling_subaddress)); ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ } else { ++ call_rerouting->calling_subaddress.length = 0; ++ } ++ ++ /* Remove EXPLICIT tag */ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ++ ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PresentedNumberScreened(ctrl, "callingNumber", tag, pos, ++ explicit_end, &call_rerouting->calling)); ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ ++ /* ++ * A sequence specifies an ordered list of component types. ++ * However, for simplicity we are not checking the order of ++ * the remaining optional components. ++ */ ++ call_rerouting->calling_name_present = 0; ++ call_rerouting->redirecting_name_present = 0; ++ call_rerouting->original_called_name_present = 0; ++ call_rerouting->original_called_present = 0; ++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5: ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "callingName", tag, pos, ++ explicit_end, &call_rerouting->calling_name)); ++ call_rerouting->calling_name_present = 1; ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 6: ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "originalCalledNr", ++ tag, pos, explicit_end, &call_rerouting->original_called)); ++ call_rerouting->original_called_present = 1; ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 7: ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "redirectingName", tag, pos, ++ explicit_end, &call_rerouting->redirecting_name)); ++ call_rerouting->redirecting_name_present = 1; ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 8: ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "originalCalledName", tag, pos, ++ explicit_end, &call_rerouting->original_called_name)); ++ call_rerouting->original_called_name_present = 1; ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 9: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 9: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 10: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " extension %s\n", asn1_tag2str(tag)); ++ } ++ /* Fixup will skip over the manufacturer extension information */ ++ default: ++ pos = save_pos; ++ goto cancel_options; ++ } ++ } ++cancel_options:; ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG DivertingLegInformation1 invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_DivertingLegInformation1_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ struct roseQsigDivertingLegInformation1_ARG *diverting_leg_information_1; ++ ++ diverting_leg_information_1 = &args->qsig.DivertingLegInformation1; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " DivertingLegInformation1 %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionReason", tag, pos, seq_end, &value)); ++ diverting_leg_information_1->diversion_reason = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "subscriptionOption", tag, pos, seq_end, &value)); ++ diverting_leg_information_1->subscription_option = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "nominatedNr", tag, pos, seq_end, ++ &diverting_leg_information_1->nominated_number)); ++ ++ /* Fixup will skip over any OPTIONAL manufacturer extension information */ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG DivertingLegInformation2 invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_DivertingLegInformation2_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ int explicit_offset; ++ const unsigned char *explicit_end; ++ const unsigned char *seq_end; ++ const unsigned char *save_pos; ++ struct roseQsigDivertingLegInformation2_ARG *diverting_leg_information_2; ++ ++ diverting_leg_information_2 = &args->qsig.DivertingLegInformation2; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " DivertingLegInformation2 %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_INTEGER); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionCounter", tag, pos, seq_end, &value)); ++ diverting_leg_information_2->diversion_counter = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "diversionReason", tag, pos, seq_end, &value)); ++ diverting_leg_information_2->diversion_reason = value; ++ ++ /* ++ * A sequence specifies an ordered list of component types. ++ * However, for simplicity we are not checking the order of ++ * the remaining optional components. ++ */ ++ diverting_leg_information_2->original_diversion_reason_present = 0; ++ diverting_leg_information_2->diverting_present = 0; ++ diverting_leg_information_2->original_called_present = 0; ++ diverting_leg_information_2->redirecting_name_present = 0; ++ diverting_leg_information_2->original_called_name_present = 0; ++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0: ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "originalDiversionReason", tag, pos, ++ seq_end, &value)); ++ diverting_leg_information_2->original_diversion_reason = value; ++ diverting_leg_information_2->original_diversion_reason_present = 1; ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1: ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "divertingNr", tag, ++ pos, explicit_end, &diverting_leg_information_2->diverting)); ++ diverting_leg_information_2->diverting_present = 1; ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2: ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PresentedNumberUnscreened(ctrl, "originalCalledNr", ++ tag, pos, explicit_end, &diverting_leg_information_2->original_called)); ++ diverting_leg_information_2->original_called_present = 1; ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3: ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "redirectingName", tag, pos, ++ explicit_end, &diverting_leg_information_2->redirecting_name)); ++ diverting_leg_information_2->redirecting_name_present = 1; ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 4: ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "originalCalledName", tag, pos, ++ explicit_end, &diverting_leg_information_2->original_called_name)); ++ diverting_leg_information_2->original_called_name_present = 1; ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 5: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 6: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " extension %s\n", asn1_tag2str(tag)); ++ } ++ /* Fixup will skip over the manufacturer extension information */ ++ default: ++ pos = save_pos; ++ goto cancel_options; ++ } ++ } ++cancel_options:; ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Q.SIG DivertingLegInformation3 invoke argument parameters. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param tag Component tag that identified this structure. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param args Arguments to fill in from the decoded buffer. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_qsig_DivertingLegInformation3_ARG(struct pri *ctrl, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ union rose_msg_invoke_args *args) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ int explicit_offset; ++ const unsigned char *explicit_end; ++ const unsigned char *seq_end; ++ const unsigned char *save_pos; ++ struct roseQsigDivertingLegInformation3_ARG *diverting_leg_information_3; ++ ++ diverting_leg_information_3 = &args->qsig.DivertingLegInformation3; ++ ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TAG_SEQUENCE); ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " DivertingLegInformation3 %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_BOOLEAN); ++ ASN1_CALL(pos, asn1_dec_boolean(ctrl, "presentationAllowedIndicator", tag, pos, ++ seq_end, &value)); ++ diverting_leg_information_3->presentation_allowed_indicator = value; ++ ++ /* ++ * A sequence specifies an ordered list of component types. ++ * However, for simplicity we are not checking the order of ++ * the remaining optional components. ++ */ ++ diverting_leg_information_3->redirection_name_present = 0; ++ while (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ save_pos = pos; ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ switch (tag) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0: ++ /* Remove EXPLICIT tag */ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, seq_end, &length)); ++ ASN1_END_SETUP(explicit_end, explicit_offset, length, pos, seq_end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, explicit_end, &tag)); ++ ASN1_CALL(pos, rose_dec_qsig_Name(ctrl, "redirectionName", tag, pos, ++ explicit_end, &diverting_leg_information_3->redirection_name)); ++ diverting_leg_information_3->redirection_name_present = 1; ++ ++ ASN1_END_FIXUP(ctrl, pos, explicit_offset, explicit_end, seq_end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 1: ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 2: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " extension %s\n", asn1_tag2str(tag)); ++ } ++ /* Fixup will skip over the manufacturer extension information */ ++ default: ++ pos = save_pos; ++ goto cancel_options; ++ } ++ } ++cancel_options:; ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/* ------------------------------------------------------------------- */ ++/* end rose_qsig_diversion.c */ + +Property changes on: rose_qsig_diversion.c +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: rose.h +=================================================================== +--- a/rose.h (.../tags/1.4.10.2) (revision 0) ++++ b/rose.h (.../branches/1.4) (revision 1357) +@@ -0,0 +1,3580 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief ROSE definitions and prototypes ++ * ++ * \details ++ * This file contains all of the data structures and definitions needed ++ * for ROSE component encoding and decoding. ++ * ++ * ROSE - Remote Operations Service Element ++ * ASN.1 - Abstract Syntax Notation 1 ++ * APDU - Application Protocol Data Unit ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++#ifndef _LIBPRI_ROSE_H ++#define _LIBPRI_ROSE_H ++ ++#include <string.h> ++#include <sys/types.h> ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* Northern Telecom DMS-100 RLT related operations */ ++#define ROSE_DMS100_RLT_SERVICE_ID 0x3e ++#define ROSE_DMS100_RLT_OPERATION_IND 0x01 ++#define ROSE_DMS100_RLT_THIRD_PARTY 0x02 ++ ++/*! \brief ROSE operation-value function code */ ++enum rose_operation { ++ /*! \brief No ROSE operation */ ++ ROSE_None, ++ /*! \brief Unknown OID/localValue operation-value code */ ++ ROSE_Unknown, ++ ++/* *INDENT-OFF* */ ++ /* ETSI Diversion-Operations */ ++ ROSE_ETSI_ActivationDiversion, /*!< Invoke/Result */ ++ ROSE_ETSI_DeactivationDiversion, /*!< Invoke/Result */ ++ ROSE_ETSI_ActivationStatusNotificationDiv,/*!< Invoke only */ ++ ROSE_ETSI_DeactivationStatusNotificationDiv,/*!< Invoke only */ ++ ROSE_ETSI_InterrogationDiversion, /*!< Invoke/Result */ ++ ROSE_ETSI_DiversionInformation, /*!< Invoke only */ ++ ROSE_ETSI_CallDeflection, /*!< Invoke/Result */ ++ ROSE_ETSI_CallRerouting, /*!< Invoke/Result */ ++ ROSE_ETSI_InterrogateServedUserNumbers, /*!< Invoke/Result */ ++ ROSE_ETSI_DivertingLegInformation1, /*!< Invoke only */ ++ ROSE_ETSI_DivertingLegInformation2, /*!< Invoke only */ ++ ROSE_ETSI_DivertingLegInformation3, /*!< Invoke only */ ++ ++ /* ++ * ETSI Advice-of-Charge-Operations ++ * ++ * Advice-Of-Charge-at-call-Setup(AOCS) ++ * Advice-Of-Charge-During-the-call(AOCD) ++ * Advice-Of-Charge-at-the-End-of-the-call(AOCE) ++ */ ++ ROSE_ETSI_ChargingRequest, /*!< Invoke/Result */ ++ ROSE_ETSI_AOCSCurrency, /*!< Invoke only */ ++ ROSE_ETSI_AOCSSpecialArr, /*!< Invoke only */ ++ ROSE_ETSI_AOCDCurrency, /*!< Invoke only */ ++ ROSE_ETSI_AOCDChargingUnit, /*!< Invoke only */ ++ ROSE_ETSI_AOCECurrency, /*!< Invoke only */ ++ ROSE_ETSI_AOCEChargingUnit, /*!< Invoke only */ ++ ++ /* ETSI Explicit-Call-Transfer-Operations-and-Errors */ ++ ROSE_ETSI_EctExecute, /*!< Invoke/Result */ ++ ROSE_ETSI_ExplicitEctExecute, /*!< Invoke/Result */ ++ ROSE_ETSI_RequestSubaddress, /*!< Invoke only */ ++ ROSE_ETSI_SubaddressTransfer, /*!< Invoke only */ ++ ROSE_ETSI_EctLinkIdRequest, /*!< Invoke/Result */ ++ ROSE_ETSI_EctInform, /*!< Invoke only */ ++ ROSE_ETSI_EctLoopTest, /*!< Invoke/Result */ ++ ++ /* Q.SIG Name-Operations */ ++ ROSE_QSIG_CallingName, /*!< Invoke only */ ++ ROSE_QSIG_CalledName, /*!< Invoke only */ ++ ROSE_QSIG_ConnectedName, /*!< Invoke only */ ++ ROSE_QSIG_BusyName, /*!< Invoke only */ ++ ++ /* Q.SIG SS-AOC-Operations */ ++ ROSE_QSIG_ChargeRequest, /*!< Invoke/Result */ ++ ROSE_QSIG_GetFinalCharge, /*!< Invoke only */ ++ ROSE_QSIG_AocFinal, /*!< Invoke only */ ++ ROSE_QSIG_AocInterim, /*!< Invoke only */ ++ ROSE_QSIG_AocRate, /*!< Invoke only */ ++ ROSE_QSIG_AocComplete, /*!< Invoke/Result */ ++ ROSE_QSIG_AocDivChargeReq, /*!< Invoke only */ ++ ++ /* Q.SIG Call-Transfer-Operations (CT) */ ++ ROSE_QSIG_CallTransferIdentify, /*!< Invoke/Result */ ++ ROSE_QSIG_CallTransferAbandon, /*!< Invoke only */ ++ ROSE_QSIG_CallTransferInitiate, /*!< Invoke/Result */ ++ ROSE_QSIG_CallTransferSetup, /*!< Invoke/Result */ ++ ROSE_QSIG_CallTransferActive, /*!< Invoke only */ ++ ROSE_QSIG_CallTransferComplete, /*!< Invoke only */ ++ ROSE_QSIG_CallTransferUpdate, /*!< Invoke only */ ++ ROSE_QSIG_SubaddressTransfer, /*!< Invoke only */ ++ ++ ROSE_QSIG_PathReplacement, /*!< Invoke only */ ++ ++ /* Q.SIG Call-Diversion-Operations */ ++ ROSE_QSIG_ActivateDiversionQ, /*!< Invoke/Result */ ++ ROSE_QSIG_DeactivateDiversionQ, /*!< Invoke/Result */ ++ ROSE_QSIG_InterrogateDiversionQ, /*!< Invoke/Result */ ++ ROSE_QSIG_CheckRestriction, /*!< Invoke/Result */ ++ ROSE_QSIG_CallRerouting, /*!< Invoke/Result */ ++ ROSE_QSIG_DivertingLegInformation1, /*!< Invoke only */ ++ ROSE_QSIG_DivertingLegInformation2, /*!< Invoke only */ ++ ROSE_QSIG_DivertingLegInformation3, /*!< Invoke only */ ++ ROSE_QSIG_CfnrDivertedLegFailed, /*!< Invoke only */ ++ ++ /* Q.SIG SS-MWI-Operations */ ++ ROSE_QSIG_MWIActivate, /*!< Invoke/Result */ ++ ROSE_QSIG_MWIDeactivate, /*!< Invoke/Result */ ++ ROSE_QSIG_MWIInterrogate, /*!< Invoke/Result */ ++ ++ /* Northern Telecom DMS-100 RLT related operations */ ++ /*! Invoke/Result: Must set invokeId to ROSE_DMS100_RLT_OPERATION_IND */ ++ ROSE_DMS100_RLT_OperationInd, ++ /*! Invoke/Result: Must set invokeId to ROSE_DMS100_RLT_THIRD_PARTY */ ++ ROSE_DMS100_RLT_ThirdParty, ++ ++ ROSE_NI2_InformationFollowing, /*!< Invoke only? */ ++ ROSE_NI2_InitiateTransfer, /*!< Invoke only? Is this correct operation name? */ ++ ++ ROSE_Num_Operation_Codes /*!< Must be last in the enumeration */ ++/* *INDENT-ON* */ ++}; ++ ++enum rose_error_code { ++ /*! \brief No error occurred */ ++ ROSE_ERROR_None, ++ /*! \brief Unknown OID/localValue error-value code */ ++ ROSE_ERROR_Unknown, ++ ++ /* General-Errors (ETS 300 196) and General-Error-List(Q.950) */ ++ ROSE_ERROR_Gen_NotSubscribed, /*!< also: UserNotSubscribed */ ++ ROSE_ERROR_Gen_NotAvailable, ++ ROSE_ERROR_Gen_NotImplemented, /*!< Not in Q.950 */ ++ ROSE_ERROR_Gen_InvalidServedUserNr, ++ ROSE_ERROR_Gen_InvalidCallState, ++ ROSE_ERROR_Gen_BasicServiceNotProvided, ++ ROSE_ERROR_Gen_NotIncomingCall, ++ ROSE_ERROR_Gen_SupplementaryServiceInteractionNotAllowed, ++ ROSE_ERROR_Gen_ResourceUnavailable, ++ ++ /* Additional General-Error-List(Q.950) */ ++ ROSE_ERROR_Gen_RejectedByNetwork, ++ ROSE_ERROR_Gen_RejectedByUser, ++ ROSE_ERROR_Gen_InsufficientInformation, ++ ROSE_ERROR_Gen_CallFailure, ++ ROSE_ERROR_Gen_ProceduralError, ++ ++ /* ETSI Diversion-Operations */ ++ ROSE_ERROR_Div_InvalidDivertedToNr, ++ ROSE_ERROR_Div_SpecialServiceNr, ++ ROSE_ERROR_Div_DiversionToServedUserNr, ++ ROSE_ERROR_Div_IncomingCallAccepted, ++ ROSE_ERROR_Div_NumberOfDiversionsExceeded, ++ ROSE_ERROR_Div_NotActivated, ++ ROSE_ERROR_Div_RequestAlreadyAccepted, ++ ++ /* ETSI Advice-of-Charge-Operations */ ++ ROSE_ERROR_AOC_NoChargingInfoAvailable, ++ ++ /* ETSI Explicit-Call-Transfer-Operations-and-Errors */ ++ ROSE_ERROR_ECT_LinkIdNotAssignedByNetwork, ++ ++ /* Q.SIG from various specifications */ ++ ROSE_ERROR_QSIG_Unspecified, ++ ++ /* Q.SIG SS-AOC-Operations */ ++ ROSE_ERROR_QSIG_AOC_FreeOfCharge, ++ ++ /* Q.SIG Call-Transfer-Operations (CT) */ ++ ROSE_ERROR_QSIG_CT_InvalidReroutingNumber, ++ ROSE_ERROR_QSIG_CT_UnrecognizedCallIdentity, ++ ROSE_ERROR_QSIG_CT_EstablishmentFailure, ++ ++ /* Q.SIG Call-Diversion-Operations (Additional Q.SIG specific errors) */ ++ ROSE_ERROR_QSIG_Div_TemporarilyUnavailable, ++ ROSE_ERROR_QSIG_Div_NotAuthorized, ++ ++ /* Q.SIG SS-MWI-Operations */ ++ ROSE_ERROR_QSIG_InvalidMsgCentreId, ++ ++ /* Northern Telecom DMS-100 RLT related operations */ ++ ROSE_ERROR_DMS100_RLT_BridgeFail, ++ ROSE_ERROR_DMS100_RLT_CallIDNotFound, ++ ROSE_ERROR_DMS100_RLT_NotAllowed, ++ ROSE_ERROR_DMS100_RLT_SwitchEquipCongs, ++ ++ ROSE_ERROR_Num_Codes /*!< Must be last in the enumeration */ ++}; ++ ++#define ROSE_REJECT_BASE(base) ((base) * 0x100) ++enum rose_reject_base { ++ ROSE_REJECT_BASE_General, ++ ROSE_REJECT_BASE_Invoke, ++ ROSE_REJECT_BASE_Result, ++ ROSE_REJECT_BASE_Error, ++ ++ /*! \brief Must be last in the list */ ++ ROSE_REJECT_BASE_Last ++}; ++ ++/*! ++ * \brief From Facility-Information-Element-Components ++ * {itu-t identified-organization etsi(0) 196 facility-information-element-component(3)} ++ */ ++enum rose_reject_code { ++ /*! \brief Not rejected */ ++ ROSE_REJECT_None = -1, ++ /*! \brief Unknown reject code */ ++ ROSE_REJECT_Unknown = -2, ++ ++/* *INDENT-OFF* */ ++ ROSE_REJECT_Gen_UnrecognizedComponent = ROSE_REJECT_BASE(ROSE_REJECT_BASE_General) + 0, ++ ROSE_REJECT_Gen_MistypedComponent = ROSE_REJECT_BASE(ROSE_REJECT_BASE_General) + 1, ++ ROSE_REJECT_Gen_BadlyStructuredComponent = ROSE_REJECT_BASE(ROSE_REJECT_BASE_General) + 2, ++ ++ ROSE_REJECT_Inv_DuplicateInvocation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 0, ++ ROSE_REJECT_Inv_UnrecognizedOperation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 1, ++ ROSE_REJECT_Inv_MistypedArgument = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 2, ++ ROSE_REJECT_Inv_ResourceLimitation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 3, ++ ROSE_REJECT_Inv_InitiatorReleasing = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 4, ++ ROSE_REJECT_Inv_UnrecognizedLinkedID = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 5, ++ ROSE_REJECT_Inv_LinkedResponseUnexpected = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 6, ++ ROSE_REJECT_Inv_UnexpectedChildOperation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Invoke) + 7, ++ ++ ROSE_REJECT_Res_UnrecognizedInvocation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result) + 0, ++ ROSE_REJECT_Res_ResultResponseUnexpected = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result) + 1, ++ ROSE_REJECT_Res_MistypedResult = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Result) + 2, ++ ++ ROSE_REJECT_Err_UnrecognizedInvocation = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 0, ++ ROSE_REJECT_Err_ErrorResponseUnexpected = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 1, ++ ROSE_REJECT_Err_UnrecognizedError = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 2, ++ ROSE_REJECT_Err_UnexpectedError = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 3, ++ ROSE_REJECT_Err_MistypedParameter = ROSE_REJECT_BASE(ROSE_REJECT_BASE_Error) + 4, ++/* *INDENT-ON* */ ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * Q931InformationElement ::= [APPLICATION 0] IMPLICIT OCTET STRING ++ */ ++struct roseQ931ie { ++ /*! ++ * \brief The Q.931 ie is present if length is nonzero. ++ * (If this field is optional in the message.) ++ */ ++ u_int8_t length; ++ ++ /*! ++ * \brief We mostly just need to store the contents so we will defer ++ * decoding/encoding. ++ * ++ * \note To reduce the size of the structure, the memory for the ++ * ie contents is "allocated" after the structure. ++ * \note Remember the "allocated" memory needs to have room for a ++ * null terminator. ++ */ ++ unsigned char contents[0]; ++}; ++ ++enum { ++ /*! Bearer Capability has a max length of 12. */ ++ ROSE_Q931_MAX_BC = 12, ++ /*! High Layer Compatibility has a max length of 5. */ ++ ROSE_Q931_MAX_HLC = 5, ++ /*! Low Layer Compatibility has a max length of 18. */ ++ ROSE_Q931_MAX_LLC = 18, ++ /*! ++ * User-User Information has a network dependent maximum. ++ * The network dependent maximum is either 35 or 131 octets ++ * in non-USER-INFORMATION messages. ++ */ ++ ROSE_Q931_MAX_USER = 131, ++ /*! ++ * Progress Indicator has a max length of 4. ++ * There can be multiple progress indicator ies. ++ * Q.SIG allows up to 3. ++ * ITU-T allows up to 2. ++ */ ++ ROSE_Q931_MAX_PROGRESS = 3 * 4, ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * PartyNumber ::= CHOICE { ++ * -- the numbering plan is the default numbering plan of ++ * -- the network. It is recommended that this value is ++ * -- used. ++ * unknownPartyNumber [0] IMPLICIT NumberDigits, ++ * ++ * -- the numbering plan is according to ++ * -- ITU-T Recommendation E.164. ++ * publicPartyNumber [1] IMPLICIT PublicPartyNumber, ++ * ++ * -- ATM endsystem address encoded as an NSAP address. ++ * nsapEncodedNumber [2] IMPLICIT NsapEncodedNumber, ++ * ++ * -- not used, value reserved. ++ * dataPartyNumber [3] IMPLICIT NumberDigits, ++ * ++ * -- not used, value reserved. ++ * telexPartyNumber [4] IMPLICIT NumberDigits, ++ * privatePartyNumber [5] IMPLICIT PrivatePartyNumber, ++ * ++ * -- not used, value reserved. ++ * nationalStandardPartyNumber [8] IMPLICIT NumberDigits ++ * } ++ */ ++struct rosePartyNumber { ++ /*! ++ * \brief Party numbering plan ++ * \details ++ * unknown(0), ++ * public(1) - The numbering plan is according to ITU-T E.164, ++ * nsapEncoded(2), ++ * data(3) - Reserved, ++ * telex(4) - Reserved, ++ * private(5), ++ * nationalStandard(8) - Reserved ++ */ ++ u_int8_t plan; ++ ++ /*! ++ * \brief Type-Of-Number valid for public and private party number plans ++ * \details ++ * public: ++ * unknown(0), ++ * internationalNumber(1), ++ * nationalNumber(2), ++ * networkSpecificNumber(3) - Reserved, ++ * subscriberNumber(4) - Reserved, ++ * abbreviatedNumber(6) ++ * \details ++ * private: ++ * unknown(0), ++ * level2RegionalNumber(1), ++ * level1RegionalNumber(2), ++ * pTNSpecificNumber/pISNSpecificNumber(3), ++ * localNumber(4), ++ * abbreviatedNumber(6) ++ */ ++ u_int8_t ton; ++ ++ /*! \brief Number present if length is nonzero. */ ++ u_int8_t length; ++ ++ /*! \brief Number string data. */ ++ unsigned char str[20 + 1]; ++}; ++ ++/* ++ * NumberScreened ::= SEQUENCE { ++ * partyNumber PartyNumber, ++ * screeningIndicator ScreeningIndicator ++ * } ++ */ ++struct roseNumberScreened { ++ struct rosePartyNumber number; ++ ++ /*! ++ * \details ++ * userProvidedNotScreened(0), ++ * userProvidedVerifiedAndPassed(1), ++ * userProvidedVerifiedAndFailed(2) (Not used, value reserved), ++ * networkProvided(3) ++ */ ++ u_int8_t screening_indicator; ++}; ++ ++/* ++ * PartySubaddress ::= CHOICE { ++ * -- not recommended ++ * UserSpecifiedSubaddress, ++ * ++ * -- according to ITU-T Recommendation X.213 ++ * NSAPSubaddress ++ * } ++ * ++ * UserSpecifiedSubaddress ::= SEQUENCE { ++ * SubaddressInformation, ++ * ++ * -- used when the coding of subaddress is BCD ++ * oddCountIndicator BOOLEAN OPTIONAL ++ * } ++ * ++ * -- specified according to ITU-T Recommendation X.213. Some ++ * -- networks may limit the subaddress value to some other ++ * -- length, e.g. 4 octets ++ * NSAPSubaddress ::= OCTET STRING (SIZE(1..20)) ++ * ++ * -- coded according to user requirements. Some networks may ++ * -- limit the subaddress value to some other length, ++ * -- e.g. 4 octets ++ * SubaddressInformation ::= OCTET STRING (SIZE(1..20)) ++ */ ++struct rosePartySubaddress { ++ /*! \brief Subaddress type UserSpecified(0), NSAP(1) */ ++ u_int8_t type; ++ ++ /*! \brief Subaddress present if length is nonzero */ ++ u_int8_t length; ++ ++ union { ++ /*! \brief Specified according to ITU-T Recommendation X.213 */ ++ unsigned char nsap[20 + 1]; ++ ++ /*! \brief Use of this formatting is not recommended */ ++ struct { ++ /*! \brief TRUE if OddCount present */ ++ u_int8_t odd_count_present; ++ ++ /*! ++ * \brief TRUE if odd number of BCD digits (optional) ++ * \note Used when the coding of subaddress is BCD. ++ */ ++ u_int8_t odd_count; ++ unsigned char information[20 + 1]; ++ } user_specified; ++ } u; ++}; ++ ++/* ++ * Address ::= SEQUENCE { ++ * PartyNumber, ++ * PartySubaddress OPTIONAL ++ * } ++ */ ++struct roseAddress { ++ struct rosePartyNumber number; ++ ++ /*! \brief Subaddress (Optional) */ ++ struct rosePartySubaddress subaddress; ++}; ++ ++/* ++ * AddressScreened ::= SEQUENCE { ++ * PartyNumber, ++ * ScreeningIndicator, ++ * PartySubaddress OPTIONAL ++ * } ++ */ ++struct roseAddressScreened { ++ struct rosePartyNumber number; ++ ++ /*! \brief Subaddress (Optional) */ ++ struct rosePartySubaddress subaddress; ++ ++ /*! ++ * \details ++ * userProvidedNotScreened(0), ++ * userProvidedVerifiedAndPassed(1), ++ * userProvidedVerifiedAndFailed(2) (Not used, value reserved), ++ * networkProvided(3) ++ */ ++ u_int8_t screening_indicator; ++}; ++ ++/* ++ * PresentedNumberUnscreened ::= CHOICE { ++ * presentationAllowedNumber [0] EXPLICIT PartyNumber, ++ * presentationRestricted [1] IMPLICIT NULL, ++ * numberNotAvailableDueToInterworking [2] IMPLICIT NULL, ++ * presentationRestrictedNumber [3] EXPLICIT PartyNumber ++ * } ++ */ ++struct rosePresentedNumberUnscreened { ++ struct rosePartyNumber number; ++ /*! ++ * \brief Number presentation type ++ * \details ++ * presentationAllowedNumber(0), ++ * presentationRestricted(1), ++ * numberNotAvailableDueToInterworking(2), ++ * presentationRestrictedNumber(3) ++ */ ++ u_int8_t presentation; ++}; ++ ++/* ++ * PresentedNumberScreened ::= CHOICE { ++ * presentationAllowedNumber [0] IMPLICIT NumberScreened, ++ * presentationRestricted [1] IMPLICIT NULL, ++ * numberNotAvailableDueToInterworking [2] IMPLICIT NULL, ++ * presentationRestrictedNumber [3] IMPLICIT NumberScreened ++ * } ++ */ ++struct rosePresentedNumberScreened { ++ /*! \brief Screened number */ ++ struct roseNumberScreened screened; ++ /*! ++ * \brief Number presentation type ++ * \details ++ * presentationAllowedNumber(0), ++ * presentationRestricted(1), ++ * numberNotAvailableDueToInterworking(2), ++ * presentationRestrictedNumber(3) ++ */ ++ u_int8_t presentation; ++}; ++ ++/* ++ * PresentedAddressScreened ::= CHOICE { ++ * presentationAllowedAddress [0] IMPLICIT AddressScreened, ++ * presentationRestricted [1] IMPLICIT NULL, ++ * numberNotAvailableDueToInterworking [2] IMPLICIT NULL, ++ * presentationRestrictedAddress [3] IMPLICIT AddressScreened ++ * } ++ */ ++struct rosePresentedAddressScreened { ++ /*! \breif Screened address */ ++ struct roseAddressScreened screened; ++ /*! ++ * \brief Address presentation type ++ * \details ++ * presentationAllowedAddress(0), ++ * presentationRestricted(1), ++ * numberNotAvailableDueToInterworking(2), ++ * presentationRestrictedAddress(3) ++ */ ++ u_int8_t presentation; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * Time ::= SEQUENCE { ++ * lengthOfTimeUnit [1] IMPLICIT LengthOfTimeUnit, ++ * scale [2] IMPLICIT Scale ++ * } ++ */ ++struct roseEtsiAOCTime { ++ /*! LengthOfTimeUnit ::= INTEGER (0..16777215) -- 24 bit number */ ++ u_int32_t length; ++ /*! ++ * \details ++ * oneHundredthSecond(0), ++ * oneTenthSecond(1), ++ * oneSecond(2), ++ * tenSeconds(3), ++ * oneMinute(4), ++ * oneHour(5), ++ * twentyFourHours(6) ++ */ ++ u_int8_t scale; ++}; ++ ++/* ++ * Amount ::= SEQUENCE { ++ * currencyAmount [1] IMPLICIT CurrencyAmount, ++ * multiplier [2] IMPLICIT Multiplier ++ * } ++ */ ++struct roseEtsiAOCAmount { ++ /*! CurrencyAmount ::= INTEGER (0..16777215) -- 24 bit number */ ++ u_int32_t currency; ++ /*! ++ * \details ++ * oneThousandth(0), ++ * oneHundredth(1), ++ * oneTenth(2), ++ * one(3), ++ * ten(4), ++ * hundred(5), ++ * thousand(6) ++ */ ++ u_int8_t multiplier; ++}; ++ ++/* ++ * DurationCurrency ::= SEQUENCE { ++ * dCurrency [1] IMPLICIT Currency, ++ * dAmount [2] IMPLICIT Amount, ++ * dChargingType [3] IMPLICIT ChargingType, ++ * dTime [4] IMPLICIT Time, ++ * dGranularity [5] IMPLICIT Time OPTIONAL ++ * } ++ */ ++struct roseEtsiAOCDurationCurrency { ++ struct roseEtsiAOCAmount amount; ++ struct roseEtsiAOCTime time; ++ /*! \breif dGranularity (optional) */ ++ struct roseEtsiAOCTime granularity; ++ /*! Currency ::= IA5String (SIZE (1..10)) -- Name of currency. */ ++ unsigned char currency[10 + 1]; ++ /*! ++ * \details ++ * continuousCharging(0), ++ * stepFunction(1) ++ */ ++ u_int8_t charging_type; ++ /*! TRUE if granularity time is present */ ++ u_int8_t granularity_present; ++}; ++ ++/* ++ * FlatRateCurrency ::= SEQUENCE { ++ * fRCurrency [1] IMPLICIT Currency, ++ * fRAmount [2] IMPLICIT Amount ++ * } ++ */ ++struct roseEtsiAOCFlatRateCurrency { ++ struct roseEtsiAOCAmount amount; ++ /*! Currency ::= IA5String (SIZE (1..10)) -- Name of currency. */ ++ unsigned char currency[10 + 1]; ++}; ++ ++/* ++ * VolumeRateCurrency ::= SEQUENCE { ++ * vRCurrency [1] IMPLICIT Currency, ++ * vRAmount [2] IMPLICIT Amount, ++ * vRVolumeUnit [3] IMPLICIT VolumeUnit ++ * } ++ */ ++struct roseEtsiAOCVolumeRateCurrency { ++ struct roseEtsiAOCAmount amount; ++ /*! Currency ::= IA5String (SIZE (1..10)) -- Name of currency. */ ++ unsigned char currency[10 + 1]; ++ /*! ++ * \brief Volume rate volume unit ++ * \details ++ * octet(0), ++ * segment(1), ++ * message(2) ++ */ ++ u_int8_t unit; ++}; ++ ++/* ++ * AOCSCurrencyInfo ::= SEQUENCE { ++ * chargedItem ChargedItem, ++ * CHOICE { ++ * specialChargingCode SpecialChargingCode, ++ * durationCurrency [1] IMPLICIT DurationCurrency, ++ * flatRateCurrency [2] IMPLICIT FlatRateCurrency, ++ * volumeRateCurrency [3] IMPLICIT VolumeRateCurrency ++ * freeOfCharge [4] IMPLICIT NULL, ++ * currencyInfoNotAvailable [5] IMPLICIT NULL ++ * } ++ * } ++ */ ++struct roseEtsiAOCSCurrencyInfo { ++ union { ++ struct roseEtsiAOCDurationCurrency duration; ++ struct roseEtsiAOCFlatRateCurrency flat_rate; ++ struct roseEtsiAOCVolumeRateCurrency volume_rate; ++ /*! SpecialChargingCode ::= INTEGER (1..10) */ ++ u_int8_t special_charging_code; ++ } u; ++ /*! ++ * \brief Determine what is stored in the union. ++ * \details ++ * specialChargingCode(0), ++ * durationCurrency(1), ++ * flatRateCurrency(2), ++ * volumeRateCurrency(3), ++ * freeOfCharge(4), ++ * currencyInfoNotAvailable(5), ++ */ ++ u_int8_t currency_type; ++ /*! ++ * \brief What service is being billed. ++ * \details ++ * basicCommunication(0), ++ * callAttempt(1), ++ * callSetup(2), ++ * userToUserInfo(3), ++ * operationOfSupplementaryServ(4) ++ */ ++ u_int8_t charged_item; ++}; ++ ++/* ++ * AOCSCurrencyInfoList ::= SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo ++ */ ++struct roseEtsiAOCSCurrencyInfoList { ++ /*! \brief SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo */ ++ struct roseEtsiAOCSCurrencyInfo list[10]; ++ ++ /*! \brief Number of AOCSCurrencyInfo records present */ ++ u_int8_t num_records; ++}; ++ ++/* ++ * RecordedCurrency ::= SEQUENCE { ++ * rCurrency [1] IMPLICIT Currency, ++ * rAmount [2] IMPLICIT Amount ++ * } ++ */ ++struct roseEtsiAOCRecordedCurrency { ++ /*! Amount of currency involved. */ ++ struct roseEtsiAOCAmount amount; ++ /*! Currency ::= IA5String (SIZE (1..10)) -- Name of currency. */ ++ unsigned char currency[10 + 1]; ++}; ++ ++/* ++ * RecordedUnits ::= SEQUENCE { ++ * CHOICE { ++ * recordedNumberOfUnits NumberOfUnits, ++ * notAvailable NULL ++ * }, ++ * recordedTypeOfUnits TypeOfUnit OPTIONAL ++ * } ++ */ ++struct roseEtsiAOCRecordedUnits { ++ /*! \brief recordedNumberOfUnits INTEGER (0..16777215) -- 24 bit number */ ++ u_int32_t number_of_units; ++ /*! \brief TRUE if number_of_units is not available (not present) */ ++ u_int8_t not_available; ++ /*! \brief recordedTypeOfUnits INTEGER (1..16) (optional) */ ++ u_int8_t type_of_unit; ++ /*! \brief TRUE if type_of_unit is present */ ++ u_int8_t type_of_unit_present; ++}; ++ ++/* ++ * RecordedUnitsList ::= SEQUENCE SIZE (1..32) OF RecordedUnits ++ */ ++struct roseEtsiAOCRecordedUnitsList { ++ /*! \brief SEQUENCE SIZE (1..32) OF RecordedUnits */ ++ struct roseEtsiAOCRecordedUnits list[32]; ++ ++ /*! \brief Number of RecordedUnits records present */ ++ u_int8_t num_records; ++}; ++ ++/* ++ * ChargingAssociation ::= CHOICE { ++ * chargedNumber [0] EXPLICIT PartyNumber, ++ * chargeIdentifier ChargeIdentifier ++ * } ++ */ ++struct roseEtsiAOCChargingAssociation { ++ /*! chargeIdentifier: INTEGER (-32768..32767) -- 16 bit number */ ++ int16_t id; ++ /*! chargedNumber */ ++ struct rosePartyNumber number; ++ /*! ++ * \details ++ * charge_identifier(0), ++ * charged_number(1) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * AOCECurrencyInfo ::= SEQUENCE { ++ * CHOICE { ++ * freeOfCharge [1] IMPLICIT NULL, ++ * specificCurrency SEQUENCE { ++ * recordedCurrency [1] IMPLICIT RecordedCurrency, ++ * aOCEBillingId [2] IMPLICIT AOCEBillingId OPTIONAL ++ * } ++ * }, ++ * chargingAssociation ChargingAssociation OPTIONAL ++ * } ++ */ ++struct roseEtsiAOCECurrencyInfo { ++ struct { ++ /*! \brief recorded currency */ ++ struct roseEtsiAOCRecordedCurrency recorded; ++ /*! ++ * \brief AOCEBillingId (optional) ++ * \details ++ * normalCharging(0), ++ * reverseCharging(1), ++ * creditCardCharging(2), ++ * callForwardingUnconditional(3), ++ * callForwardingBusy(4), ++ * callForwardingNoReply(5), ++ * callDeflection(6), ++ * callTransfer(7) ++ */ ++ u_int8_t billing_id; ++ /*! \brief TRUE if billing id is present */ ++ u_int8_t billing_id_present; ++ } specific; ++ ++ /*! \brief chargingAssociation (optional) */ ++ struct roseEtsiAOCChargingAssociation charging_association; ++ ++ /*! \brief TRUE if charging_association is present */ ++ u_int8_t charging_association_present; ++ ++ /*! ++ * \brief TRUE if this is free of charge. ++ * \note When TRUE, the contents of specific are not valid. ++ */ ++ u_int8_t free_of_charge; ++}; ++ ++/* ++ * AOCEChargingUnitInfo ::= SEQUENCE { ++ * CHOICE { ++ * freeOfCharge [1] IMPLICIT NULL, ++ * specificChargingUnits SEQUENCE ++ * { ++ * recordedUnitsList [1] IMPLICIT RecordedUnitsList, ++ * aOCEBillingId [2] IMPLICIT AOCEBillingId OPTIONAL ++ * } ++ * }, ++ * chargingAssociation ChargingAssociation OPTIONAL ++ * } ++ */ ++struct roseEtsiAOCEChargingUnitInfo { ++ /*! \brief Not valid if free_of_charge is TRUE */ ++ struct { ++ /*! \brief RecordedUnitsList */ ++ struct roseEtsiAOCRecordedUnitsList recorded; ++ /*! ++ * \brief AOCEBillingId (optional) ++ * \details ++ * normalCharging(0), ++ * reverseCharging(1), ++ * creditCardCharging(2), ++ * callForwardingUnconditional(3), ++ * callForwardingBusy(4), ++ * callForwardingNoReply(5), ++ * callDeflection(6), ++ * callTransfer(7) ++ */ ++ u_int8_t billing_id; ++ /*! \brief TRUE if billing id is present */ ++ u_int8_t billing_id_present; ++ } specific; ++ ++ /*! \brief chargingAssociation (optional) */ ++ struct roseEtsiAOCChargingAssociation charging_association; ++ ++ /*! \brief TRUE if charging_association is present */ ++ u_int8_t charging_association_present; ++ ++ /*! ++ * \brief TRUE if this is free of charge. ++ * \note When TRUE, the contents of specific are not valid. ++ */ ++ u_int8_t free_of_charge; ++}; ++ ++/* ++ * ARGUMENT ChargingCase ++ */ ++struct roseEtsiChargingRequest_ARG { ++ /*! ++ * \details ++ * chargingInformationAtCallSetup(0), ++ * chargingDuringACall(1), ++ * chargingAtTheEndOfACall(2) ++ */ ++ u_int8_t charging_case; ++}; ++ ++/* ++ * RESULT CHOICE { ++ * AOCSCurrencyInfoList, ++ * AOCSSpecialArrInfo, ++ * chargingInfoFollows NULL ++ * } ++ */ ++struct roseEtsiChargingRequest_RES { ++ union { ++ struct roseEtsiAOCSCurrencyInfoList currency_info; ++ ++ /*! AOCSSpecialArrInfo ::= INTEGER (1..10) */ ++ u_int8_t special_arrangement; ++ } u; ++ /*! ++ * \details ++ * currency_info_list(0), ++ * special_arrangement_info(1), ++ * charging_info_follows(2) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * ARGUMENT CHOICE { ++ * chargeNotAvailable NULL, ++ * AOCSCurrencyInfoList ++ * } ++ */ ++struct roseEtsiAOCSCurrency_ARG { ++ struct roseEtsiAOCSCurrencyInfoList currency_info; ++ /*! ++ * \details ++ * charge_not_available(0), ++ * currency_info_list(1) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * ARGUMENT CHOICE { ++ * chargeNotAvailable NULL, ++ * AOCSSpecialArrInfo ++ * } ++ */ ++struct roseEtsiAOCSSpecialArr_ARG { ++ /*! ++ * \details ++ * charge_not_available(0), ++ * special_arrangement_info(1) ++ */ ++ u_int8_t type; ++ /*! AOCSSpecialArrInfo ::= INTEGER (1..10) */ ++ u_int8_t special_arrangement; ++}; ++ ++/* ++ * ARGUMENT CHOICE { ++ * chargeNotAvailable NULL, ++ * aOCDCurrencyInfo CHOICE { ++ * freeOfCharge [1] IMPLICIT NULL, ++ * specificCurrency SEQUENCE { ++ * recordedCurrency [1] IMPLICIT RecordedCurrency, ++ * typeOfChargingInfo [2] IMPLICIT TypeOfChargingInfo, ++ * aOCDBillingId [3] IMPLICIT AOCDBillingId OPTIONAL ++ * } ++ * } ++ * } ++ */ ++struct roseEtsiAOCDCurrency_ARG { ++ struct { ++ /*! \brief recorded currency */ ++ struct roseEtsiAOCRecordedCurrency recorded; ++ /*! ++ * \brief Type of recorded charging information. ++ * \details ++ * subTotal(0), ++ * total(1) ++ */ ++ u_int8_t type_of_charging_info; ++ /*! ++ * \brief AOCDBillingId (optional) ++ * \details ++ * normalCharging(0), ++ * reverseCharging(1), ++ * creditCardCharging(2) ++ */ ++ u_int8_t billing_id; ++ /*! \brief TRUE if billing id is present */ ++ u_int8_t billing_id_present; ++ } specific; ++ /*! ++ * \details ++ * charge_not_available(0), ++ * free_of_charge(1), ++ * specific_currency(2) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * ARGUMENT CHOICE { ++ * chargeNotAvailable NULL, ++ * aOCDChargingUnitInfo CHOICE { ++ * freeOfCharge [1] IMPLICIT NULL, ++ * specificChargingUnits SEQUENCE { ++ * recordedUnitsList [1] IMPLICIT RecordedUnitsList, ++ * typeOfChargingInfo [2] IMPLICIT TypeOfChargingInfo, ++ * aOCDBillingId [3] IMPLICIT AOCDBillingId OPTIONAL ++ * } ++ * } ++ * } ++ */ ++struct roseEtsiAOCDChargingUnit_ARG { ++ struct { ++ /*! \brief RecordedUnitsList */ ++ struct roseEtsiAOCRecordedUnitsList recorded; ++ /*! ++ * \brief Type of recorded charging information. ++ * \details ++ * subTotal(0), ++ * total(1) ++ */ ++ u_int8_t type_of_charging_info; ++ /*! ++ * \brief AOCDBillingId (optional) ++ * \details ++ * normalCharging(0), ++ * reverseCharging(1), ++ * creditCardCharging(2) ++ */ ++ u_int8_t billing_id; ++ /*! \brief TRUE if billing id is present */ ++ u_int8_t billing_id_present; ++ } specific; ++ /*! ++ * \details ++ * charge_not_available(0), ++ * free_of_charge(1), ++ * specific_charging_units(2) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * ARGUMENT CHOICE { ++ * chargeNotAvailable NULL, ++ * AOCECurrencyInfo ++ * } ++ */ ++struct roseEtsiAOCECurrency_ARG { ++ struct roseEtsiAOCECurrencyInfo currency_info; ++ /*! ++ * \details ++ * charge_not_available(0), ++ * currency_info(1) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * ARGUMENT CHOICE { ++ * chargeNotAvailable NULL, ++ * AOCEChargingUnitInfo ++ * } ++ */ ++struct roseEtsiAOCEChargingUnit_ARG { ++ struct roseEtsiAOCEChargingUnitInfo charging_unit; ++ /*! ++ * \details ++ * charge_not_available(0), ++ * charging_unit(1) ++ */ ++ u_int8_t type; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * procedure Procedure, ++ * basicService BasicService, ++ * forwardedToAddress Address, ++ * servedUserNr ServedUserNr ++ * } ++ */ ++struct roseEtsiActivationDiversion_ARG { ++ /*! \brief Forwarded to address */ ++ struct roseAddress forwarded_to; ++ ++ /*! \brief Forward all numbers if not present (Number length is zero). */ ++ struct rosePartyNumber served_user_number; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3k1Hz(3), ++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), ++ * multirate(5), ++ * telephony3k1Hz(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * telephony7kHz(38), ++ * euroFileTransfer(39), ++ * fileTransferAndAccessManagement(40), ++ * videoconference(41), ++ * audioGraphicConference(42) ++ */ ++ u_int8_t basic_service; ++}; ++ ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * procedure Procedure, ++ * basicService BasicService, ++ * servedUserNr ServedUserNr ++ * } ++ */ ++struct roseEtsiDeactivationDiversion_ARG { ++ /*! \brief Forward all numbers if not present (Number length is zero). */ ++ struct rosePartyNumber served_user_number; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3k1Hz(3), ++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), ++ * multirate(5), ++ * telephony3k1Hz(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * telephony7kHz(38), ++ * euroFileTransfer(39), ++ * fileTransferAndAccessManagement(40), ++ * videoconference(41), ++ * audioGraphicConference(42) ++ */ ++ u_int8_t basic_service; ++}; ++ ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * procedure Procedure, ++ * basicService BasicService, ++ * forwardedToAddresss Address, ++ * servedUserNr ServedUserNr ++ * } ++ */ ++struct roseEtsiActivationStatusNotificationDiv_ARG { ++ /*! \brief Forwarded to address */ ++ struct roseAddress forwarded_to; ++ ++ /*! \brief Forward all numbers if not present (Number length is zero). */ ++ struct rosePartyNumber served_user_number; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3k1Hz(3), ++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), ++ * multirate(5), ++ * telephony3k1Hz(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * telephony7kHz(38), ++ * euroFileTransfer(39), ++ * fileTransferAndAccessManagement(40), ++ * videoconference(41), ++ * audioGraphicConference(42) ++ */ ++ u_int8_t basic_service; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * procedure Procedure, ++ * basicService BasicService, ++ * servedUserNr ServedUserNr ++ * } ++ */ ++struct roseEtsiDeactivationStatusNotificationDiv_ARG { ++ /*! \brief Forward all numbers if not present (Number length is zero). */ ++ struct rosePartyNumber served_user_number; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3k1Hz(3), ++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), ++ * multirate(5), ++ * telephony3k1Hz(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * telephony7kHz(38), ++ * euroFileTransfer(39), ++ * fileTransferAndAccessManagement(40), ++ * videoconference(41), ++ * audioGraphicConference(42) ++ */ ++ u_int8_t basic_service; ++}; ++ ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * procedure Procedure, ++ * basicService BasicService DEFAULT allServices, ++ * servedUserNr ServedUserNr ++ * } ++ */ ++struct roseEtsiInterrogationDiversion_ARG { ++ /*! \brief Forward all numbers if not present (Number length is zero). */ ++ struct rosePartyNumber served_user_number; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! ++ * \details ++ * DEFAULT allServices ++ * ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3k1Hz(3), ++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), ++ * multirate(5), ++ * telephony3k1Hz(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * telephony7kHz(38), ++ * euroFileTransfer(39), ++ * fileTransferAndAccessManagement(40), ++ * videoconference(41), ++ * audioGraphicConference(42) ++ */ ++ u_int8_t basic_service; ++}; ++ ++/* ++ * IntResult ::= SEQUENCE { ++ * servedUserNr ServedUserNr, ++ * basicService BasicService, ++ * procedure Procedure, ++ * forwardedToAddress Address ++ * } ++ */ ++struct roseEtsiForwardingRecord { ++ /*! \brief Forwarded to address */ ++ struct roseAddress forwarded_to; ++ ++ /*! \brief Forward all numbers if not present (Number length is zero). */ ++ struct rosePartyNumber served_user_number; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3k1Hz(3), ++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), ++ * multirate(5), ++ * telephony3k1Hz(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * telephony7kHz(38), ++ * euroFileTransfer(39), ++ * fileTransferAndAccessManagement(40), ++ * videoconference(41), ++ * audioGraphicConference(42) ++ */ ++ u_int8_t basic_service; ++}; ++ ++/* ++ * roseInterrogationDiversion_RES ++ * IntResultList ::= SET SIZE (0..29) OF IntResult ++ */ ++struct roseEtsiForwardingList { ++ /*! ++ * \brief SET SIZE (0..29) OF Forwarding Records ++ * \note Reduced the size of the array to conserve ++ * potential stack usage. ++ */ ++ struct roseEtsiForwardingRecord list[10]; ++ ++ /*! \brief Number of Forwarding records present */ ++ u_int8_t num_records; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * diversionReason DiversionReason, ++ * basicService BasicService, ++ * servedUserSubaddress PartySubaddress OPTIONAL, ++ * callingAddress [0] EXPLICIT PresentedAddressScreened OPTIONAL, ++ * originalCalledNr [1] EXPLICIT PresentedNumberUnscreened OPTIONAL, ++ * lastDivertingNr [2] EXPLICIT PresentedNumberUnscreened OPTIONAL, ++ * lastDivertingReason [3] EXPLICIT DiversionReason OPTIONAL, ++ * ++ * -- The User-user information element, as specified ++ * -- in ETS 300 102-1 [11], subclause 4.5.29, shall ++ * -- be embedded in the userInfo parameter. ++ * userInfo Q931InformationElement OPTIONAL ++ * } ++ */ ++struct roseEtsiDiversionInformation_ARG { ++ /*! \brief Served user subaddress (Optional) */ ++ struct rosePartySubaddress served_user_subaddress; ++ ++ /*! \brief Calling address (Optional) */ ++ struct rosePresentedAddressScreened calling; ++ ++ /*! \brief Original called number (Optional) */ ++ struct rosePresentedNumberUnscreened original_called; ++ ++ /*! \brief Last diverting number (Optional) */ ++ struct rosePresentedNumberUnscreened last_diverting; ++ ++ /*! \brief User-User information embedded in Q.931 IE (Optional) */ ++ struct roseQ931ie q931ie; ++ /*! \brief q931ie.contents "allocated" after the stucture. */ ++ unsigned char q931ie_contents[ROSE_Q931_MAX_USER + 1]; ++ ++ /*! ++ * \brief Last diverting reason (Optional) ++ * ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3), ++ * cdAlerting(4), ++ * cdImmediate(5) ++ */ ++ u_int8_t last_diverting_reason; ++ ++ /*! \brief TRUE if CallingAddress is present */ ++ u_int8_t calling_present; ++ ++ /*! \brief TRUE if OriginalCalled is present */ ++ u_int8_t original_called_present; ++ ++ /*! \brief TRUE if LastDiverting is present */ ++ u_int8_t last_diverting_present; ++ ++ /*! \brief TRUE if LastDivertingReason is present */ ++ u_int8_t last_diverting_reason_present; ++ ++ /*! ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3), ++ * cdAlerting(4), ++ * cdImmediate(5) ++ */ ++ u_int8_t diversion_reason; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3k1Hz(3), ++ * unrestrictedDigitalInformationWithTonesAndAnnouncements(4), ++ * multirate(5), ++ * telephony3k1Hz(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * telephony7kHz(38), ++ * euroFileTransfer(39), ++ * fileTransferAndAccessManagement(40), ++ * videoconference(41), ++ * audioGraphicConference(42) ++ */ ++ u_int8_t basic_service; ++}; ++ ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * deflectionAddress Address, ++ * presentationAllowedDivertedToUser PresentationAllowedIndicator OPTIONAL ++ * } ++ */ ++struct roseEtsiCallDeflection_ARG { ++ /*! \brief Deflection address (Deflected-To address) */ ++ struct roseAddress deflection; ++ ++ /*! \brief TRUE if PresentationAllowedToDivertedToUser is present */ ++ u_int8_t presentation_allowed_to_diverted_to_user_present; ++ ++ /*! \brief TRUE if presentation is allowed (Optional) */ ++ u_int8_t presentation_allowed_to_diverted_to_user; ++}; ++ ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * reroutingReason DiversionReason, ++ * calledAddress Address, ++ * reroutingCounter DiversionCounter, ++ * ++ * -- The User-user information element (optional), ++ * -- High layer compatibility information element (optional), ++ * -- Bearer capability information element ++ * -- and Low layer compatibility information element (optional) ++ * -- as specified in ETS 300 102-1 [11] subclause 4.5 shall be ++ * -- embedded in the q931InfoElement. ++ * q931InfoElement Q931InformationElement, ++ * lastReroutingNr [1] EXPLICIT PresentedNumberUnscreened, ++ * subscriptionOption [2] EXPLICIT SubscriptionOption DEFAULT noNotification, ++ * callingPartySubaddress [3] EXPLICIT PartySubaddress OPTIONAL ++ * } ++ */ ++struct roseEtsiCallRerouting_ARG { ++ struct roseAddress called_address; ++ ++ /*! \brief The BC, HLC (optional), LLC (optional), and User-user (optional) information */ ++ struct roseQ931ie q931ie; ++ /*! \brief q931ie.contents "allocated" after the stucture. */ ++ unsigned char q931ie_contents[ROSE_Q931_MAX_BC + ROSE_Q931_MAX_HLC + ++ ROSE_Q931_MAX_LLC + ROSE_Q931_MAX_USER + 1]; ++ ++ /*! \brief Last rerouting number */ ++ struct rosePresentedNumberUnscreened last_rerouting; ++ ++ /*! \brief Calling party subaddress (Optional) */ ++ struct rosePartySubaddress calling_subaddress; ++ ++ /*! ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3), ++ * cdAlerting(4), ++ * cdImmediate(5) ++ */ ++ u_int8_t rerouting_reason; ++ ++ /*! \brief Range 1-5 */ ++ u_int8_t rerouting_counter; ++ ++ /*! ++ * \details ++ * DEFAULT noNotification ++ * ++ * \details ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2) ++ */ ++ u_int8_t subscription_option; ++}; ++ ++ ++/* ++ * roseInterrogateServedUserNumbers_RES ++ * ServedUserNumberList ::= SET SIZE (0..99) OF PartyNumber ++ */ ++struct roseEtsiServedUserNumberList { ++ /*! ++ * \brief SET SIZE (0..99) OF Served user numbers ++ * \note Reduced the size of the array to conserve ++ * potential stack usage. ++ */ ++ struct rosePartyNumber number[20]; ++ ++ /*! \brief Number of Served user numbers present */ ++ u_int8_t num_records; ++}; ++ ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * diversionReason DiversionReason, ++ * subscriptionOption SubscriptionOption, ++ * divertedToNumber PresentedNumberUnscreened OPTIONAL ++ * } ++ */ ++struct roseEtsiDivertingLegInformation1_ARG { ++ /*! \brief Diverted to number (Optional) */ ++ struct rosePresentedNumberUnscreened diverted_to; ++ ++ /*! \brief TRUE if DivertedTo is present */ ++ u_int8_t diverted_to_present; ++ ++ /*! ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3), ++ * cdAlerting(4), ++ * cdImmediate(5) ++ */ ++ u_int8_t diversion_reason; ++ ++ /*! ++ * \details ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2) ++ */ ++ u_int8_t subscription_option; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * diversionCounter DiversionCounter, ++ * diversionReason DiversionReason, ++ * divertingNr [1] EXPLICIT PresentedNumberUnscreened OPTIONAL, ++ * originalCalledNr [2] EXPLICIT PresentedNumberUnscreened OPTIONAL ++ * } ++ */ ++struct roseEtsiDivertingLegInformation2_ARG { ++ /*! \brief Diverting number (Optional) */ ++ struct rosePresentedNumberUnscreened diverting; ++ ++ /*! \brief Original called number (Optional) */ ++ struct rosePresentedNumberUnscreened original_called; ++ ++ /*! \brief TRUE if Diverting number is present */ ++ u_int8_t diverting_present; ++ ++ /*! \brief TRUE if OriginalCalled is present */ ++ u_int8_t original_called_present; ++ ++ /*! ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3), ++ * cdAlerting(4), ++ * cdImmediate(5) ++ */ ++ u_int8_t diversion_reason; ++ ++ /*! \brief Range 1-5 */ ++ u_int8_t diversion_counter; ++}; ++ ++/* ++ * ARGUMENT presentationAllowedIndicator PresentationAllowedIndicator ++ */ ++struct roseEtsiDivertingLegInformation3_ARG { ++ /*! \brief TRUE if presentation is allowed */ ++ u_int8_t presentation_allowed_indicator; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * ARGUMENT LinkId ++ */ ++struct roseEtsiExplicitEctExecute_ARG { ++ int16_t link_id; ++}; ++ ++/* ++ * ARGUMENT transferredToSubaddress PartySubaddress ++ */ ++struct roseEtsiSubaddressTransfer_ARG { ++ /*! \brief Transferred to subaddress */ ++ struct rosePartySubaddress subaddress; ++}; ++ ++ ++/* ++ * RESULT LinkId ++ */ ++struct roseEtsiEctLinkIdRequest_RES { ++ int16_t link_id; ++}; ++ ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * ENUMERATED { ++ * alerting (0), ++ * active (1) ++ * }, ++ * redirectionNumber PresentedNumberUnscreened OPTIONAL ++ * } ++ */ ++struct roseEtsiEctInform_ARG { ++ /*! \brief Redirection Number (Optional) */ ++ struct rosePresentedNumberUnscreened redirection; ++ ++ /*! \brief TRUE if the Redirection Number is present */ ++ u_int8_t redirection_present; ++ ++ /*! \details alerting(0), active(1) */ ++ u_int8_t status; ++}; ++ ++ ++/* ++ * ARGUMENT CallTransferIdentity ++ */ ++struct roseEtsiEctLoopTest_ARG { ++ int8_t call_transfer_id; ++}; ++ ++/* ++ * RESULT LoopResult ++ */ ++struct roseEtsiEctLoopTest_RES { ++ /*! ++ * \details ++ * insufficientInformation(0), ++ * noLoopExists(1), ++ * simultaneousTransfer(2) ++ */ ++ u_int8_t loop_result; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * Name ::= CHOICE { ++ * -- iso8859-1 is implied in namePresentationAllowedSimple. ++ * namePresentationAllowedSimple [0] IMPLICIT NameData, ++ * namePresentationAllowedExtended [1] IMPLICIT NameSet, ++ * ++ * -- iso8859-1 is implied in namePresentationRestrictedSimple. ++ * namePresentationRestrictedSimple [2] IMPLICIT NameData, ++ * namePresentationRestrictedExtended [3] IMPLICIT NameSet, ++ * ++ * -- namePresentationRestrictedNull shall only be used in the ++ * -- case of interworking where the other network provides an ++ * -- indication that the name is restricted without the name itself. ++ * namePresentationRestrictedNull [7] IMPLICIT NULL, ++ * ++ * nameNotAvailable [4] IMPLICIT NULL ++ * } ++ * ++ * NameSet ::= SEQUENCE { ++ * nameData NameData, ++ * ++ * -- If characterSet is not included, iso8859-1 is implied. ++ * characterSet CharacterSet OPTIONAL -- DEFAULT iso8859-1 ++ * } ++ * ++ * -- The maximum allowed size of the name field is 50 octets. ++ * -- The minimum required size of the name field is 1 octet. ++ * NameData ::= OCTET STRING (SIZE (1..50)) ++ */ ++struct roseQsigName { ++ /*! ++ * \details ++ * optional_name_not_present(0), ++ * presentation_allowed(1), ++ * presentation_restricted(2), ++ * presentation_restricted_null(3), ++ * name_not_available(4) ++ */ ++ u_int8_t presentation; ++ ++ /*! ++ * \details ++ * Set to iso8859-1 if not present in the encoding. ++ * ++ * \details ++ * unknown(0), ++ * iso8859-1(1), ++ * enum-value-withdrawn-by-ITU-T(2) ++ * iso8859-2(3), ++ * iso8859-3(4), ++ * iso8859-4(5), ++ * iso8859-5(6), ++ * iso8859-7(7), ++ * iso10646-BmpString(8), ++ * iso10646-utf-8String(9) ++ */ ++ u_int8_t char_set; ++ ++ /*! \brief Length of name data */ ++ u_int8_t length; ++ ++ /*! \brief Name string data */ ++ unsigned char data[50 + 1]; ++}; ++ ++/* ++ * NOTE: We are not going to record the Extension information ++ * since it is manufacturer specific. ++ * ++ * ARGUMENT CHOICE { ++ * Name, ++ * SEQUENCE { ++ * Name, ++ * CHOICE { ++ * [5] IMPLICIT Extension, ++ * [6] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ * } ++ */ ++struct roseQsigPartyName_ARG { ++ struct roseQsigName name; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * Time ::= SEQUENCE { ++ * lengthOfTimeUnit [1] IMPLICIT LengthOfTimeUnit, ++ * scale [2] IMPLICIT Scale ++ * } ++ */ ++struct roseQsigAOCTime { ++ /*! LengthOfTimeUnit ::= INTEGER (0..16777215) -- 24 bit number */ ++ u_int32_t length; ++ /*! ++ * \details ++ * oneHundredthSecond(0), ++ * oneTenthSecond(1), ++ * oneSecond(2), ++ * tenSeconds(3), ++ * oneMinute(4), ++ * oneHour(5), ++ * twentyFourHours(6) ++ */ ++ u_int8_t scale; ++}; ++ ++/* ++ * Amount ::= SEQUENCE { ++ * currencyAmount [1] IMPLICIT CurrencyAmount, ++ * multiplier [2] IMPLICIT Multiplier ++ * } ++ */ ++struct roseQsigAOCAmount { ++ /*! CurrencyAmount ::= INTEGER (0..16777215) -- 24 bit number */ ++ u_int32_t currency; ++ /*! ++ * \details ++ * oneThousandth(0), ++ * oneHundredth(1), ++ * oneTenth(2), ++ * one(3), ++ * ten(4), ++ * hundred(5), ++ * thousand(6) ++ */ ++ u_int8_t multiplier; ++}; ++ ++/* ++ * DurationCurrency ::= SEQUENCE { ++ * dCurrency [1] IMPLICIT Currency, ++ * dAmount [2] IMPLICIT Amount, ++ * dChargingType [3] IMPLICIT ChargingType, ++ * dTime [4] IMPLICIT Time, ++ * dGranularity [5] IMPLICIT Time OPTIONAL ++ * } ++ */ ++struct roseQsigAOCDurationCurrency { ++ struct roseQsigAOCAmount amount; ++ struct roseQsigAOCTime time; ++ /*! \brief dGranularity (optional) */ ++ struct roseQsigAOCTime granularity; ++ /*! ++ * \brief Name of currency ++ * \details ++ * Currency ::= IA5String (SIZE (0..10)) ++ * \note The empty string is the default currency for the network. ++ */ ++ unsigned char currency[10 + 1]; ++ /*! ++ * \details ++ * continuousCharging(0), ++ * stepFunction(1) ++ */ ++ u_int8_t charging_type; ++ /*! TRUE if granularity time is present */ ++ u_int8_t granularity_present; ++}; ++ ++/* ++ * FlatRateCurrency ::= SEQUENCE { ++ * fRCurrency [1] IMPLICIT Currency, ++ * fRAmount [2] IMPLICIT Amount ++ * } ++ */ ++struct roseQsigAOCFlatRateCurrency { ++ struct roseQsigAOCAmount amount; ++ /*! ++ * \brief Name of currency ++ * \details ++ * Currency ::= IA5String (SIZE (0..10)) ++ * \note The empty string is the default currency for the network. ++ */ ++ unsigned char currency[10 + 1]; ++}; ++ ++/* ++ * VolumeRateCurrency ::= SEQUENCE { ++ * vRCurrency [1] IMPLICIT Currency, ++ * vRAmount [2] IMPLICIT Amount, ++ * vRVolumeUnit [3] IMPLICIT VolumeUnit ++ * } ++ */ ++struct roseQsigAOCVolumeRateCurrency { ++ struct roseQsigAOCAmount amount; ++ /*! ++ * \brief Name of currency ++ * \details ++ * Currency ::= IA5String (SIZE (0..10)) ++ * \note The empty string is the default currency for the network. ++ */ ++ unsigned char currency[10 + 1]; ++ /*! ++ * \brief Volume rate volume unit ++ * \details ++ * octet(0), ++ * segment(1), ++ * message(2) ++ */ ++ u_int8_t unit; ++}; ++ ++/* ++ * AOCSCurrencyInfo ::= SEQUENCE { ++ * chargedItem ChargedItem, ++ * rateType CHOICE { ++ * durationCurrency [1] IMPLICIT DurationCurrency, ++ * flatRateCurrency [2] IMPLICIT FlatRateCurrency, ++ * volumeRateCurrency [3] IMPLICIT VolumeRateCurrency, ++ * specialChargingCode SpecialChargingCode, ++ * freeOfCharge [4] IMPLICIT NULL, ++ * currencyInfoNotAvailable [5] IMPLICIT NULL, ++ * freeOfChargefromBeginning [6] IMPLICIT NULL ++ * } ++ * } ++ */ ++struct roseQsigAOCSCurrencyInfo { ++ union { ++ struct roseQsigAOCDurationCurrency duration; ++ struct roseQsigAOCFlatRateCurrency flat_rate; ++ struct roseQsigAOCVolumeRateCurrency volume_rate; ++ /*! SpecialChargingCode ::= INTEGER (1..10) */ ++ u_int8_t special_charging_code; ++ } u; ++ /*! ++ * \brief Determine what is stored in the union. ++ * \details ++ * specialChargingCode(0), ++ * durationCurrency(1), ++ * flatRateCurrency(2), ++ * volumeRateCurrency(3), ++ * freeOfCharge(4), ++ * currencyInfoNotAvailable(5), ++ * freeOfChargeFromBeginning(6) ++ */ ++ u_int8_t currency_type; ++ /*! ++ * \brief What service is being billed. ++ * \details ++ * basicCommunication(0), ++ * callAttempt(1), ++ * callSetup(2), ++ * userToUserInfo(3), ++ * operationOfSupplementaryServ(4) ++ */ ++ u_int8_t charged_item; ++}; ++ ++/* ++ * AOCSCurrencyInfoList ::= SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo ++ */ ++struct roseQsigAOCSCurrencyInfoList { ++ /*! \brief SEQUENCE SIZE (1..10) OF AOCSCurrencyInfo */ ++ struct roseQsigAOCSCurrencyInfo list[10]; ++ ++ /*! \brief Number of AOCSCurrencyInfo records present */ ++ u_int8_t num_records; ++}; ++ ++/* ++ * RecordedCurrency ::= SEQUENCE { ++ * rCurrency [1] IMPLICIT Currency, ++ * rAmount [2] IMPLICIT Amount ++ * } ++ */ ++struct roseQsigAOCRecordedCurrency { ++ /*! Amount of currency involved. */ ++ struct roseQsigAOCAmount amount; ++ /*! ++ * \brief Name of currency ++ * \details ++ * Currency ::= IA5String (SIZE (0..10)) ++ * \note The empty string is the default currency for the network. ++ */ ++ unsigned char currency[10 + 1]; ++}; ++ ++/* ++ * ChargingAssociation ::= CHOICE { ++ * chargedNumber [0] EXPLICIT PartyNumber, ++ * chargeIdentifier ChargeIdentifier ++ * } ++ */ ++struct roseQsigAOCChargingAssociation { ++ /*! chargeIdentifier: INTEGER (-32768..32767) -- 16 bit number */ ++ int16_t id; ++ /*! chargedNumber */ ++ struct rosePartyNumber number; ++ /*! ++ * \details ++ * charge_identifier(0) ++ * charged_number(1), ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * AocRateArg ::= SEQUENCE { ++ * aocRate CHOICE ++ * { ++ * chargeNotAvailable NULL, ++ * aocSCurrencyInfoList AOCSCurrencyInfoList ++ * }, ++ * rateArgExtension CHOICE { ++ * extension [1] IMPLICIT Extension, ++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigAocRateArg_ARG { ++ struct roseQsigAOCSCurrencyInfoList currency_info; ++ /*! ++ * \details ++ * charge_not_available(0), ++ * currency_info_list(1) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * AocInterimArg ::= SEQUENCE { ++ * interimCharge CHOICE { ++ * chargeNotAvailable [0] IMPLICIT NULL, ++ * freeOfCharge [1] IMPLICIT NULL, ++ * specificCurrency SEQUENCE { ++ * recordedCurrency [1] IMPLICIT RecordedCurrency, ++ * interimBillingId [2] IMPLICIT InterimBillingId OPTIONAL ++ * } ++ * }, ++ * interimArgExtension CHOICE { ++ * extension [1] IMPLICIT Extension, ++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigAocInterimArg_ARG { ++ struct { ++ /*! \brief recorded currency */ ++ struct roseQsigAOCRecordedCurrency recorded; ++ /*! ++ * \brief InterimBillingId (optional) ++ * \details ++ * normalCharging(0), ++ * creditCardCharging(2) ++ */ ++ u_int8_t billing_id; ++ /*! \brief TRUE if billing id is present */ ++ u_int8_t billing_id_present; ++ } specific; ++ /*! ++ * \details ++ * charge_not_available(0), ++ * free_of_charge(1), ++ * specific_currency(2) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * AocFinalArg ::= SEQUENCE { ++ * finalCharge CHOICE { ++ * chargeNotAvailable [0] IMPLICIT NULL, ++ * freeOfCharge [1] IMPLICIT NULL, ++ * specificCurrency SEQUENCE { ++ * recordedCurrency [1] IMPLICIT RecordedCurrency, ++ * finalBillingId [2] IMPLICIT FinalBillingId OPTIONAL ++ * } ++ * }, ++ * chargingAssociation ChargingAssociation OPTIONAL, ++ * finalArgExtension CHOICE { ++ * extension [1] IMPLICIT Extension, ++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigAocFinalArg_ARG { ++ struct { ++ /*! \brief recorded currency */ ++ struct roseQsigAOCRecordedCurrency recorded; ++ /*! ++ * \brief FinalBillingId (optional) ++ * \details ++ * normalCharging(0), ++ * creditCardCharging(2), ++ * callForwardingUnconditional(3), ++ * callForwardingBusy(4), ++ * callForwardingNoReply(5), ++ * callDeflection(6), ++ * callTransfer(7) ++ */ ++ u_int8_t billing_id; ++ /*! \brief TRUE if billing id is present */ ++ u_int8_t billing_id_present; ++ } specific; ++ ++ /*! \brief chargingAssociation (optional) */ ++ struct roseQsigAOCChargingAssociation charging_association; ++ ++ /*! \brief TRUE if charging_association is present */ ++ u_int8_t charging_association_present; ++ ++ /*! ++ * \details ++ * charge_not_available(0), ++ * free_of_charge(1), ++ * specific_currency(2) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * ChargeRequestArg ::= SEQUENCE { ++ * adviceModeCombinations SEQUENCE SIZE(0..7) OF AdviceModeCombination, ++ * chargeReqArgExtension CHOICE { ++ * extension [1] IMPLICIT Extension, ++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigChargeRequestArg_ARG { ++ /*! ++ * \brief SEQUENCE SIZE(0..7) OF AdviceModeCombination ++ * \details ++ * rate(0) <charge rate provision>, ++ * rateInterim(1) <charge rate and interim charge provision>, ++ * rateFinal(2) <charge rate and final charge provision>, ++ * interim(3) <interim charge provision>, ++ * final(4) <final charge provision>, ++ * interimFinal(5) <interim charge and final charge provision>, ++ * rateInterimFinal(6) <charge rate, interim charge and final charge provision> ++ */ ++ u_int8_t advice_mode_combinations[7]; ++ ++ /*! \brief Number of AdviceModeCombination values present */ ++ u_int8_t num_records; ++}; ++ ++/* ++ * ChargeRequestRes ::= SEQUENCE { ++ * adviceModeCombination AdviceModeCombination, ++ * chargeReqResExtension CHOICE { ++ * extension [1] IMPLICIT Extension, ++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigChargeRequestRes_RES { ++ /*! ++ * \details ++ * rate(0) <charge rate provision>, ++ * rateInterim(1) <charge rate and interim charge provision>, ++ * rateFinal(2) <charge rate and final charge provision>, ++ * interim(3) <interim charge provision>, ++ * final(4) <final charge provision>, ++ * interimFinal(5) <interim charge and final charge provision>, ++ * rateInterimFinal(6) <charge rate, interim charge and final charge provision> ++ */ ++ u_int8_t advice_mode_combination; ++}; ++ ++/* ++ * AocCompleteArg ::= SEQUENCE { ++ * chargedUser PartyNumber, ++ * chargingAssociation ChargingAssociation OPTIONAL, ++ * completeArgExtension CHOICE { ++ * extension [1] IMPLICIT Extension, ++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigAocCompleteArg_ARG { ++ /*! \brief chargingAssociation (optional) */ ++ struct roseQsigAOCChargingAssociation charging_association; ++ ++ struct rosePartyNumber charged_user_number; ++ ++ /*! \brief TRUE if charging_association is present */ ++ u_int8_t charging_association_present; ++}; ++ ++/* ++ * AocCompleteRes ::= SEQUENCE { ++ * chargingOption ChargingOption, ++ * completeResExtension CHOICE { ++ * extension [1] IMPLICIT Extension, ++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigAocCompleteRes_RES { ++ /*! ++ * \details ++ * aocFreeOfCharge(0), ++ * aocContinueCharging(1), ++ * aocStopCharging(2) ++ */ ++ u_int8_t charging_option; ++}; ++ ++/* ++ * AocDivChargeReqArg ::= SEQUENCE { ++ * divertingUser PartyNumber, ++ * chargingAssociation ChargingAssociation OPTIONAL, ++ * diversionType DiversionType, ++ * aocDivChargeReqArgExt CHOICE { ++ * extension [1] IMPLICIT Extension, ++ * multipleExtension [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigAocDivChargeReqArg_ARG { ++ /*! \brief chargingAssociation (optional) */ ++ struct roseQsigAOCChargingAssociation charging_association; ++ ++ struct rosePartyNumber diverting_user_number; ++ ++ /*! \brief TRUE if charging_association is present */ ++ u_int8_t charging_association_present; ++ ++ /*! ++ * \details ++ * callForwardingUnconditional(0), ++ * callForwardingBusy(1), ++ * callForwardingNoReply(2), ++ * callDeflection(3) ++ */ ++ u_int8_t diversion_type; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * CTIdentifyRes ::= SEQUENCE { ++ * callIdentity CallIdentity, ++ * reroutingNumber PartyNumber, ++ * resultExtension CHOICE { ++ * [6] IMPLICIT Extension, ++ * [7] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigCTIdentifyRes_RES { ++ struct rosePartyNumber rerouting_number; ++ ++ /*! \brief CallIdentity ::= NumericString (SIZE (1..4)) */ ++ unsigned char call_id[4 + 1]; ++}; ++ ++/* ++ * CTInitiateArg ::= SEQUENCE { ++ * callIdentity CallIdentity, ++ * reroutingNumber PartyNumber, ++ * argumentExtension CHOICE { ++ * [6] IMPLICIT Extension, ++ * [7] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigCTInitiateArg_ARG { ++ struct rosePartyNumber rerouting_number; ++ ++ /*! \brief CallIdentity ::= NumericString (SIZE (1..4)) */ ++ unsigned char call_id[4 + 1]; ++}; ++ ++/* ++ * CTSetupArg ::= SEQUENCE { ++ * callIdentity CallIdentity, ++ * argumentExtension CHOICE { ++ * [0] IMPLICIT Extension, ++ * [1] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigCTSetupArg_ARG { ++ /*! \brief CallIdentity ::= NumericString (SIZE (1..4)) */ ++ unsigned char call_id[4 + 1]; ++}; ++ ++/* ++ * CTActiveArg ::= SEQUENCE { ++ * connectedAddress PresentedAddressScreened, ++ * ++ * -- ISO/IEC 11572 information elements Party ++ * -- category and Progress indicator are conveyed ++ * basicCallInfoElements PSS1InformationElement OPTIONAL, ++ * connectedName Name OPTIONAL, ++ * argumentExtension CHOICE { ++ * [9] IMPLICIT Extension, ++ * [10] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigCTActiveArg_ARG { ++ /*! \brief connectedAddress */ ++ struct rosePresentedAddressScreened connected; ++ ++ /*! \brief basicCallInfoElements (optional) */ ++ struct roseQ931ie q931ie; ++ /*! \brief q931ie.contents "allocated" after the stucture. */ ++ unsigned char q931ie_contents[ROSE_Q931_MAX_PROGRESS + 1]; ++ ++ /*! \brief connectedName (optional) */ ++ struct roseQsigName connected_name; ++ ++ /*! \brief TRUE if connected_name is present */ ++ u_int8_t connected_name_present; ++}; ++ ++/* ++ * CTCompleteArg ::= SEQUENCE { ++ * endDesignation EndDesignation, ++ * redirectionNumber PresentedNumberScreened, ++ * ++ * -- ISO/IEC 11572 information elements Party ++ * -- category and Progress indicator are conveyed ++ * basicCallInfoElements PSS1InformationElement OPTIONAL, ++ * redirectionName Name OPTIONAL, ++ * callStatus CallStatus DEFAULT answered, ++ * argumentExtension CHOICE { ++ * [9] IMPLICIT Extension, ++ * [10] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigCTCompleteArg_ARG { ++ /*! \brief redirectionNumber */ ++ struct rosePresentedNumberScreened redirection; ++ ++ /*! \brief basicCallInfoElements (optional) */ ++ struct roseQ931ie q931ie; ++ /*! \brief q931ie.contents "allocated" after the stucture. */ ++ unsigned char q931ie_contents[ROSE_Q931_MAX_PROGRESS + 1]; ++ ++ /*! \brief redirectionName (optional) */ ++ struct roseQsigName redirection_name; ++ ++ /*! \brief TRUE if redirection_name is present */ ++ u_int8_t redirection_name_present; ++ ++ /*! ++ * \brief endDesignation ++ * \details ++ * primaryEnd(0), ++ * secondaryEnd(1) ++ */ ++ u_int8_t end_designation; ++ ++ /*! ++ * \brief callStatus ++ * \details ++ * DEFAULT answered ++ * ++ * \details ++ * answered(0), ++ * alerting(1) ++ */ ++ u_int8_t call_status; ++}; ++ ++/* ++ * CTUpdateArg ::= SEQUENCE { ++ * redirectionNumber PresentedNumberScreened, ++ * redirectionName Name OPTIONAL, ++ * ++ * -- ISO/IEC 11572 information elements Party ++ * -- category and Progress indicator are conveyed ++ * basicCallInfoElements PSS1InformationElement OPTIONAL, ++ * argumentExtension CHOICE { ++ * [9] IMPLICIT Extension, ++ * [10] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigCTUpdateArg_ARG { ++ /*! \brief redirectionNumber */ ++ struct rosePresentedNumberScreened redirection; ++ ++ /*! \brief basicCallInfoElements (optional) */ ++ struct roseQ931ie q931ie; ++ /*! \brief q931ie.contents "allocated" after the stucture. */ ++ unsigned char q931ie_contents[ROSE_Q931_MAX_PROGRESS + 1]; ++ ++ /*! \brief redirectionName (optional) */ ++ struct roseQsigName redirection_name; ++ ++ /*! \brief TRUE if redirection_name is present */ ++ u_int8_t redirection_name_present; ++}; ++ ++/* ++ * SubaddressTransferArg ::= SEQUENCE { ++ * redirectionSubaddress PartySubaddress, ++ * argumentExtension CHOICE { ++ * [0] IMPLICIT Extension, ++ * [1] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigSubaddressTransferArg_ARG { ++ struct rosePartySubaddress redirection_subaddress; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * IntResult ::= SEQUENCE { ++ * servedUserNr PartyNumber, ++ * basicService BasicService, ++ * procedure Procedure, ++ * divertedToAddress Address, ++ * remoteEnabled BOOLEAN DEFAULT FALSE, ++ * extension CHOICE { ++ * [1] IMPLICIT Extension, ++ * [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigForwardingRecord { ++ /*! \brief Diverted to address */ ++ struct roseAddress diverted_to; ++ ++ struct rosePartyNumber served_user_number; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3100Hz(3), ++ * telephony(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36) ++ */ ++ u_int8_t basic_service; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! \brief remoteEnabled BOOLEAN DEFAULT FALSE */ ++ u_int8_t remote_enabled; ++}; ++ ++/* ++ * roseQsigInterrogateDiversionQ_REQ ++ * IntResultList ::= SET SIZE (0..29) OF IntResult ++ */ ++struct roseQsigForwardingList { ++ /*! ++ * \brief SET SIZE (0..29) OF Forwarding Records ++ * \note Reduced the size of the array to conserve ++ * potential stack usage. ++ */ ++ struct roseQsigForwardingRecord list[10]; ++ ++ /*! \brief Number of Forwarding records present */ ++ u_int8_t num_records; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * procedure Procedure, ++ * basicService BasicService, ++ * divertedToAddress Address, ++ * servedUserNr PartyNumber, ++ * activatingUserNr PartyNumber, ++ * extension CHOICE { ++ * [1] IMPLICIT Extension, ++ * [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigActivateDiversionQ_ARG { ++ /*! \brief divertedToAddress */ ++ struct roseAddress diverted_to; ++ ++ struct rosePartyNumber served_user_number; ++ struct rosePartyNumber activating_user_number; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3100Hz(3), ++ * telephony(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36) ++ */ ++ u_int8_t basic_service; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * procedure Procedure, ++ * basicService BasicService, ++ * servedUserNr PartyNumber, ++ * deactivatingUserNr PartyNumber, ++ * extension CHOICE { ++ * [1] IMPLICIT Extension, ++ * [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigDeactivateDiversionQ_ARG { ++ struct rosePartyNumber served_user_number; ++ struct rosePartyNumber deactivating_user_number; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3100Hz(3), ++ * telephony(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36) ++ */ ++ u_int8_t basic_service; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * procedure Procedure, ++ * basicService BasicService DEFAULT allServices, ++ * servedUserNr PartyNumber, ++ * interrogatingUserNr PartyNumber, ++ * extension CHOICE { ++ * [1] IMPLICIT Extension, ++ * [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigInterrogateDiversionQ_ARG { ++ struct rosePartyNumber served_user_number; ++ struct rosePartyNumber interrogating_user_number; ++ ++ /*! \details cfu(0), cfb(1), cfnr(2) */ ++ u_int8_t procedure; ++ ++ /*! ++ * \details ++ * DEFAULT allServices ++ * ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3100Hz(3), ++ * telephony(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36) ++ */ ++ u_int8_t basic_service; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * servedUserNr PartyNumber, ++ * basicService BasicService, ++ * divertedToNr PartyNumber, ++ * extension CHOICE { ++ * [1] IMPLICIT Extension, ++ * [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigCheckRestriction_ARG { ++ struct rosePartyNumber served_user_number; ++ struct rosePartyNumber diverted_to_number; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3100Hz(3), ++ * telephony(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotexSyntaxBased(35), ++ * videotelephony(36) ++ */ ++ u_int8_t basic_service; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * reroutingReason DiversionReason, ++ * originalReroutingReason [0] IMPLICIT DiversionReason OPTIONAL, ++ * calledAddress Address, ++ * diversionCounter INTEGER (1..15), ++ * ++ * -- The basic call information elements Bearer capability, ++ * -- High layer compatibility, Low layer compatibity ++ * -- and Progress indicator can be embedded in the ++ * -- pSS1InfoElement in accordance with 6.5.3.1.5. ++ * pSS1InfoElement PSS1InformationElement, ++ * lastReroutingNr [1] EXPLICIT PresentedNumberUnscreened, ++ * subscriptionOption [2] IMPLICIT SubscriptionOption, ++ * callingPartySubaddress [3] EXPLICIT PartySubaddress OPTIONAL, ++ * callingNumber [4] EXPLICIT PresentedNumberScreened, ++ * callingName [5] EXPLICIT Name OPTIONAL, ++ * originalCalledNr [6] EXPLICIT PresentedNumberUnscreened OPTIONAL, ++ * redirectingName [7] EXPLICIT Name OPTIONAL, ++ * originalCalledName [8] EXPLICIT Name OPTIONAL, ++ * extension CHOICE { ++ * [9] IMPLICIT Extension, ++ * [10] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigCallRerouting_ARG { ++ /*! \brief calledAddress */ ++ struct roseAddress called; ++ ++ /*! \brief lastReroutingNr */ ++ struct rosePresentedNumberUnscreened last_rerouting; ++ ++ /*! \brief originalCalledNr (optional) */ ++ struct rosePresentedNumberUnscreened original_called; ++ ++ /*! ++ * \brief callingPartySubaddress (optional) ++ * The subaddress is present if the length is nonzero. ++ */ ++ struct rosePartySubaddress calling_subaddress; ++ ++ /*! \brief callingNumber */ ++ struct rosePresentedNumberScreened calling; ++ ++ /*! \brief callingName (optional) */ ++ struct roseQsigName calling_name; ++ ++ /*! \brief redirectingName (optional) */ ++ struct roseQsigName redirecting_name; ++ ++ /*! \brief originalCalledName (optional) */ ++ struct roseQsigName original_called_name; ++ ++ /*! ++ * \brief The BC, HLC (optional), LLC (optional), ++ * and progress indicator(s) information. ++ */ ++ struct roseQ931ie q931ie; ++ /*! \brief q931ie.contents "allocated" after the stucture. */ ++ unsigned char q931ie_contents[ROSE_Q931_MAX_BC + ROSE_Q931_MAX_HLC + ++ ROSE_Q931_MAX_LLC + ROSE_Q931_MAX_PROGRESS + 1]; ++ ++ /*! \brief TRUE if calling_name is present */ ++ u_int8_t calling_name_present; ++ ++ /*! \brief TRUE if redirecting_name is present */ ++ u_int8_t redirecting_name_present; ++ ++ /*! \brief TRUE if original_called_name is present */ ++ u_int8_t original_called_name_present; ++ ++ /*! \brief TRUE if original_called number is present */ ++ u_int8_t original_called_present; ++ ++ /*! ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3) ++ * ++ * \note The value unknown is only used if received from ++ * another network when interworking. ++ */ ++ u_int8_t rerouting_reason; ++ ++ /*! ++ * \brief originalReroutingReason (optional) ++ * ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3) ++ * ++ * \note The value unknown is only used if received from ++ * another network when interworking. ++ */ ++ u_int8_t original_rerouting_reason; ++ ++ /*! \brief TRUE if original_rerouting_reason is present */ ++ u_int8_t original_rerouting_reason_present; ++ ++ /*! \brief diversionCounter INTEGER (1..15) */ ++ u_int8_t diversion_counter; ++ ++ /*! ++ * \brief subscriptionOption ++ * ++ * \details ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2) ++ */ ++ u_int8_t subscription_option; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * diversionReason DiversionReason, ++ * subscriptionOption SubscriptionOption, ++ * nominatedNr PartyNumber, ++ * extension CHOICE { ++ * [9] IMPLICIT Extension, ++ * [10] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigDivertingLegInformation1_ARG { ++ struct rosePartyNumber nominated_number; ++ ++ /*! ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3) ++ * ++ * \note The value unknown is only used if received from ++ * another network when interworking. ++ */ ++ u_int8_t diversion_reason; ++ ++ /*! ++ * \brief subscriptionOption ++ * ++ * \details ++ * noNotification(0), ++ * notificationWithoutDivertedToNr(1), ++ * notificationWithDivertedToNr(2) ++ */ ++ u_int8_t subscription_option; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * diversionCounter INTEGER (1..15), ++ * diversionReason DiversionReason, ++ * originalDiversionReason [0] IMPLICIT DiversionReason OPTIONAL, ++ * ++ * -- The divertingNr element is mandatory except in the case ++ * -- of interworking. ++ * divertingNr [1] EXPLICIT PresentedNumberUnscreened OPTIONAL, ++ * originalCalledNr [2] EXPLICIT PresentedNumberUnscreened OPTIONAL, ++ * redirectingName [3] EXPLICIT Name OPTIONAL, ++ * originalCalledName [4] EXPLICIT Name OPTIONAL, ++ * extension CHOICE { ++ * [5] IMPLICIT Extension, ++ * [6] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigDivertingLegInformation2_ARG { ++ /*! \brief divertingNr (optional) */ ++ struct rosePresentedNumberUnscreened diverting; ++ ++ /*! \brief originalCalledNr (optional) */ ++ struct rosePresentedNumberUnscreened original_called; ++ ++ /*! \brief redirectingName (optional) */ ++ struct roseQsigName redirecting_name; ++ ++ /*! \brief originalCalledName (optional) */ ++ struct roseQsigName original_called_name; ++ ++ /*! \brief diversionCounter INTEGER (1..15) */ ++ u_int8_t diversion_counter; ++ ++ /*! ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3) ++ * ++ * \note The value unknown is only used if received from ++ * another network when interworking. ++ */ ++ u_int8_t diversion_reason; ++ ++ /*! ++ * \brief originalDiversionReason (optional) ++ * ++ * \details ++ * unknown(0), ++ * cfu(1), ++ * cfb(2), ++ * cfnr(3) ++ * ++ * \note The value unknown is only used if received from ++ * another network when interworking. ++ */ ++ u_int8_t original_diversion_reason; ++ ++ /*! \brief TRUE if original_diversion_reason is present */ ++ u_int8_t original_diversion_reason_present; ++ ++ /*! \brief TRUE if diverting number is present */ ++ u_int8_t diverting_present; ++ ++ /*! \brief TRUE if original_called number is present */ ++ u_int8_t original_called_present; ++ ++ /*! \brief TRUE if redirecting_name is present */ ++ u_int8_t redirecting_name_present; ++ ++ /*! \brief TRUE if original_called_name is present */ ++ u_int8_t original_called_name_present; ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * presentationAllowedIndicator PresentationAllowedIndicator, -- BOOLEAN ++ * redirectionName [0] EXPLICIT Name OPTIONAL, ++ * extension CHOICE { ++ * [1] IMPLICIT Extension, ++ * [2] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigDivertingLegInformation3_ARG { ++ /*! \brief redirectionName (optional) */ ++ struct roseQsigName redirection_name; ++ ++ /*! \brief TRUE if redirection_name is present */ ++ u_int8_t redirection_name_present; ++ ++ /*! \brief TRUE if presentation is allowed */ ++ u_int8_t presentation_allowed_indicator; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * MsgCentreId ::= CHOICE { ++ * integer [0] IMPLICIT INTEGER (0..65535), ++ * ++ * -- The party number must be a complete number as required ++ * -- for routing purposes. ++ * partyNumber [1] EXPLICIT PartyNumber, ++ * numericString [2] IMPLICIT NumericString (SIZE (1..10)) ++ * } ++ */ ++struct roseQsigMsgCentreId { ++ union { ++ /*! \brief INTEGER (0..65535) */ ++ u_int16_t integer; ++ ++ /*! ++ * \note The party number must be a complete number as required ++ * for routing purposes. ++ */ ++ struct rosePartyNumber number; ++ ++ /*! \brief NumericString (SIZE (1..10)) */ ++ unsigned char str[10 + 1]; ++ } u; ++ ++ /*! ++ * \details ++ * integer(0), ++ * partyNumber(1), ++ * numericString(2) ++ */ ++ u_int8_t type; ++}; ++ ++/* ++ * MWIActivateArg ::= SEQUENCE { ++ * servedUserNr PartyNumber, ++ * basicService BasicService, ++ * msgCentreId MsgCentreId OPTIONAL, ++ * nbOfMessages [3] IMPLICIT NbOfMessages OPTIONAL, ++ * originatingNr [4] EXPLICIT PartyNumber OPTIONAL, ++ * timestamp TimeStamp OPTIONAL, ++ * ++ * -- The value 0 means the highest priority and 9 the lowest ++ * priority [5] IMPLICIT INTEGER (0..9) OPTIONAL, ++ * argumentExt CHOICE { ++ * extension [6] IMPLICIT Extension, ++ * multipleExtension [7] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigMWIActivateArg { ++ /*! \brief NbOfMessages ::= INTEGER (0..65535) (optional) */ ++ u_int16_t number_of_messages; ++ ++ /*! \brief msgCentreId (optional) */ ++ struct roseQsigMsgCentreId msg_centre_id; ++ ++ struct rosePartyNumber served_user_number; ++ ++ /*! \brief originatingNr (optional) (Number present if length is nonzero) */ ++ struct rosePartyNumber originating_number; ++ ++ /*! \brief GeneralizedTime (SIZE (12..19)) (optional) */ ++ unsigned char timestamp[19 + 1]; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3100Hz(3), ++ * telephony(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotextSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * reservedNotUsed1(38), ++ * reservedNotUsed2(39), ++ * reservedNotUsed3(40), ++ * reservedNotUsed4(41), ++ * reservedNotUsed5(42), ++ * email(51), ++ * video(52), ++ * fileTransfer(53), ++ * shortMessageService(54), ++ * speechAndVideo(55), ++ * speechAndFax(56), ++ * speechAndEmail(57), ++ * videoAndFax(58), ++ * videoAndEmail(59), ++ * faxAndEmail(60), ++ * speechVideoAndFax(61), ++ * speechVideoAndEmail(62), ++ * speechFaxAndEmail(63), ++ * videoFaxAndEmail(64), ++ * speechVideoFaxAndEmail(65), ++ * multimediaUnknown(66), ++ * serviceUnknown(67), ++ * futureReserve1(68), ++ * futureReserve2(69), ++ * futureReserve3(70), ++ * futureReserve4(71), ++ * futureReserve5(72), ++ * futureReserve6(73), ++ * futureReserve7(74), ++ * futureReserve8(75) ++ */ ++ u_int8_t basic_service; ++ ++ /*! ++ * \brief INTEGER (0..9) (optional) ++ * \note The value 0 means the highest priority and 9 the lowest. ++ */ ++ u_int8_t priority; ++ ++ /*! \brief TRUE if msg_centre_id is present */ ++ u_int8_t msg_centre_id_present; ++ ++ /*! \brief TRUE if number_of_messages is present */ ++ u_int8_t number_of_messages_present; ++ ++ /*! \brief TRUE if timestamp is present */ ++ u_int8_t timestamp_present; ++ ++ /*! \brief TRUE if priority is present */ ++ u_int8_t priority_present; ++}; ++ ++/* ++ * MWIDeactivateArg ::= SEQUENCE { ++ * servedUserNr PartyNumber, ++ * basicService BasicService, ++ * msgCentreId MsgCentreId OPTIONAL, ++ * argumentExt CHOICE { ++ * extension [3] IMPLICIT Extension, ++ * multipleExtension [4] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigMWIDeactivateArg { ++ /*! \brief msgCentreId (optional) */ ++ struct roseQsigMsgCentreId msg_centre_id; ++ ++ struct rosePartyNumber served_user_number; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3100Hz(3), ++ * telephony(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotextSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * reservedNotUsed1(38), ++ * reservedNotUsed2(39), ++ * reservedNotUsed3(40), ++ * reservedNotUsed4(41), ++ * reservedNotUsed5(42), ++ * email(51), ++ * video(52), ++ * fileTransfer(53), ++ * shortMessageService(54), ++ * speechAndVideo(55), ++ * speechAndFax(56), ++ * speechAndEmail(57), ++ * videoAndFax(58), ++ * videoAndEmail(59), ++ * faxAndEmail(60), ++ * speechVideoAndFax(61), ++ * speechVideoAndEmail(62), ++ * speechFaxAndEmail(63), ++ * videoFaxAndEmail(64), ++ * speechVideoFaxAndEmail(65), ++ * multimediaUnknown(66), ++ * serviceUnknown(67), ++ * futureReserve1(68), ++ * futureReserve2(69), ++ * futureReserve3(70), ++ * futureReserve4(71), ++ * futureReserve5(72), ++ * futureReserve6(73), ++ * futureReserve7(74), ++ * futureReserve8(75) ++ */ ++ u_int8_t basic_service; ++ ++ /*! \brief TRUE if msg_centre_id is present */ ++ u_int8_t msg_centre_id_present; ++}; ++ ++/* ++ * MWIInterrogateArg ::= SEQUENCE { ++ * servedUserNr PartyNumber, ++ * basicService BasicService, ++ * msgCentreId MsgCentreId OPTIONAL, ++ * argumentExt CHOICE { ++ * extension [3] IMPLICIT Extension, ++ * multipleExtension [4] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigMWIInterrogateArg { ++ /*! \brief msgCentreId (optional) */ ++ struct roseQsigMsgCentreId msg_centre_id; ++ ++ struct rosePartyNumber served_user_number; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3100Hz(3), ++ * telephony(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotextSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * reservedNotUsed1(38), ++ * reservedNotUsed2(39), ++ * reservedNotUsed3(40), ++ * reservedNotUsed4(41), ++ * reservedNotUsed5(42), ++ * email(51), ++ * video(52), ++ * fileTransfer(53), ++ * shortMessageService(54), ++ * speechAndVideo(55), ++ * speechAndFax(56), ++ * speechAndEmail(57), ++ * videoAndFax(58), ++ * videoAndEmail(59), ++ * faxAndEmail(60), ++ * speechVideoAndFax(61), ++ * speechVideoAndEmail(62), ++ * speechFaxAndEmail(63), ++ * videoFaxAndEmail(64), ++ * speechVideoFaxAndEmail(65), ++ * multimediaUnknown(66), ++ * serviceUnknown(67), ++ * futureReserve1(68), ++ * futureReserve2(69), ++ * futureReserve3(70), ++ * futureReserve4(71), ++ * futureReserve5(72), ++ * futureReserve6(73), ++ * futureReserve7(74), ++ * futureReserve8(75) ++ */ ++ u_int8_t basic_service; ++ ++ /*! \brief TRUE if msg_centre_id is present */ ++ u_int8_t msg_centre_id_present; ++}; ++ ++/* ++ * MWIInterrogateResElt ::= SEQUENCE { ++ * basicService BasicService, ++ * msgCentreId MsgCentreId OPTIONAL, ++ * nbOfMessages [3] IMPLICIT NbOfMessages OPTIONAL, ++ * originatingNr [4] EXPLICIT PartyNumber OPTIONAL, ++ * timestamp TimeStamp OPTIONAL, ++ * ++ * -- The value 0 means the highest priority and 9 the lowest ++ * priority [5] IMPLICIT INTEGER (0..9) OPTIONAL, ++ * argumentExt CHOICE { ++ * extension [6] IMPLICIT Extension, ++ * multipleExtension [7] IMPLICIT SEQUENCE OF Extension ++ * } OPTIONAL ++ * } ++ */ ++struct roseQsigMWIInterrogateResElt { ++ /*! \brief NbOfMessages ::= INTEGER (0..65535) (optional) */ ++ u_int16_t number_of_messages; ++ ++ /*! \brief msgCentreId (optional) */ ++ struct roseQsigMsgCentreId msg_centre_id; ++ ++ /*! \brief originatingNr (optional) (Number present if length is nonzero) */ ++ struct rosePartyNumber originating_number; ++ ++ /*! \brief GeneralizedTime (SIZE (12..19)) (optional) */ ++ unsigned char timestamp[19 + 1]; ++ ++ /*! ++ * \details ++ * allServices(0), ++ * speech(1), ++ * unrestrictedDigitalInformation(2), ++ * audio3100Hz(3), ++ * telephony(32), ++ * teletex(33), ++ * telefaxGroup4Class1(34), ++ * videotextSyntaxBased(35), ++ * videotelephony(36), ++ * telefaxGroup2-3(37), ++ * reservedNotUsed1(38), ++ * reservedNotUsed2(39), ++ * reservedNotUsed3(40), ++ * reservedNotUsed4(41), ++ * reservedNotUsed5(42), ++ * email(51), ++ * video(52), ++ * fileTransfer(53), ++ * shortMessageService(54), ++ * speechAndVideo(55), ++ * speechAndFax(56), ++ * speechAndEmail(57), ++ * videoAndFax(58), ++ * videoAndEmail(59), ++ * faxAndEmail(60), ++ * speechVideoAndFax(61), ++ * speechVideoAndEmail(62), ++ * speechFaxAndEmail(63), ++ * videoFaxAndEmail(64), ++ * speechVideoFaxAndEmail(65), ++ * multimediaUnknown(66), ++ * serviceUnknown(67), ++ * futureReserve1(68), ++ * futureReserve2(69), ++ * futureReserve3(70), ++ * futureReserve4(71), ++ * futureReserve5(72), ++ * futureReserve6(73), ++ * futureReserve7(74), ++ * futureReserve8(75) ++ */ ++ u_int8_t basic_service; ++ ++ /*! ++ * \brief INTEGER (0..9) (optional) ++ * \note The value 0 means the highest priority and 9 the lowest. ++ */ ++ u_int8_t priority; ++ ++ /*! \brief TRUE if msg_centre_id is present */ ++ u_int8_t msg_centre_id_present; ++ ++ /*! \brief TRUE if number_of_messages is present */ ++ u_int8_t number_of_messages_present; ++ ++ /*! \brief TRUE if timestamp is present */ ++ u_int8_t timestamp_present; ++ ++ /*! \brief TRUE if priority is present */ ++ u_int8_t priority_present; ++}; ++ ++/* ++ * MWIInterrogateRes ::= SEQUENCE SIZE(1..10) OF MWIInterrogateResElt ++ */ ++struct roseQsigMWIInterrogateRes { ++ /*! \brief SEQUENCE SIZE(1..10) OF MWIInterrogateResElt */ ++ struct roseQsigMWIInterrogateResElt list[10]; ++ ++ /*! \brief Number of MWIInterrogateResElt records present */ ++ u_int8_t num_records; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ++ * Northern Telecom DMS-100 transfer ability result ++ * ++ * callId [0] IMPLICIT INTEGER (0..16777215) -- 24 bit number ++ */ ++struct roseDms100RLTOperationInd_RES { ++ /*! INTEGER (0..16777215) -- 24 bit number */ ++ u_int32_t call_id; ++}; ++ ++/* ++ * Northern Telecom DMS-100 transfer invoke ++ * ++ * ARGUMENT SEQUENCE { ++ * callId [0] IMPLICIT INTEGER (0..16777215), -- 24 bit number ++ * reason [1] IMPLICIT INTEGER ++ * } ++ */ ++struct roseDms100RLTThirdParty_ARG { ++ /*! INTEGER (0..16777215) -- 24 bit number */ ++ u_int32_t call_id; ++ ++ /*! Reason for redirect */ ++ u_int8_t reason; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/* ARGUMENT ENUMERATED */ ++struct roseNi2InformationFollowing_ARG { ++ u_int8_t value; /*!< Unknown enumerated value */ ++}; ++ ++/* ++ * ARGUMENT SEQUENCE { ++ * callReference INTEGER -- 16 bit number ++ * } ++ */ ++struct roseNi2InitiateTransfer_ARG { ++ u_int16_t call_reference; ++}; ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++ ++/*! \brief Facility ie invoke etsi messages with arguments. */ ++union rose_msg_invoke_etsi_args { ++ /* ETSI Advice Of Charge (AOC) */ ++ struct roseEtsiChargingRequest_ARG ChargingRequest; ++ struct roseEtsiAOCSCurrency_ARG AOCSCurrency; ++ struct roseEtsiAOCSSpecialArr_ARG AOCSSpecialArr; ++ struct roseEtsiAOCDCurrency_ARG AOCDCurrency; ++ struct roseEtsiAOCDChargingUnit_ARG AOCDChargingUnit; ++ struct roseEtsiAOCECurrency_ARG AOCECurrency; ++ struct roseEtsiAOCEChargingUnit_ARG AOCEChargingUnit; ++ ++ /* ETSI Call Diversion */ ++ struct roseEtsiActivationDiversion_ARG ActivationDiversion; ++ struct roseEtsiDeactivationDiversion_ARG DeactivationDiversion; ++ struct roseEtsiActivationStatusNotificationDiv_ARG ActivationStatusNotificationDiv; ++ struct roseEtsiDeactivationStatusNotificationDiv_ARG ++ DeactivationStatusNotificationDiv; ++ struct roseEtsiInterrogationDiversion_ARG InterrogationDiversion; ++ struct roseEtsiDiversionInformation_ARG DiversionInformation; ++ struct roseEtsiCallDeflection_ARG CallDeflection; ++ struct roseEtsiCallRerouting_ARG CallRerouting; ++ struct roseEtsiDivertingLegInformation1_ARG DivertingLegInformation1; ++ struct roseEtsiDivertingLegInformation2_ARG DivertingLegInformation2; ++ struct roseEtsiDivertingLegInformation3_ARG DivertingLegInformation3; ++ ++ /* ETSI Explicit Call Transfer (ECT) */ ++ struct roseEtsiExplicitEctExecute_ARG ExplicitEctExecute; ++ struct roseEtsiSubaddressTransfer_ARG SubaddressTransfer; ++ struct roseEtsiEctInform_ARG EctInform; ++ struct roseEtsiEctLoopTest_ARG EctLoopTest; ++}; ++ ++/*! \brief Facility ie result etsi messages with arguments. */ ++union rose_msg_result_etsi_args { ++ /* ETSI Advice Of Charge (AOC) */ ++ struct roseEtsiChargingRequest_RES ChargingRequest; ++ ++ /* ETSI Call Diversion */ ++ struct roseEtsiForwardingList InterrogationDiversion; ++ struct roseEtsiServedUserNumberList InterrogateServedUserNumbers; ++ ++ /* ETSI Explicit Call Transfer (ECT) */ ++ struct roseEtsiEctLinkIdRequest_RES EctLinkIdRequest; ++ struct roseEtsiEctLoopTest_RES EctLoopTest; ++}; ++ ++/*! \brief Facility ie invoke qsig messages with arguments. */ ++union rose_msg_invoke_qsig_args { ++ /* Q.SIG Name-Operations */ ++ struct roseQsigPartyName_ARG CallingName; ++ struct roseQsigPartyName_ARG CalledName; ++ struct roseQsigPartyName_ARG ConnectedName; ++ struct roseQsigPartyName_ARG BusyName; ++ ++ /* Q.SIG SS-AOC-Operations */ ++ struct roseQsigChargeRequestArg_ARG ChargeRequest; ++ struct roseQsigAocFinalArg_ARG AocFinal; ++ struct roseQsigAocInterimArg_ARG AocInterim; ++ struct roseQsigAocRateArg_ARG AocRate; ++ struct roseQsigAocCompleteArg_ARG AocComplete; ++ struct roseQsigAocDivChargeReqArg_ARG AocDivChargeReq; ++ ++ /* Q.SIG Call-Transfer-Operations */ ++ struct roseQsigCTInitiateArg_ARG CallTransferInitiate; ++ struct roseQsigCTSetupArg_ARG CallTransferSetup; ++ struct roseQsigCTActiveArg_ARG CallTransferActive; ++ struct roseQsigCTCompleteArg_ARG CallTransferComplete; ++ struct roseQsigCTUpdateArg_ARG CallTransferUpdate; ++ struct roseQsigSubaddressTransferArg_ARG SubaddressTransfer; ++ ++ /* Q.SIG Call-Diversion-Operations */ ++ struct roseQsigActivateDiversionQ_ARG ActivateDiversionQ; ++ struct roseQsigDeactivateDiversionQ_ARG DeactivateDiversionQ; ++ struct roseQsigInterrogateDiversionQ_ARG InterrogateDiversionQ; ++ struct roseQsigCheckRestriction_ARG CheckRestriction; ++ struct roseQsigCallRerouting_ARG CallRerouting; ++ struct roseQsigDivertingLegInformation1_ARG DivertingLegInformation1; ++ struct roseQsigDivertingLegInformation2_ARG DivertingLegInformation2; ++ struct roseQsigDivertingLegInformation3_ARG DivertingLegInformation3; ++ ++ /* Q.SIG SS-MWI-Operations */ ++ struct roseQsigMWIActivateArg MWIActivate; ++ struct roseQsigMWIDeactivateArg MWIDeactivate; ++ struct roseQsigMWIInterrogateArg MWIInterrogate; ++}; ++ ++/*! \brief Facility ie result qsig messages with arguments. */ ++union rose_msg_result_qsig_args { ++ /* Q.SIG SS-AOC-Operations */ ++ struct roseQsigChargeRequestRes_RES ChargeRequest; ++ struct roseQsigAocCompleteRes_RES AocComplete; ++ ++ /* Q.SIG Call-Transfer-Operations */ ++ struct roseQsigCTIdentifyRes_RES CallTransferIdentify; ++ ++ /* Q.SIG Call-Diversion-Operations */ ++ struct roseQsigForwardingList InterrogateDiversionQ; ++ ++ /* Q.SIG SS-MWI-Operations */ ++ struct roseQsigMWIInterrogateRes MWIInterrogate; ++}; ++ ++/*! \brief Facility ie invoke DMS-100 messages with arguments. */ ++union rose_msg_invoke_dms100_args { ++ struct roseDms100RLTThirdParty_ARG RLT_ThirdParty; ++}; ++ ++/*! \brief Facility ie result DMS-100 messages with arguments. */ ++union rose_msg_result_dms100_args { ++ struct roseDms100RLTOperationInd_RES RLT_OperationInd; ++}; ++ ++/*! \brief Facility ie invoke NI2 messages with arguments. */ ++union rose_msg_invoke_ni2_args { ++ struct roseNi2InformationFollowing_ARG InformationFollowing; ++ struct roseNi2InitiateTransfer_ARG InitiateTransfer; ++}; ++ ++/*! \brief Facility ie result NI2 messages with arguments. */ ++union rose_msg_result_ni2_args { ++ int dummy; /*!< place holder until there are results with parameters */ ++}; ++ ++/*! \brief Facility ie invoke messages with arguments. */ ++union rose_msg_invoke_args { ++ union rose_msg_invoke_etsi_args etsi; ++ union rose_msg_invoke_qsig_args qsig; ++ union rose_msg_invoke_dms100_args dms100; ++ union rose_msg_invoke_ni2_args ni2; ++}; ++ ++/*! \brief Facility ie result messages with arguments. */ ++union rose_msg_result_args { ++ union rose_msg_result_etsi_args etsi; ++ union rose_msg_result_qsig_args qsig; ++ union rose_msg_result_dms100_args dms100; ++ union rose_msg_result_ni2_args ni2; ++}; ++ ++/*! \brief Facility ie error messages with parameters. */ ++union rose_msg_error_args { ++ int dummy; /*!< place holder until there are errors with parameters */ ++}; ++ ++struct rose_msg_invoke { ++ /*! \brief Invoke ID (-32768..32767) */ ++ int16_t invoke_id; ++ /*! \brief Linked ID (-32768..32767) (optional) */ ++ int16_t linked_id; ++ /*! \brief library encoded operation-value */ ++ enum rose_operation operation; ++ /*! \brief TRUE if the Linked ID is present */ ++ u_int8_t linked_id_present; ++ union rose_msg_invoke_args args; ++}; ++ ++struct rose_msg_result { ++ /*! \brief Invoke ID (-32768..32767) */ ++ int16_t invoke_id; ++ /*! ++ * \brief library encoded operation-value ++ * \note Set to ROSE_None if the operation sequence is not present. ++ * \note ETSI and Q.SIG imply that if a return result does not have ++ * any arguments then you must rely upon the invokeId value to ++ * distinguish between return results because the operation-value is ++ * not present. ++ */ ++ enum rose_operation operation; ++ union rose_msg_result_args args; ++}; ++ ++struct rose_msg_error { ++ /*! \brief Invoke ID (-32768..32767) */ ++ int16_t invoke_id; ++ /*! \brief library encoded error-value */ ++ enum rose_error_code code; ++ union rose_msg_error_args args; ++}; ++ ++struct rose_msg_reject { ++ /*! \brief Invoke ID (-32768..32767) (optional) */ ++ int16_t invoke_id; ++ /*! \brief TRUE if the Invoke ID is present */ ++ u_int8_t invoke_id_present; ++ /*! \brief library encoded problem-value */ ++ enum rose_reject_code code; ++}; ++ ++enum rose_component_type { ++ ROSE_COMP_TYPE_INVALID, ++ ROSE_COMP_TYPE_INVOKE, ++ ROSE_COMP_TYPE_RESULT, ++ ROSE_COMP_TYPE_ERROR, ++ ROSE_COMP_TYPE_REJECT ++}; ++ ++struct rose_message { ++ /*! \brief invoke, result, error, reject */ ++ enum rose_component_type type; ++ union { ++ struct rose_msg_invoke invoke; ++ struct rose_msg_result result; ++ struct rose_msg_error error; ++ struct rose_msg_reject reject; ++ } component; ++}; ++ ++/* ++ * NetworkFacilityExtension ::= [10] IMPLICIT SEQUENCE { ++ * sourceEntity [0] IMPLICIT EntityType, ++ * sourceEntityAddress [1] EXPLICIT AddressInformation OPTIONAL, ++ * destinationEntity [2] IMPLICIT EntityType, ++ * destinationEntityAddress [3] EXPLICIT AddressInformation OPTIONAL ++ * } ++ * ++ * AddressInformation ::= PartyNumber ++ */ ++struct facNetworkFacilityExtension { ++ /*! \brief sourceEntityAddress (optional) (Number present if length is nonzero) */ ++ struct rosePartyNumber source_number; ++ /*! \brief destinationEntityAddress (optional) (Number present if length is nonzero) */ ++ struct rosePartyNumber destination_number; ++ ++ /*! ++ * \details ++ * endPINX(0), ++ * anyTypeOfPINX(1) ++ */ ++ u_int8_t source_entity; ++ ++ /*! ++ * \details ++ * endPINX(0), ++ * anyTypeOfPINX(1) ++ */ ++ u_int8_t destination_entity; ++}; ++ ++/* ++ * The network extensions header is a sequence of the following components: ++ * ++ * nfe NetworkFacilityExtension OPTIONAL, ++ * npp NetworkProtocolProfile OPTIONAL, ++ * interpretation InterpretationApdu OPTIONAL ++ * ++ * NetworkProtocolProfile ::= [18] IMPLICIT INTEGER (0..254) ++ * ++ * InterpretationApdu ::= [11] IMPLICIT ENUMERATED { ++ * discardAnyUnrecognisedInvokePdu(0), ++ * ++ * -- this value also applies to Call independent signalling connections ++ * -- see clause 8.1.2 (ECMA-165) ++ * clearCallIfAnyInvokePduNotRecognised(1), ++ * ++ * -- this coding is implied by the absence of an ++ * -- interpretation APDU. ++ * rejectAnyUnrecognisedInvokePdu(2) ++ * } ++ */ ++struct fac_extension_header { ++ /*! \brief Network Facility Extension component */ ++ struct facNetworkFacilityExtension nfe; ++ ++ /*! \brief Network Protocol Profile component */ ++ u_int8_t npp; ++ ++ /*! ++ * \brief interpretation component ++ * ++ * \details ++ * discardAnyUnrecognisedInvokePdu(0), ++ * clearCallIfAnyInvokePduNotRecognised(1), ++ * rejectAnyUnrecognisedInvokePdu(2) ++ */ ++ u_int8_t interpretation; ++ ++ /*! \brief TRUE if nfe is present */ ++ u_int8_t nfe_present; ++ ++ /*! \brief TRUE if npp is present */ ++ u_int8_t npp_present; ++ ++ /*! \brief TRUE if interpretation is present */ ++ u_int8_t interpretation_present; ++}; ++ ++const char *rose_operation2str(enum rose_operation operation); ++const char *rose_error2str(enum rose_error_code code); ++const char *rose_reject2str(enum rose_reject_code code); ++ ++unsigned char *rose_encode_invoke(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rose_msg_invoke *msg); ++unsigned char *rose_encode_result(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rose_msg_result *msg); ++unsigned char *rose_encode_error(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rose_msg_error *msg); ++unsigned char *rose_encode_reject(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rose_msg_reject *msg); ++ ++unsigned char *rose_encode(struct pri *ctrl, unsigned char *pos, unsigned char *end, ++ const struct rose_message *msg); ++const unsigned char *rose_decode(struct pri *ctrl, const unsigned char *pos, ++ const unsigned char *end, struct rose_message *msg); ++ ++unsigned char *fac_enc_extension_header(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct fac_extension_header *header); ++unsigned char *facility_encode_header(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct fac_extension_header *header); ++ ++const unsigned char *fac_dec_extension_header(struct pri *ctrl, const unsigned char *pos, ++ const unsigned char *end, struct fac_extension_header *header); ++const unsigned char *facility_decode_header(struct pri *ctrl, const unsigned char *pos, ++ const unsigned char *end, struct fac_extension_header *header); ++ ++void facility_decode_dump(struct pri *ctrl, const unsigned char *buf, size_t length); ++ ++/* ------------------------------------------------------------------- */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* _LIBPRI_ROSE_H */ ++/* ------------------------------------------------------------------- */ ++/* end rose.h */ + +Property changes on: rose.h +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: rose_address.c +=================================================================== +--- a/rose_address.c (.../tags/1.4.10.2) (revision 0) ++++ b/rose_address.c (.../branches/1.4) (revision 1357) +@@ -0,0 +1,983 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief ROSE Addressing-Data-Elements ++ * ++ * Addressing-Data-Elements ETS 300 196-1 D.3 ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++ ++#include "compat.h" ++#include "libpri.h" ++#include "pri_internal.h" ++#include "rose.h" ++#include "rose_internal.h" ++#include "asn1.h" ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++/*! ++ * \internal ++ * \brief Encode the public or private network PartyNumber type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param number ++ * \param length_of_number ++ * \param type_of_number ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_NetworkPartyNumber(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, unsigned tag, const unsigned char *number, ++ size_t length_of_number, u_int8_t type_of_number) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, type_of_number)); ++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_NUMERIC_STRING, number, ++ length_of_number)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the PartyNumber type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param party_number ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_PartyNumber(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePartyNumber *party_number) ++{ ++ switch (party_number->plan) { ++ case 0: /* Unknown PartyNumber */ ++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0, ++ party_number->str, party_number->length)); ++ break; ++ case 1: /* Public PartyNumber */ ++ ASN1_CALL(pos, rose_enc_NetworkPartyNumber(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, party_number->str, party_number->length, ++ party_number->ton)); ++ break; ++ case 2: /* NSAP encoded PartyNumber */ ++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, ++ party_number->str, party_number->length)); ++ break; ++ case 3: /* Data PartyNumber (Not used) */ ++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3, ++ party_number->str, party_number->length)); ++ break; ++ case 4: /* Telex PartyNumber (Not used) */ ++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 4, ++ party_number->str, party_number->length)); ++ break; ++ case 5: /* Private PartyNumber */ ++ ASN1_CALL(pos, rose_enc_NetworkPartyNumber(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 5, party_number->str, party_number->length, ++ party_number->ton)); ++ break; ++ case 8: /* National Standard PartyNumber (Not used) */ ++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 8, ++ party_number->str, party_number->length)); ++ break; ++ default: ++ ASN1_ENC_ERROR(ctrl, "Unknown numbering plan"); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the PartySubaddress type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param party_subaddress ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_PartySubaddress(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePartySubaddress *party_subaddress) ++{ ++ unsigned char *seq_len; ++ ++ switch (party_subaddress->type) { ++ case 0: /* UserSpecified */ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_TAG_SEQUENCE); ++ ++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_OCTET_STRING, ++ party_subaddress->u.user_specified.information, party_subaddress->length)); ++ if (party_subaddress->u.user_specified.odd_count_present) { ++ ASN1_CALL(pos, asn1_enc_boolean(pos, end, ASN1_TYPE_BOOLEAN, ++ party_subaddress->u.user_specified.odd_count)); ++ } ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ break; ++ case 1: /* NSAP */ ++ ASN1_CALL(pos, asn1_enc_string_bin(pos, end, ASN1_TYPE_OCTET_STRING, ++ party_subaddress->u.nsap, party_subaddress->length)); ++ break; ++ default: ++ ASN1_ENC_ERROR(ctrl, "Unknown subaddress type"); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the Address type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param address ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_Address(struct pri *ctrl, unsigned char *pos, unsigned char *end, ++ unsigned tag, const struct roseAddress *address) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &address->number)); ++ if (address->subaddress.length) { ++ ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end, &address->subaddress)); ++ } ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the PresentedNumberUnscreened type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param party ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_PresentedNumberUnscreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePresentedNumberUnscreened *party) ++{ ++ unsigned char *seq_len; ++ ++ switch (party->presentation) { ++ case 0: /* presentationAllowedNumber */ ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 0); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &party->number)); ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ break; ++ case 1: /* presentationRestricted */ ++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1)); ++ break; ++ case 2: /* numberNotAvailableDueToInterworking */ ++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2)); ++ break; ++ case 3: /* presentationRestrictedNumber */ ++ /* EXPLICIT tag */ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3); ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &party->number)); ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ break; ++ default: ++ ASN1_ENC_ERROR(ctrl, "Unknown presentation type"); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the NumberScreened type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param screened ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_NumberScreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, unsigned tag, const struct roseNumberScreened *screened) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &screened->number)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ screened->screening_indicator)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the PresentedNumberScreened type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param party ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_PresentedNumberScreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePresentedNumberScreened *party) ++{ ++ switch (party->presentation) { ++ case 0: /* presentationAllowedNumber */ ++ ASN1_CALL(pos, rose_enc_NumberScreened(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 0, &party->screened)); ++ break; ++ case 1: /* presentationRestricted */ ++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1)); ++ break; ++ case 2: /* numberNotAvailableDueToInterworking */ ++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2)); ++ break; ++ case 3: /* presentationRestrictedNumber */ ++ ASN1_CALL(pos, rose_enc_NumberScreened(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 3, &party->screened)); ++ break; ++ default: ++ ASN1_ENC_ERROR(ctrl, "Unknown presentation type"); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the AddressScreened type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param screened ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_AddressScreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, unsigned tag, const struct roseAddressScreened *screened) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, rose_enc_PartyNumber(ctrl, pos, end, &screened->number)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ screened->screening_indicator)); ++ if (screened->subaddress.length) { ++ ASN1_CALL(pos, rose_enc_PartySubaddress(ctrl, pos, end, &screened->subaddress)); ++ } ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Encode the PresentedAddressScreened type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param party ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++unsigned char *rose_enc_PresentedAddressScreened(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, const struct rosePresentedAddressScreened *party) ++{ ++ switch (party->presentation) { ++ case 0: /* presentationAllowedAddress */ ++ ASN1_CALL(pos, rose_enc_AddressScreened(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 0, &party->screened)); ++ break; ++ case 1: /* presentationRestricted */ ++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1)); ++ break; ++ case 2: /* numberNotAvailableDueToInterworking */ ++ ASN1_CALL(pos, asn1_enc_null(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2)); ++ break; ++ case 3: /* presentationRestrictedAddress */ ++ ASN1_CALL(pos, rose_enc_AddressScreened(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 3, &party->screened)); ++ break; ++ default: ++ ASN1_ENC_ERROR(ctrl, "Unknown presentation type"); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the NumberDigits PartyNumber argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party_number Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_dec_NumberDigits(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePartyNumber *party_number) ++{ ++ size_t str_len; ++ ++ ASN1_CALL(pos, asn1_dec_string_max(ctrl, name, tag, pos, end, ++ sizeof(party_number->str), party_number->str, &str_len)); ++ party_number->length = str_len; ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the NSAP PartyNumber argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party_number Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_dec_NSAPPartyNumber(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePartyNumber *party_number) ++{ ++ size_t str_len; ++ ++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end, ++ sizeof(party_number->str), party_number->str, &str_len)); ++ party_number->length = str_len; ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the public or private network PartyNumber argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party_number Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_dec_NetworkPartyNumber(struct pri *ctrl, ++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePartyNumber *party_number) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s %s\n", name, asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "typeOfNumber", tag, pos, seq_end, &value)); ++ party_number->ton = value; ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_TYPE_NUMERIC_STRING); ++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "numberDigits", tag, pos, seq_end, ++ party_number)); ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the PartyNumber argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party_number Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_PartyNumber(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePartyNumber *party_number) ++{ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s PartyNumber\n", name); ++ } ++ party_number->ton = 0; /* unknown */ ++ switch (tag & ~ASN1_PC_MASK) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 0: ++ party_number->plan = 0; /* Unknown PartyNumber */ ++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "unknownPartyNumber", tag, pos, end, ++ party_number)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ /* Must be constructed but we will not check for it for simplicity. */ ++ party_number->plan = 1; /* Public PartyNumber */ ++ ASN1_CALL(pos, rose_dec_NetworkPartyNumber(ctrl, "publicPartyNumber", tag, pos, ++ end, party_number)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ party_number->plan = 2; /* NSAP encoded PartyNumber */ ++ ASN1_CALL(pos, rose_dec_NSAPPartyNumber(ctrl, "nsapEncodedPartyNumber", tag, pos, ++ end, party_number)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 3: ++ party_number->plan = 3; /* Data PartyNumber (Not used) */ ++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "dataPartyNumber", tag, pos, end, ++ party_number)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 4: ++ party_number->plan = 4; /* Telex PartyNumber (Not used) */ ++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "telexPartyNumber", tag, pos, end, ++ party_number)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 5: ++ /* Must be constructed but we will not check for it for simplicity. */ ++ party_number->plan = 5; /* Private PartyNumber */ ++ ASN1_CALL(pos, rose_dec_NetworkPartyNumber(ctrl, "privatePartyNumber", tag, pos, ++ end, party_number)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 8: ++ party_number->plan = 8; /* National Standard PartyNumber (Not used) */ ++ ASN1_CALL(pos, rose_dec_NumberDigits(ctrl, "nationalStandardPartyNumber", tag, ++ pos, end, party_number)); ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the User PartySubaddress argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party_subaddress Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_dec_UserSubaddress(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePartySubaddress *party_subaddress) ++{ ++ size_t str_len; ++ int32_t odd_count; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ ++ party_subaddress->type = 0; /* UserSpecified */ ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s UserSpecified %s\n", name, asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ /* SubaddressInformation */ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag & ~ASN1_PC_MASK, ASN1_TYPE_OCTET_STRING); ++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, "subaddressInformation", tag, pos, seq_end, ++ sizeof(party_subaddress->u.user_specified.information), ++ party_subaddress->u.user_specified.information, &str_len)); ++ party_subaddress->length = str_len; ++ ++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ /* ++ * The optional odd count indicator must be present since there ++ * is something left. ++ */ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_BOOLEAN); ++ ASN1_CALL(pos, asn1_dec_boolean(ctrl, "oddCount", tag, pos, seq_end, ++ &odd_count)); ++ party_subaddress->u.user_specified.odd_count = odd_count; ++ party_subaddress->u.user_specified.odd_count_present = 1; ++ } else { ++ party_subaddress->u.user_specified.odd_count = 0; ++ party_subaddress->u.user_specified.odd_count_present = 0; ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Decode the NSAP PartySubaddress argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party_subaddress Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++static const unsigned char *rose_dec_NSAPSubaddress(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePartySubaddress *party_subaddress) ++{ ++ size_t str_len; ++ ++ party_subaddress->type = 1; /* NSAP */ ++ ++ ASN1_CALL(pos, asn1_dec_string_bin(ctrl, name, tag, pos, end, ++ sizeof(party_subaddress->u.nsap), party_subaddress->u.nsap, &str_len)); ++ party_subaddress->length = str_len; ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the PartySubaddress argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party_subaddress Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_PartySubaddress(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePartySubaddress *party_subaddress) ++{ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s PartySubaddress\n", name); ++ } ++ switch (tag) { ++ case ASN1_TAG_SEQUENCE: ++ ASN1_CALL(pos, rose_dec_UserSubaddress(ctrl, "user", tag, pos, end, ++ party_subaddress)); ++ break; ++ case ASN1_TYPE_OCTET_STRING: ++ case ASN1_TYPE_OCTET_STRING | ASN1_PC_CONSTRUCTED: ++ ASN1_CALL(pos, rose_dec_NSAPSubaddress(ctrl, "nsap", tag, pos, end, ++ party_subaddress)); ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the Address argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param address Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_Address(struct pri *ctrl, const char *name, unsigned tag, ++ const unsigned char *pos, const unsigned char *end, struct roseAddress *address) ++{ ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s Address %s\n", name, asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, seq_end, ++ &address->number)); ++ ++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ /* The optional subaddress must be present since there is something left. */ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "partySubaddress", tag, pos, ++ seq_end, &address->subaddress)); ++ } else { ++ address->subaddress.length = 0; /* Subaddress not present */ ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the PresentedNumberUnscreened argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_PresentedNumberUnscreened(struct pri *ctrl, ++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePresentedNumberUnscreened *party) ++{ ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s PresentedNumberUnscreened\n", name); ++ } ++ switch (tag) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ party->presentation = 0; /* presentationAllowedNumber */ ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "presentationAllowedNumber", tag, pos, ++ seq_end, &party->number)); ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ party->presentation = 1; /* presentationRestricted */ ++ ASN1_CALL(pos, asn1_dec_null(ctrl, "presentationRestricted", tag, pos, end)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ party->presentation = 2; /* numberNotAvailableDueToInterworking */ ++ ASN1_CALL(pos, asn1_dec_null(ctrl, "numberNotAvailableDueToInterworking", tag, ++ pos, end)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3: ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " Explicit %s\n", asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ party->presentation = 3; /* presentationRestrictedNumber */ ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "presentationRestrictedNumber", tag, ++ pos, seq_end, &party->number)); ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the NumberScreened argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param screened Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_NumberScreened(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct roseNumberScreened *screened) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s NumberScreened %s\n", name, asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, seq_end, ++ &screened->number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "screeningIndicator", tag, pos, seq_end, &value)); ++ screened->screening_indicator = value; ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the PresentedNumberScreened argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_PresentedNumberScreened(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePresentedNumberScreened *party) ++{ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s PresentedNumberScreened\n", name); ++ } ++ switch (tag) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0: ++ party->presentation = 0; /* presentationAllowedNumber */ ++ ASN1_CALL(pos, rose_dec_NumberScreened(ctrl, "presentationAllowedNumber", tag, ++ pos, end, &party->screened)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ party->presentation = 1; /* presentationRestricted */ ++ ASN1_CALL(pos, asn1_dec_null(ctrl, "presentationRestricted", tag, pos, end)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ party->presentation = 2; /* numberNotAvailableDueToInterworking */ ++ ASN1_CALL(pos, asn1_dec_null(ctrl, "numberNotAvailableDueToInterworking", tag, ++ pos, end)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3: ++ party->presentation = 3; /* presentationRestrictedNumber */ ++ ASN1_CALL(pos, rose_dec_NumberScreened(ctrl, "presentationRestrictedNumber", tag, ++ pos, end, &party->screened)); ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the AddressScreened argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param screened Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_AddressScreened(struct pri *ctrl, const char *name, ++ unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct roseAddressScreened *screened) ++{ ++ int32_t value; ++ int length; ++ int seq_offset; ++ const unsigned char *seq_end; ++ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s AddressScreened %s\n", name, asn1_tag2str(tag)); ++ } ++ ASN1_CALL(pos, asn1_dec_length(pos, end, &length)); ++ ASN1_END_SETUP(seq_end, seq_offset, length, pos, end); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartyNumber(ctrl, "partyNumber", tag, pos, seq_end, ++ &screened->number)); ++ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CHECK_TAG(ctrl, tag, tag, ASN1_TYPE_ENUMERATED); ++ ASN1_CALL(pos, asn1_dec_int(ctrl, "screeningIndicator", tag, pos, seq_end, &value)); ++ screened->screening_indicator = value; ++ ++ if (pos < seq_end && *pos != ASN1_INDEF_TERM) { ++ /* The optional subaddress must be present since there is something left. */ ++ ASN1_CALL(pos, asn1_dec_tag(pos, seq_end, &tag)); ++ ASN1_CALL(pos, rose_dec_PartySubaddress(ctrl, "partySubaddress", tag, pos, ++ seq_end, &screened->subaddress)); ++ } else { ++ screened->subaddress.length = 0; /* Subaddress not present */ ++ } ++ ++ ASN1_END_FIXUP(ctrl, pos, seq_offset, seq_end, end); ++ ++ return pos; ++} ++ ++/*! ++ * \brief Decode the PresentedAddressScreened argument parameters. ++ * ++ * \param ctrl D channel controller for any diagnostic messages. ++ * \param name Field name ++ * \param tag Component tag that identified this production. ++ * \param pos Starting position of the ASN.1 component length. ++ * \param end End of ASN.1 decoding data buffer. ++ * \param party Parameter storage to fill. ++ * ++ * \retval Start of the next ASN.1 component on success. ++ * \retval NULL on error. ++ */ ++const unsigned char *rose_dec_PresentedAddressScreened(struct pri *ctrl, ++ const char *name, unsigned tag, const unsigned char *pos, const unsigned char *end, ++ struct rosePresentedAddressScreened *party) ++{ ++ if (ctrl->debug & PRI_DEBUG_APDU) { ++ pri_message(ctrl, " %s PresentedAddressScreened\n", name); ++ } ++ switch (tag) { ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 0: ++ party->presentation = 0; /* presentationAllowedAddress */ ++ ASN1_CALL(pos, rose_dec_AddressScreened(ctrl, "presentationAllowedAddress", tag, ++ pos, end, &party->screened)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 1: ++ party->presentation = 1; /* presentationRestricted */ ++ ASN1_CALL(pos, asn1_dec_null(ctrl, "presentationRestricted", tag, pos, end)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | 2: ++ party->presentation = 2; /* numberNotAvailableDueToInterworking */ ++ ASN1_CALL(pos, asn1_dec_null(ctrl, "numberNotAvailableDueToInterworking", tag, ++ pos, end)); ++ break; ++ case ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_PC_CONSTRUCTED | 3: ++ party->presentation = 3; /* presentationRestrictedAddress */ ++ ASN1_CALL(pos, rose_dec_AddressScreened(ctrl, "presentationRestrictedAddress", ++ tag, pos, end, &party->screened)); ++ break; ++ default: ++ ASN1_DID_NOT_EXPECT_TAG(ctrl, tag); ++ return NULL; ++ } ++ ++ return pos; ++} ++ ++/* ------------------------------------------------------------------- */ ++/* end rose_address.c */ + +Property changes on: rose_address.c +___________________________________________________________________ +Added: svn:eol-style + + native +Added: svn:mime-type + + text/plain +Added: svn:keywords + + 'Author Date Id Revision' + +Index: rose_qsig_aoc.c +=================================================================== +--- a/rose_qsig_aoc.c (.../tags/1.4.10.2) (revision 0) ++++ b/rose_qsig_aoc.c (.../branches/1.4) (revision 1357) +@@ -0,0 +1,1714 @@ ++/* ++ * libpri: An implementation of Primary Rate ISDN ++ * ++ * Copyright (C) 2009 Digium, Inc. ++ * ++ * Richard Mudgett <rmudgett@digium.com> ++ * ++ * See http://www.asterisk.org for more information about ++ * the Asterisk project. Please do not directly contact ++ * any of the maintainers of this project for assistance; ++ * the project provides a web site, mailing lists and IRC ++ * channels for your use. ++ * ++ * This program is free software, distributed under the terms of ++ * the GNU General Public License Version 2 as published by the ++ * Free Software Foundation. See the LICENSE file included with ++ * this program for more details. ++ * ++ * In addition, when this program is distributed with Asterisk in ++ * any form that would qualify as a 'combined work' or as a ++ * 'derivative work' (but not mere aggregation), you can redistribute ++ * and/or modify the combination under the terms of the license ++ * provided with that copy of Asterisk, instead of the license ++ * terms granted here. ++ */ ++ ++/*! ++ * \file ++ * \brief Q.SIG ROSE Advice-Of-Charge (AOC) operations ++ * ++ * SS-AOC-Operations ECMA-212 Annex E Table E.1 ++ * ++ * \author Richard Mudgett <rmudgett@digium.com> ++ */ ++ ++ ++#include "compat.h" ++#include "libpri.h" ++#include "pri_internal.h" ++#include "rose.h" ++#include "rose_internal.h" ++#include "asn1.h" ++ ++ ++/* ------------------------------------------------------------------- */ ++ ++/*! ++ * \internal ++ * \brief Encode the Time type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param time Time information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_AOC_Time(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, unsigned tag, const struct roseQsigAOCTime *time) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, ++ time->length)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, time->scale)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the Amount type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param amount Amount information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_AOC_Amount(struct pri *ctrl, unsigned char *pos, ++ unsigned char *end, unsigned tag, const struct roseQsigAOCAmount *amount) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, ++ amount->currency)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 2, ++ amount->multiplier)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the RecordedCurrency type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param recorded Recorded currency information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_AOC_RecordedCurrency(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, unsigned tag, ++ const struct roseQsigAOCRecordedCurrency *recorded) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, ++ recorded->currency, sizeof(recorded->currency) - 1)); ++ ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &recorded->amount)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the DurationCurrency type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param duration Duration currency information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_AOC_DurationCurrency(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, unsigned tag, ++ const struct roseQsigAOCDurationCurrency *duration) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, ++ duration->currency, sizeof(duration->currency) - 1)); ++ ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &duration->amount)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3, ++ duration->charging_type)); ++ ASN1_CALL(pos, rose_enc_qsig_AOC_Time(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 4, &duration->time)); ++ if (duration->granularity_present) { ++ ASN1_CALL(pos, rose_enc_qsig_AOC_Time(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 5, &duration->granularity)); ++ } ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the FlatRateCurrency type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param flat_rate Flat rate currency information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_AOC_FlatRateCurrency(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, unsigned tag, ++ const struct roseQsigAOCFlatRateCurrency *flat_rate) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, ++ flat_rate->currency, sizeof(flat_rate->currency) - 1)); ++ ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &flat_rate->amount)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the VolumeRateCurrency type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param volume_rate Volume rate currency information to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_AOC_VolumeRateCurrency(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, unsigned tag, ++ const struct roseQsigAOCVolumeRateCurrency *volume_rate) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, asn1_enc_string_max(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 1, ++ volume_rate->currency, sizeof(volume_rate->currency) - 1)); ++ ASN1_CALL(pos, rose_enc_qsig_AOC_Amount(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 2, &volume_rate->amount)); ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_CLASS_CONTEXT_SPECIFIC | 3, ++ volume_rate->unit)); ++ ++ ASN1_CONSTRUCTED_END(seq_len, pos, end); ++ ++ return pos; ++} ++ ++/*! ++ * \internal ++ * \brief Encode the AOCSCurrencyInfo type. ++ * ++ * \param ctrl D channel controller for diagnostic messages or global options. ++ * \param pos Starting position to encode ASN.1 component. ++ * \param end End of ASN.1 encoding data buffer. ++ * \param tag Component tag to identify the encoded component. ++ * The tag should be ASN1_TAG_SEQUENCE unless the caller implicitly ++ * tags it otherwise. ++ * \param currency_info Currency information record to encode. ++ * ++ * \retval Start of the next ASN.1 component to encode on success. ++ * \retval NULL on error. ++ */ ++static unsigned char *rose_enc_qsig_AOCSCurrencyInfo(struct pri *ctrl, ++ unsigned char *pos, unsigned char *end, unsigned tag, ++ const struct roseQsigAOCSCurrencyInfo *currency_info) ++{ ++ unsigned char *seq_len; ++ ++ ASN1_CONSTRUCTED_BEGIN(seq_len, pos, end, tag); ++ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_ENUMERATED, ++ currency_info->charged_item)); ++ ++ switch (currency_info->currency_type) { ++ case 0: /* specialChargingCode */ ++ ASN1_CALL(pos, asn1_enc_int(pos, end, ASN1_TYPE_INTEGER, ++ currency_info->u.special_charging_code)); ++ break; ++ case 1: /* durationCurrency */ ++ ASN1_CALL(pos, rose_enc_qsig_AOC_DurationCurrency(ctrl, pos, end, ++ ASN1_CLASS_CONTEXT_SPECIFIC | 1, ¤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 + |