ETSI Call Waiting support.
Add the ability to announce a call to an endpoint when there are no B channels available. A call waiting call is a SETUP message with no B channel selected. Relevant specification: EN 300 056, EN 300 057, EN 300 058 Review: https://reviewboard.asterisk.org/r/569/ git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1746 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
9bb285fdc1
commit
e4b8bed7e9
34
libpri.h
34
libpri.h
@ -98,6 +98,7 @@
|
||||
#define PRI_EVENT_RETRIEVE 24 /* RETRIEVE request received */
|
||||
#define PRI_EVENT_RETRIEVE_ACK 25 /* RETRIEVE_ACKNOWLEDGE received */
|
||||
#define PRI_EVENT_RETRIEVE_REJ 26 /* RETRIEVE_REJECT received */
|
||||
#define PRI_EVENT_CONNECT_ACK 27 /* CONNECT_ACKNOWLEDGE received */
|
||||
|
||||
/* Simple states */
|
||||
#define PRI_STATE_DOWN 0
|
||||
@ -1160,6 +1161,13 @@ struct pri_event_retrieve_rej {
|
||||
struct pri_subcommands *subcmds;
|
||||
};
|
||||
|
||||
struct pri_event_connect_ack {
|
||||
int e;
|
||||
int channel;
|
||||
q931_call *call;
|
||||
struct pri_subcommands *subcmds;
|
||||
};
|
||||
|
||||
typedef union {
|
||||
int e;
|
||||
pri_event_generic gen; /* Generic view */
|
||||
@ -1184,6 +1192,7 @@ typedef union {
|
||||
struct pri_event_retrieve retrieve;
|
||||
struct pri_event_retrieve_ack retrieve_ack;
|
||||
struct pri_event_retrieve_rej retrieve_rej;
|
||||
struct pri_event_connect_ack connect_ack;
|
||||
} pri_event;
|
||||
|
||||
struct pri;
|
||||
@ -1284,10 +1293,33 @@ int pri_keypad_facility(struct pri *pri, q931_call *call, const char *digits);
|
||||
Set non-isdn to non-zero if you are not connecting to ISDN equipment */
|
||||
int pri_need_more_info(struct pri *pri, q931_call *call, int channel, int nonisdn);
|
||||
|
||||
/* Answer the call on the given channel (ignored if you called acknowledge already).
|
||||
/* Answer(CONNECT) the call on the given channel.
|
||||
Set non-isdn to non-zero if you are not connecting to ISDN equipment */
|
||||
int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn);
|
||||
|
||||
/*!
|
||||
* \brief Send the manual CONNECT_ACKNOWLEDGE message.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param call Q.931 call leg.
|
||||
* \param channel Selected channel to assign to the call waiting call.
|
||||
* Zero if do not include the channel id ie in the CONNECT_ACKNOWLEDGE message.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int pri_connect_ack(struct pri *ctrl, q931_call *call, int channel);
|
||||
|
||||
/*!
|
||||
* \brief Set the manual CONNECT_ACKNOWLEDGE message enable flag.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param enable TRUE to enable manual CONNECT_ACKNOWLEDGE message feature.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
void pri_connect_ack_enable(struct pri *ctrl, int enable);
|
||||
|
||||
/*!
|
||||
* \brief Give connected line information to a call
|
||||
* \note Could be used instead of pri_sr_set_caller_party() before calling pri_setup().
|
||||
|
17
pri.c
17
pri.c
@ -507,6 +507,7 @@ char *pri_event2str(int id)
|
||||
{ PRI_EVENT_RETRIEVE, "Retrieve" },
|
||||
{ PRI_EVENT_RETRIEVE_ACK, "Retrieve ACK" },
|
||||
{ PRI_EVENT_RETRIEVE_REJ, "Retrieve Rej" },
|
||||
{ PRI_EVENT_CONNECT_ACK, "Connect ACK" },
|
||||
/* *INDENT-ON* */
|
||||
};
|
||||
|
||||
@ -693,6 +694,22 @@ int pri_answer(struct pri *pri, q931_call *call, int channel, int nonisdn)
|
||||
return q931_connect(pri, call, channel, nonisdn);
|
||||
}
|
||||
|
||||
int pri_connect_ack(struct pri *ctrl, q931_call *call, int channel)
|
||||
{
|
||||
if (!ctrl || !call) {
|
||||
return -1;
|
||||
}
|
||||
return q931_connect_acknowledge(ctrl, call, channel);
|
||||
}
|
||||
|
||||
void pri_connect_ack_enable(struct pri *ctrl, int enable)
|
||||
{
|
||||
if (ctrl) {
|
||||
ctrl = PRI_MASTER(ctrl);
|
||||
ctrl->manual_connect_ack = enable ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Copy the PRI party name to the Q.931 party name structure.
|
||||
*
|
||||
|
@ -108,6 +108,7 @@ struct pri {
|
||||
unsigned int cc_support:1;/* TRUE if upper layer supports call completion. */
|
||||
unsigned int transfer_support:1;/* TRUE if the upper layer supports ECT */
|
||||
unsigned int aoc_support:1;/* TRUE if can send AOC events to the upper layer. */
|
||||
unsigned int manual_connect_ack:1;/* TRUE if the CONNECT_ACKNOWLEDGE is sent with API call */
|
||||
|
||||
/* MDL variables */
|
||||
int mdl_error;
|
||||
|
@ -475,6 +475,7 @@ extern int q931_information(struct pri *pri, q931_call *call, char digit);
|
||||
extern int q931_keypad_facility(struct pri *pri, q931_call *call, const char *digits);
|
||||
|
||||
extern int q931_connect(struct pri *pri, q931_call *call, int channel, int nonisdn);
|
||||
int q931_connect_acknowledge(struct pri *ctrl, q931_call *call, int channel);
|
||||
|
||||
extern int q931_release(struct pri *pri, q931_call *call, int cause);
|
||||
|
||||
|
103
q931.c
103
q931.c
@ -1063,6 +1063,10 @@ static int transmit_channel_id(int full_ie, struct pri *ctrl, q931_call *call, i
|
||||
}
|
||||
if (call->chanflags & FLAG_EXCLUSIVE) {
|
||||
/* Channel is exclusive */
|
||||
if (!(ie->data[pos] & 0x03)) {
|
||||
/* An exclusive no channel id ie is to be discarded. */
|
||||
return 0;
|
||||
}
|
||||
ie->data[pos] |= 0x08;
|
||||
} else if (!call->chanflags) {
|
||||
/* Don't need this IE */
|
||||
@ -5179,20 +5183,6 @@ static int q931_release_complete(struct pri *ctrl, q931_call *c, int cause)
|
||||
return res;
|
||||
}
|
||||
|
||||
static int connect_acknowledge_ies[] = { -1 };
|
||||
|
||||
static int gr303_connect_acknowledge_ies[] = { Q931_CHANNEL_IDENT, -1 };
|
||||
|
||||
static int q931_connect_acknowledge(struct pri *ctrl, q931_call *c)
|
||||
{
|
||||
if (ctrl->subchannel && !ctrl->bri) {
|
||||
if (ctrl->localtype == PRI_CPE)
|
||||
return send_message(ctrl, c, Q931_CONNECT_ACKNOWLEDGE, gr303_connect_acknowledge_ies);
|
||||
} else
|
||||
return send_message(ctrl, c, Q931_CONNECT_ACKNOWLEDGE, connect_acknowledge_ies);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
|
||||
*
|
||||
@ -5218,6 +5208,49 @@ struct q931_call *q931_find_winning_call(struct q931_call *call)
|
||||
return call;
|
||||
}
|
||||
|
||||
static int connect_ack_ies[] = { -1 };
|
||||
static int connect_ack_w_chan_id_ies[] = { Q931_CHANNEL_IDENT, -1 };
|
||||
static int gr303_connect_ack_ies[] = { Q931_CHANNEL_IDENT, -1 };
|
||||
|
||||
int q931_connect_acknowledge(struct pri *ctrl, q931_call *call, int channel)
|
||||
{
|
||||
int *use_ies;
|
||||
struct q931_call *winner;
|
||||
|
||||
winner = q931_find_winning_call(call);
|
||||
if (!winner) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (winner != call) {
|
||||
UPDATE_OURCALLSTATE(ctrl, call, Q931_CALL_STATE_ACTIVE);
|
||||
call->peercallstate = Q931_CALL_STATE_ACTIVE;
|
||||
}
|
||||
UPDATE_OURCALLSTATE(ctrl, winner, Q931_CALL_STATE_ACTIVE);
|
||||
winner->peercallstate = Q931_CALL_STATE_ACTIVE;
|
||||
if (channel) {
|
||||
winner->ds1no = (channel & 0xff00) >> 8;
|
||||
winner->ds1explicit = (channel & 0x10000) >> 16;
|
||||
winner->channelno = channel & 0xff;
|
||||
winner->chanflags &= ~FLAG_PREFERRED;
|
||||
winner->chanflags |= FLAG_EXCLUSIVE;
|
||||
}
|
||||
use_ies = NULL;
|
||||
if (ctrl->subchannel && !ctrl->bri) {
|
||||
if (ctrl->localtype == PRI_CPE) {
|
||||
use_ies = gr303_connect_ack_ies;
|
||||
}
|
||||
} else if (channel) {
|
||||
use_ies = connect_ack_w_chan_id_ies;
|
||||
} else {
|
||||
use_ies = connect_ack_ies;
|
||||
}
|
||||
if (use_ies) {
|
||||
return send_message(ctrl, winner, Q931_CONNECT_ACKNOWLEDGE, use_ies);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Send HOLD message response wait timeout.
|
||||
@ -5693,6 +5726,8 @@ static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause)
|
||||
release_compl = 1;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case PRI_CAUSE_INCOMPATIBLE_DESTINATION:
|
||||
/* See Q.931 Section 5.3.2 a) */
|
||||
switch (c->ourcallstate) {
|
||||
case Q931_CALL_STATE_NULL:
|
||||
@ -5705,6 +5740,13 @@ static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause)
|
||||
disconnect = 0;
|
||||
release_compl = 1;
|
||||
break;
|
||||
case Q931_CALL_STATE_CONNECT_REQUEST:
|
||||
/*
|
||||
* Send RELEASE because the B channel negotiation failed
|
||||
* for call waiting.
|
||||
*/
|
||||
disconnect = 0;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* Send DISCONNECT because some other message
|
||||
@ -7291,8 +7333,6 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
q931_status(ctrl, c, PRI_CAUSE_WRONG_MESSAGE);
|
||||
break;
|
||||
}
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
|
||||
c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
|
||||
|
||||
ctrl->ev.e = PRI_EVENT_ANSWER;
|
||||
ctrl->ev.answer.subcmds = &ctrl->subcmds;
|
||||
@ -7304,7 +7344,12 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
libpri_copy_string(ctrl->ev.answer.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.answer.useruserinfo));
|
||||
c->useruserinfo[0] = '\0';
|
||||
|
||||
q931_connect_acknowledge(ctrl, c);
|
||||
if (!PRI_MASTER(ctrl)->manual_connect_ack) {
|
||||
q931_connect_acknowledge(ctrl, c, 0);
|
||||
} else {
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CONNECT_REQUEST);
|
||||
c->peercallstate = Q931_CALL_STATE_CONNECT_REQUEST;
|
||||
}
|
||||
|
||||
if (c->cis_auto_disconnect && c->cis_call) {
|
||||
/* Make sure WE release when we initiate a signalling only connection */
|
||||
@ -7390,14 +7435,26 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
|
||||
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
|
||||
break;
|
||||
}
|
||||
if (!(c->ourcallstate == Q931_CALL_STATE_CONNECT_REQUEST) &&
|
||||
!(c->ourcallstate == Q931_CALL_STATE_ACTIVE &&
|
||||
(ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG))) {
|
||||
q931_status(ctrl,c,PRI_CAUSE_WRONG_MESSAGE);
|
||||
switch (c->ourcallstate) {
|
||||
default:
|
||||
if (ctrl->localtype == PRI_NETWORK || ctrl->switchtype == PRI_SWITCH_QSIG) {
|
||||
q931_status(ctrl, c, PRI_CAUSE_WRONG_MESSAGE);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case Q931_CALL_STATE_CONNECT_REQUEST:
|
||||
case Q931_CALL_STATE_ACTIVE:
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
|
||||
c->peercallstate = Q931_CALL_STATE_ACTIVE;
|
||||
if (PRI_MASTER(ctrl)->manual_connect_ack) {
|
||||
ctrl->ev.e = PRI_EVENT_CONNECT_ACK;
|
||||
ctrl->ev.connect_ack.subcmds = &ctrl->subcmds;
|
||||
ctrl->ev.connect_ack.channel = q931_encode_channel(c);
|
||||
ctrl->ev.connect_ack.call = c->master_call;
|
||||
return Q931_RES_HAVEEVENT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_ACTIVE);
|
||||
c->peercallstate = Q931_CALL_STATE_ACTIVE;
|
||||
break;
|
||||
case Q931_STATUS:
|
||||
if (missingmand) {
|
||||
|
Loading…
Reference in New Issue
Block a user