libpri/pri_facility.c
Richard Mudgett 6a121d4c74 The facility ie queue needs to remove facilities that have been sent.
The facility ie queue needs to remove facilities that have been sent.
Otherwise, the queue just grows until the call is terminated.  AOC
messages can clog the queue during a long call and the dummy call
reference may never be deleted.

Also removed unneeded elements of struct apdu_event.  The callback
function was not a good idea since many facility messages do not have
responses and the callback would prevents removal of events from the list.


git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1283 2fbb986a-6c06-0410-b554-c9c1f0a7f128
2009-11-10 21:51:26 +00:00

4054 lines
122 KiB
C

/*
* libpri: An implementation of Primary Rate ISDN
*
* Written by Matthew Fredrickson <creslin@digium.com>
*
* Copyright (C) 2004-2005, 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.
*/
#include "compat.h"
#include "libpri.h"
#include "pri_internal.h"
#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 short get_invokeid(struct pri *ctrl)
{
return ++ctrl->last_invoke;
}
static int redirectingreason_from_q931(struct pri *ctrl, int redirectingreason)
{
int value;
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;
}
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;
}
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;
}
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;
}
break;
}
return value;
}
/*!
* \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)
{
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 int typeofnumber_for_q931(struct pri *ctrl, int ton)
{
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;
}
/*!
* \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;
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;
}
return value;
}
/*!
* \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)
{
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;
}
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;
}
return value;
}
/*!
* \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)
{
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;
}
/*!
* \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)
{
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;
}
/*!
* \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)
{
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;
}
/*!
* \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)
{
/* 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;
}
}
/*!
* \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)
{
//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;
}
/*!
* \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;
}
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;
}
}
/*!
* \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)
{
rose_copy_number_to_q931(ctrl, &q931_address->number, &rose_address->number);
rose_copy_subaddress_to_q931(ctrl, &q931_address->subaddress,
&rose_address->subaddress);
}
/*!
* \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;
}
}
/*!
* \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;
}
}
/*!
* \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)
{
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;
}
}
/*!
* \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));
}
/*!
* \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);
}
/*!
* \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;
}
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;
}
}
/*!
* \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)
{
q931_copy_number_to_rose(ctrl, &rose_address->number, &q931_address->number);
q931_copy_subaddress_to_rose(ctrl, &rose_address->subaddress,
&q931_address->subaddress);
}
/*!
* \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 */
}
}
/*!
* \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 */
}
}
#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)
{
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 */
/*!
* \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 */
}
}
/*!
* \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;
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_DivertingLegInformation1;
msg.invoke_id = get_invokeid(ctrl);
msg.args.qsig.DivertingLegInformation1.diversion_reason =
redirectingreason_from_q931(ctrl, call->redirecting.reason);
/* 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;
}
/*!
* \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)
{
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_ETSI_DivertingLegInformation1;
msg.invoke_id = get_invokeid(ctrl);
msg.args.etsi.DivertingLegInformation1.diversion_reason =
redirectingreason_from_q931(ctrl, call->redirecting.reason);
if (call->redirecting.to.number.valid) {
msg.args.etsi.DivertingLegInformation1.subscription_option = 2;
/* 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);
return pos;
}
/*!
* \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)
{
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_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;
}
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
}
/*!
* \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;
}
/* 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);
}
}
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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)
{
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_ETSI_DivertingLegInformation2;
msg.invoke_id = get_invokeid(ctrl);
/* 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);
}
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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)
{
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_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;
}
return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer);
}
/*!
* \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;
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_DivertingLegInformation3;
msg.invoke_id = get_invokeid(ctrl);
/* 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 */
/* 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);
}
}
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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)
{
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_ETSI_DivertingLegInformation3;
msg.invoke_id = get_invokeid(ctrl);
if ((call->redirecting.to.number.presentation & PRI_PRES_RESTRICTION) == PRI_PRES_ALLOWED) {
msg.args.etsi.DivertingLegInformation3.presentation_allowed_indicator = 1; /* TRUE */
}
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;
}
if (!end) {
return -1;
}
return pri_call_apdu_queue(call, messagetype, buffer, end - buffer);
}
/*!
* \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)
{
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];
unsigned char *end;
q931_call *apdubearer;
q931_call *callwithid;
if (c2->transferable) {
apdubearer = c1;
callwithid = c2;
} else if (c1->transferable) {
apdubearer = c2;
callwithid = c1;
} else {
return -1;
}
end =
enc_dms100_rlt_initiate_transfer(ctrl, buffer, buffer + sizeof(buffer),
callwithid);
if (!end) {
return -1;
}
if (pri_call_apdu_queue(apdubearer, Q931_FACILITY, buffer, end - buffer)) {
return -1;
}
if (q931_facility(apdubearer->pri, apdubearer)) {
pri_message(ctrl, "Could not schedule facility message for call %d\n",
apdubearer->cr);
return -1;
}
return 0;
}
/*!
* \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)
{
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_OperationInd;
msg.invoke_id = ROSE_DMS100_RLT_OPERATION_IND;
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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)
{
unsigned char buffer[256];
unsigned char *end;
end = enc_dms100_rlt_transfer_ability(ctrl, buffer, buffer + sizeof(buffer));
if (!end) {
return -1;
}
return pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer);
}
/*!
* \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;
}
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);
return pos;
}
/*!
* \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;
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);
/* CallingName */
q931_copy_name_to_rose(ctrl, &msg.args.qsig.CallingName.name, name);
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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;
}
if (ctrl->switchtype == PRI_SWITCH_NI2 && !cpe) {
end = enc_ni2_information_following(ctrl, buffer, buffer + sizeof(buffer));
if (!end) {
return -1;
}
if (pri_call_apdu_queue(call, Q931_SETUP, buffer, end - buffer)) {
return -1;
}
/*
* We can reuse the buffer since the queue function doesn't
* need it.
*/
}
/* CallingName is the local_id.name */
end = enc_qsig_calling_name(ctrl, buffer, buffer + sizeof(buffer),
&call->local_id.name);
if (!end) {
return -1;
}
if (cpe) {
mymessage = Q931_SETUP;
} else {
mymessage = Q931_FACILITY;
}
return pri_call_apdu_queue(call, mymessage, buffer, end - buffer);
}
/* End Callername */
/* MWI related encode and decode functions */
/*!
* \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)
{
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;
}
/*!
* \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)
{
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_MWIDeactivate;
msg.invoke_id = get_invokeid(ctrl);
/* 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 */
msg.args.qsig.MWIDeactivate.basic_service = 1; /* speech */
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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;
}
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, end - buffer);
}
/* End MWI */
/* EECT functions */
/*!
* \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)
{
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_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);
return pos;
}
/*!
* \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;
}
if (pri_call_apdu_queue(c1, Q931_FACILITY, buffer, end - buffer)) {
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 */
if (q931_facility(c1->pri, c1)) {
pri_message(ctrl, "Could not schedule facility message for call %d\n", c1->cr);
return -1;
}
return 0;
}
/* End EECT */
/* QSIG CF CallRerouting */
/*!
* \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)
{
struct fac_extension_header header;
struct rose_msg_invoke msg;
unsigned char *q931ie_pos;
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;
}
memset(&msg, 0, sizeof(msg));
msg.operation = ROSE_QSIG_CallRerouting;
msg.invoke_id = get_invokeid(ctrl);
msg.args.qsig.CallRerouting.rerouting_reason =
redirectingreason_from_q931(ctrl, deflection->reason);
/* calledAddress is the passed in deflection->to address */
q931_copy_address_to_rose(ctrl, &msg.args.qsig.CallRerouting.called, &deflection->to);
msg.args.qsig.CallRerouting.diversion_counter = deflection->count;
/* 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;
/* 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);
msg.args.qsig.CallRerouting.subscription_option = subscription_option;
/* callingNumber is the passed in calling->number */
q931_copy_presented_number_screened_to_rose(ctrl,
&msg.args.qsig.CallRerouting.calling, &calling->number);
/* callingPartySubaddress is the passed in calling->subaddress if valid */
q931_copy_subaddress_to_rose(ctrl, &msg.args.qsig.CallRerouting.calling_subaddress,
&calling->subaddress);
/* 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);
}
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);
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);
return pos;
}
/*!
* \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;
pos = facility_encode_header(ctrl, pos, end, NULL);
if (!pos) {
return NULL;
}
memset(&msg, 0, sizeof(msg));
msg.operation = ROSE_ETSI_CallRerouting;
msg.invoke_id = get_invokeid(ctrl);
msg.args.etsi.CallRerouting.rerouting_reason =
redirectingreason_from_q931(ctrl, deflection->reason);
/* calledAddress is the passed in deflection->to address */
q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallRerouting.called_address,
&deflection->to);
msg.args.etsi.CallRerouting.rerouting_counter = deflection->count;
/* 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;
/* 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);
msg.args.etsi.CallRerouting.subscription_option = subscription_option;
/* callingPartySubaddress is the passed in calling->subaddress if valid */
q931_copy_subaddress_to_rose(ctrl, &msg.args.etsi.CallRerouting.calling_subaddress,
&calling->subaddress);
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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;
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);
/* deflectionAddress is the passed in deflection->to address */
q931_copy_address_to_rose(ctrl, &msg.args.etsi.CallDeflection.deflection,
deflection);
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;
}
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
}
/*!
* \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 */
/*
* 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(ctrl, "Could not Clear queue ADPU\n");
return -1;
}
/* Send message */
res = pri_call_apdu_queue(call->bridged_call, Q931_FACILITY, ie->data, ie->len);
if (res) {
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(ctrl, "Could not schedule facility message for call %d\n",
call->bridged_call->cr);
return -1;
}
return 0;
}
/* AFN-PR */
/*!
* \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)
{
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;
}
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;
}
res = pri_call_apdu_queue(c1, Q931_FACILITY, buffer, pos - buffer);
if (res) {
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(ctrl, "Could not schedule facility message for call %d\n", c1->cr);
return -1;
}
/* Reuse the previous message header */
pos = facility_encode_header(ctrl, buffer, end, &header);
if (!pos) {
return -1;
}
/* 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;
}
res = pri_call_apdu_queue(c2, Q931_FACILITY, buffer, pos - buffer);
if (res) {
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(ctrl, "Could not schedule facility message for call %d\n", c2->cr);
return -1;
}
return 0;
}
/* End AFN-PR */
/* AOC */
/*!
* \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)
{
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_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;
}
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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)
{
unsigned char buffer[255];
unsigned char *end;
/* sample data: [ 91 a1 12 02 02 3a 78 02 01 24 30 09 30 07 a1 05 30 03 02 01 01 ] */
end =
enc_etsi_aoce_charging_unit(ctrl, buffer, buffer + sizeof(buffer), chargedunits);
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 */
if (pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer)
|| q931_facility(call->pri, call)) {
pri_message(ctrl, "Could not schedule facility message for call %d\n", call->cr);
return -1;
}
return 0;
}
/* End AOC */
/* ===== 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)
{
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_CallTransferComplete;
msg.invoke_id = get_invokeid(ctrl);
msg.args.qsig.CallTransferComplete.end_designation = 0; /* primaryEnd */
/* redirectionNumber is the local_id.number */
q931_copy_presented_number_screened_to_rose(ctrl,
&msg.args.qsig.CallTransferComplete.redirection, &call->local_id.number);
/* 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);
}
if (call_status) {
msg.args.qsig.CallTransferComplete.call_status = 1; /* alerting */
}
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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;
pos = facility_encode_header(ctrl, pos, end, NULL);
if (!pos) {
return NULL;
}
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);
}
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 pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
}
/* ===== 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)
{
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_CalledName;
msg.invoke_id = get_invokeid(ctrl);
/* CalledName */
q931_copy_name_to_rose(ctrl, &msg.args.qsig.CalledName.name, name);
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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)
{
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;
}
return pri_call_apdu_queue(call, messagetype, buffer, end - buffer);
}
/*!
* \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;
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_ConnectedName;
msg.invoke_id = get_invokeid(ctrl);
/* ConnectedName */
q931_copy_name_to_rose(ctrl, &msg.args.qsig.ConnectedName.name, name);
pos = rose_encode_invoke(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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;
}
return pri_call_apdu_queue(call, messagetype, buffer, end - buffer);
}
/*!
* \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.
*
* \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_event *cur = NULL;
struct apdu_event *new_event = NULL;
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;
}
break;
}
new_event = calloc(1, sizeof(*new_event));
if (!new_event) {
pri_error(call->pri, "!! Malloc failed!\n");
return -1;
}
new_event->message = messagetype;
new_event->apdu_len = apdu_len;
memcpy(new_event->apdu, apdu, apdu_len);
/* Append APDU 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;
}
return 0;
}
int pri_call_apdu_queue_cleanup(q931_call *call)
{
struct apdu_event *cur_event = NULL, *free_event = NULL;
if (call && call->apdus) {
cur_event = call->apdus;
call->apdus = NULL;
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);
}
}
return 0;
}
/*! \note Only called when sending the SETUP message. */
int pri_call_add_standard_apdus(struct pri *ctrl, q931_call *call)
{
if (!ctrl->sendfacility) {
return 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);
/*
* 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;
}
return 0;
}
/*!
* \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;
}
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;
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;
pos = rose_encode_error(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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;
}
memset(&msg, 0, sizeof(msg));
msg.invoke_id = invoke_id;
msg.code = code;
pos = rose_encode_error(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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;
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;
}
return pri_call_apdu_queue(call, Q931_FACILITY, buffer, end - buffer);
}
/*!
* \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;
}
return 0;
}
/*!
* \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)
{
struct rose_msg_result msg;
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;
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;
}
memset(&msg, 0, sizeof(msg));
msg.invoke_id = invoke_id;
msg.operation = ROSE_None;
pos = rose_encode_result(ctrl, pos, end, &msg);
return pos;
}
/*!
* \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;
}
return pri_call_apdu_queue(call, msgtype, buffer, end - buffer);
}
/*!
* \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;
}
return 0;
}
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;
if (!ctrl || !call) {
return -1;
}
/* 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);
}
/*!
* \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)
{
pri_error(ctrl, "ROSE REJECT:\n");
if (reject->invoke_id_present) {
pri_error(ctrl, "\tINVOKE ID: %d\n", reject->invoke_id);
}
pri_error(ctrl, "\tPROBLEM: %s\n", rose_reject2str(reject->code));
}
/*!
* \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;
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));
}
/*!
* \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)
{
switch (ctrl->switchtype) {
case PRI_SWITCH_DMS100:
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;
}
/* 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");
}
break;
default:
pri_message(ctrl, "Could not parse invoke of type %d!\n", result->invoke_id);
break;
}
return;
default:
break;
}
switch (result->operation) {
case ROSE_None:
/*
* This is simply a positive ACK to the invoke request.
* The invoke ID must be used to distinguish between outstanding
* invoke requests.
*/
break;
#if 0 /* Not handled yet */
case ROSE_ETSI_ActivationDiversion:
break;
case ROSE_ETSI_DeactivationDiversion:
break;
case ROSE_ETSI_InterrogationDiversion:
break;
#endif /* Not handled yet */
case ROSE_ETSI_CallDeflection:
/* Successfully completed call deflection. Nothing to do. */
break;
case ROSE_ETSI_CallRerouting:
/* Successfully completed call rerouting. Nothing to do. */
break;
#if 0 /* Not handled yet */
case ROSE_ETSI_InterrogateServedUserNumbers:
break;
#endif /* Not handled yet */
#if 0 /* Not handled yet */
case ROSE_ETSI_ChargingRequest:
break;
#endif /* Not handled yet */
#if 0 /* Not handled yet */
case ROSE_ETSI_EctExecute:
break;
case ROSE_ETSI_ExplicitEctExecute:
break;
case ROSE_ETSI_EctLinkIdRequest:
break;
case ROSE_ETSI_EctLoopTest:
break;
#endif /* Not handled yet */
#if 0 /* Not handled yet */
case ROSE_QSIG_ChargeRequest:
break;
case ROSE_QSIG_AocComplete:
break;
#endif /* Not handled yet */
#if 0 /* Not handled yet */
case ROSE_QSIG_CallTransferIdentify:
break;
case ROSE_QSIG_CallTransferInitiate:
break;
case ROSE_QSIG_CallTransferSetup:
break;
#endif /* Not handled yet */
#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:
/* Successfully completed call rerouting. Nothing to do. */
break;
#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 result operation not handled! %s\n",
rose_operation2str(result->operation));
}
break;
}
}
/*!
* \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)
{
struct pri_subcommand *subcmd;
struct q931_party_id party_id;
struct q931_party_redirecting deflection;
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;
}
call->master_call->deflection_in_progress = 1;
q931_party_redirecting_init(&deflection);
/* 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;
}
/* 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 {
deflection.orig_called = call->redirecting.orig_called;
deflection.orig_reason = call->redirecting.orig_reason;
}
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;
}
q931_party_redirecting_init(&deflection);
/* Rerouting from the last address. */
rose_copy_presented_number_unscreened_to_q931(ctrl, &deflection.from.number,
&invoke->args.etsi.CallRerouting.last_rerouting);
/* 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;
}
/* Calling party subaddress update. */
party_id = call->local_id;
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;
}
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:
/*
* Unless otherwise indicated by CONNECT, the divertedToNumber will be
* the remote_id.number.
*
* Fortunately, the connected number ie is supposed to come after the
* facility ie in the same message so it will be processed later.
*/
if (invoke->args.etsi.DivertingLegInformation1.diverted_to_present) {
rose_copy_presented_number_unscreened_to_q931(ctrl, &call->remote_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 (call->remote_id.number.str[0]) {
call->remote_id.number.presentation =
PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
}
} else {
q931_party_number_init(&call->remote_id.number);
call->remote_id.number.valid = 1;
}
/* 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 = call->remote_id.number;
break;
}
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);
/* 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 {
q931_party_number_init(&call->redirecting.from.number);
call->redirecting.from.number.valid = 1;
}
call->redirecting.orig_reason = PRI_REDIR_UNKNOWN;
/* 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.
*
* Fortunately, the connected number ie is supposed to come after the
* facility ie in the same message so it will be processed later.
*/
if (!invoke->args.etsi.DivertingLegInformation3.presentation_allowed_indicator) {
call->remote_id.number.presentation =
PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
call->redirecting.to.number.presentation =
PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
}
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;
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;
}
}
}
/* 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);
/* 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;
/* connectedAddress is put in remote_id */
rose_copy_presented_address_screened_to_q931(ctrl, &call->remote_id,
&invoke->args.qsig.CallTransferActive.connected);
/* 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);
/* 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);
}
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;
/* redirectionNumber is put in party_id.number */
rose_copy_presented_number_screened_to_q931(ctrl, &party_id.number,
&invoke->args.qsig.CallTransferUpdate.redirection);
/* 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);
}
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;
}
}
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;
}
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;
}
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;
}
/* 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:
/*
* Unless otherwise indicated by CONNECT, the nominatedNr will be
* the remote_id.number.
*
* Fortunately, the connected number ie is supposed to come after the
* facility ie in the same message so it will be processed later.
*/
q931_party_number_init(&call->remote_id.number);
rose_copy_number_to_q931(ctrl, &call->remote_id.number,
&invoke->args.qsig.DivertingLegInformation1.nominated_number);
if (call->remote_id.number.str[0]) {
call->remote_id.number.presentation =
PRI_PRES_ALLOWED | PRI_PRES_USER_NUMBER_UNSCREENED;
}
/* 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 = call->remote_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 {
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.
*
* Fortunately, the connected number ie is supposed to come after the
* facility ie in the same message so it will be processed later.
*/
if (!invoke->args.qsig.DivertingLegInformation3.presentation_allowed_indicator) {
call->remote_id.number.presentation =
PRI_PRES_RESTRICTED | PRI_PRES_USER_NUMBER_UNSCREENED;
call->redirecting.to.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;
}
}