[libpri-commits] rmudgett: branch rmudgett/ntptmp r1092 - /team/rmudgett/ntptmp/
SVN commits to the libpri project
libpri-commits at lists.digium.com
Thu Sep 17 13:48:25 CDT 2009
Author: rmudgett
Date: Thu Sep 17 13:48:21 2009
New Revision: 1092
URL: http://svn.asterisk.org/svn-view/libpri?view=rev&rev=1092
Log:
Merge team/rmudgett/facility and setup for automerge from there.
Modified:
team/rmudgett/ntptmp/ (props changed)
team/rmudgett/ntptmp/libpri.h
team/rmudgett/ntptmp/pri.c
team/rmudgett/ntptmp/pri_internal.h
team/rmudgett/ntptmp/pri_q931.h
team/rmudgett/ntptmp/q931.c
Propchange: team/rmudgett/ntptmp/
------------------------------------------------------------------------------
automerge = *
Propchange: team/rmudgett/ntptmp/
------------------------------------------------------------------------------
automerge-propname = ntptmp-integrated
Propchange: team/rmudgett/ntptmp/
------------------------------------------------------------------------------
ntptmp-integrated = /team/rmudgett/facility:1-1090
Modified: team/rmudgett/ntptmp/libpri.h
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/libpri.h?view=diff&rev=1092&r1=1091&r2=1092
==============================================================================
--- team/rmudgett/ntptmp/libpri.h (original)
+++ team/rmudgett/ntptmp/libpri.h Thu Sep 17 13:48:21 2009
@@ -91,6 +91,12 @@
#define PRI_EVENT_KEYPAD_DIGIT 18 /* When we receive during ACTIVE state (INFORMATION) */
#define PRI_EVENT_SERVICE 19 /* SERVICE maintenance message */
#define PRI_EVENT_SERVICE_ACK 20 /* SERVICE maintenance acknowledgement message */
+#define PRI_EVENT_HOLD 21 /* HOLD request received */
+#define PRI_EVENT_HOLD_ACK 22 /* HOLD_ACKNOWLEDGE received */
+#define PRI_EVENT_HOLD_REJ 23 /* HOLD_REJECT received */
+#define PRI_EVENT_RETRIEVE 24 /* RETRIEVE request received */
+#define PRI_EVENT_RETRIEVE_ACK 25 /* RETRIEVE_ACKNOWLEDGE received */
+#define PRI_EVENT_RETRIEVE_REJ 26 /* RETRIEVE_REJECT received */
/* Simple states */
#define PRI_STATE_DOWN 0
@@ -200,6 +206,7 @@
#define PRI_CAUSE_NO_ANSWER 19
#define PRI_CAUSE_CALL_REJECTED 21
#define PRI_CAUSE_NUMBER_CHANGED 22
+#define PRI_CAUSE_NONSELECTED_USER_CLEARING 26
#define PRI_CAUSE_DESTINATION_OUT_OF_ORDER 27
#define PRI_CAUSE_INVALID_NUMBER_FORMAT 28
#define PRI_CAUSE_FACILITY_REJECTED 29 /* !Q.SIG */
@@ -212,6 +219,7 @@
#define PRI_CAUSE_ACCESS_INFO_DISCARDED 43 /* !Q.SIG */
#define PRI_CAUSE_REQUESTED_CHAN_UNAVAIL 44
#define PRI_CAUSE_PRE_EMPTED 45 /* !Q.SIG */
+#define PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED 47
#define PRI_CAUSE_FACILITY_NOT_SUBSCRIBED 50 /* !Q.SIG */
#define PRI_CAUSE_OUTGOING_CALL_BARRED 52 /* !Q.SIG */
#define PRI_CAUSE_INCOMING_CALL_BARRED 54 /* !Q.SIG */
@@ -497,13 +505,14 @@
* Event channel parameter encoding:
* 3322 2222 2222 1111 1111 1100 0000 0000
* 1098 7654 3210 9876 5432 1098 7654 3210
- * xxxx xxxx xxxx xxDC BBBBBBBBB AAAAAAAAA
+ * xxxx xxxx xxxx xEDC BBBBBBBBB AAAAAAAAA
*
* Bit field
* A - B channel
* B - Span (DS1) (0 - 127)
* C - DS1 Explicit bit
* D - D channel (cis_call) bit (status only)
+ * E - Call is held bit (status only)
*
* B channel values:
* 0 - No channel (ISDN uses for call waiting feature)
@@ -649,6 +658,7 @@
int channel;
int info;
struct pri_subcommands *subcmds;
+ q931_call *call;
} pri_event_notify;
typedef struct pri_event_keypad_digit {
@@ -670,6 +680,51 @@
int channel;
int changestatus;
} pri_event_service_ack;
+
+struct pri_event_hold {
+ int e;
+ int channel;
+ q931_call *call;
+ struct pri_subcommands *subcmds;
+};
+
+struct pri_event_hold_ack {
+ int e;
+ int channel;
+ q931_call *call;
+ struct pri_subcommands *subcmds;
+};
+
+struct pri_event_hold_rej {
+ int e;
+ int channel;
+ q931_call *call;
+ int cause;
+ struct pri_subcommands *subcmds;
+};
+
+struct pri_event_retrieve {
+ int e;
+ int channel;
+ q931_call *call;
+ int flexible; /* Are we flexible with our channel selection? */
+ struct pri_subcommands *subcmds;
+};
+
+struct pri_event_retrieve_ack {
+ int e;
+ int channel;
+ q931_call *call;
+ struct pri_subcommands *subcmds;
+};
+
+struct pri_event_retrieve_rej {
+ int e;
+ int channel;
+ q931_call *call;
+ int cause;
+ struct pri_subcommands *subcmds;
+};
typedef union {
int e;
@@ -689,6 +744,12 @@
pri_event_service service; /* service message */
pri_event_service_ack service_ack; /* service acknowledgement message */
struct pri_event_facility facility;
+ struct pri_event_hold hold;
+ struct pri_event_hold_ack hold_ack;
+ struct pri_event_hold_rej hold_rej;
+ struct pri_event_retrieve retrieve;
+ struct pri_event_retrieve_ack retrieve_ack;
+ struct pri_event_retrieve_rej retrieve_rej;
} pri_event;
struct pri;
@@ -967,6 +1028,76 @@
int pri_notify(struct pri *pri, q931_call *c, int channel, int info);
int pri_callrerouting_facility(struct pri *pri, q931_call *call, const char *dest, const char* original, const char* reason);
+
+/*!
+ * \brief Send the HOLD message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_hold(struct pri *ctrl, q931_call *call);
+
+/*!
+ * \brief Send the HOLD ACKNOWLEDGE message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_hold_ack(struct pri *ctrl, q931_call *call);
+
+/*!
+ * \brief Send the HOLD REJECT message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param cause Q.931 cause code for rejecting the hold request.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause);
+
+/*!
+ * \brief Send the RETRIEVE message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param channel Encoded channel id to use. If zero do not send channel id.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_retrieve(struct pri *ctrl, q931_call *call, int channel);
+
+/*!
+ * \brief Send the RETRIEVE ACKNOWLEDGE message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param channel Encoded channel id to use.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel);
+
+/*!
+ * \brief Send the RETRIEVE REJECT message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param cause Q.931 cause code for rejecting the retrieve request.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause);
/* Get/Set PRI Timers */
#define PRI_GETSET_TIMERS
@@ -1010,6 +1141,9 @@
PRI_TIMER_TM20, /*!< Maximum time awaiting XID response */
PRI_TIMER_NM20, /*!< Number of XID retransmits */
+ PRI_TIMER_T_HOLD, /*!< Maximum time to wait for HOLD request response. */
+ PRI_TIMER_T_RETRIEVE, /*!< Maximum time to wait for RETRIEVE request response. */
+
/* Must be last in the enum list */
_PRI_MAX_TIMERS,
PRI_MAX_TIMERS = (_PRI_MAX_TIMERS < 32) ? 32 : _PRI_MAX_TIMERS
Modified: team/rmudgett/ntptmp/pri.c
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/pri.c?view=diff&rev=1092&r1=1091&r2=1092
==============================================================================
--- team/rmudgett/ntptmp/pri.c (original)
+++ team/rmudgett/ntptmp/pri.c Thu Sep 17 13:48:21 2009
@@ -86,6 +86,8 @@
{ "T320", PRI_TIMER_T320, PRI_ALL_SWITCHES },
{ "T321", PRI_TIMER_T321, PRI_ALL_SWITCHES },
{ "T322", PRI_TIMER_T322, PRI_ALL_SWITCHES },
+ { "T-HOLD", PRI_TIMER_T_HOLD, PRI_ALL_SWITCHES },
+ { "T-RETRIEVE", PRI_TIMER_T_RETRIEVE, PRI_ALL_SWITCHES },
/* *INDENT-ON* */
};
@@ -151,6 +153,9 @@
ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */
ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */
ctrl->timers[PRI_TIMER_T303] = 4 * 1000; /* Length between SETUP retransmissions and timeout */
+
+ ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000; /* Wait for HOLD request response. */
+ ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */
/* Set any switch specific override default values */
switch (switchtype) {
@@ -1284,6 +1289,54 @@
}
}
+int pri_hold(struct pri *ctrl, q931_call *call)
+{
+ if (!ctrl || !call) {
+ return -1;
+ }
+ return q931_send_hold(ctrl, call);
+}
+
+int pri_hold_ack(struct pri *ctrl, q931_call *call)
+{
+ if (!ctrl || !call) {
+ return -1;
+ }
+ return q931_send_hold_ack(ctrl, call);
+}
+
+int pri_hold_rej(struct pri *ctrl, q931_call *call, int cause)
+{
+ if (!ctrl || !call) {
+ return -1;
+ }
+ return q931_send_hold_rej(ctrl, call, cause);
+}
+
+int pri_retrieve(struct pri *ctrl, q931_call *call, int channel)
+{
+ if (!ctrl || !call) {
+ return -1;
+ }
+ return q931_send_retrieve(ctrl, call, channel);
+}
+
+int pri_retrieve_ack(struct pri *ctrl, q931_call *call, int channel)
+{
+ if (!ctrl || !call) {
+ return -1;
+ }
+ return q931_send_retrieve_ack(ctrl, call, channel);
+}
+
+int pri_retrieve_rej(struct pri *ctrl, q931_call *call, int cause)
+{
+ if (!ctrl || !call) {
+ return -1;
+ }
+ return q931_send_retrieve_rej(ctrl, call, cause);
+}
+
void pri_sr_set_reversecharge(struct pri_sr *sr, int requested)
{
sr->reversecharge = requested;
Modified: team/rmudgett/ntptmp/pri_internal.h
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/pri_internal.h?view=diff&rev=1092&r1=1091&r2=1092
==============================================================================
--- team/rmudgett/ntptmp/pri_internal.h (original)
+++ team/rmudgett/ntptmp/pri_internal.h Thu Sep 17 13:48:21 2009
@@ -334,6 +334,22 @@
INCOMING_CT_STATE_POST_CONNECTED_LINE
};
+/*! Call hold supplementary states. */
+enum Q931_HOLD_STATE {
+ /*! \brief No call hold activity. */
+ Q931_HOLD_STATE_IDLE,
+ /*! \brief Request made to hold call. */
+ Q931_HOLD_STATE_HOLD_REQ,
+ /*! \brief Request received to hold call. */
+ Q931_HOLD_STATE_HOLD_IND,
+ /*! \brief Call is held. */
+ Q931_HOLD_STATE_CALL_HELD,
+ /*! \brief Request made to retrieve call. */
+ Q931_HOLD_STATE_RETRIEVE_REQ,
+ /*! \brief Request received to retrieve call. */
+ Q931_HOLD_STATE_RETRIEVE_IND,
+};
+
/* q931_call datastructure */
struct q931_call {
struct pri *pri; /* PRI */
@@ -449,6 +465,10 @@
/*! \brief Incoming call transfer state. */
enum INCOMING_CT_STATE incoming_ct_state;
+ /*! Call hold supplementary state. */
+ enum Q931_HOLD_STATE hold_state;
+ /*! Call hold event timer */
+ int hold_timer;
int useruserprotocoldisc;
char useruserinfo[256];
@@ -518,9 +538,9 @@
void q931_party_id_fixup(const struct pri *ctrl, struct q931_party_id *id);
int q931_party_id_presentation(const struct q931_party_id *id);
-const char *q931_call_state_str(int callstate);
-
-int q931_is_ptmp(struct pri *ctrl);
+const char *q931_call_state_str(enum Q931_CALL_STATE callstate);
+
+int q931_is_ptmp(const struct pri *ctrl);
struct pri_subcommand *q931_alloc_subcommand(struct pri *ctrl);
int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number);
Modified: team/rmudgett/ntptmp/pri_q931.h
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/pri_q931.h?view=diff&rev=1092&r1=1091&r2=1092
==============================================================================
--- team/rmudgett/ntptmp/pri_q931.h (original)
+++ team/rmudgett/ntptmp/pri_q931.h Thu Sep 17 13:48:21 2009
@@ -470,4 +470,12 @@
extern void q931_dl_indication(struct pri *pri, int event);
+int q931_send_hold(struct pri *ctrl, q931_call *call);
+int q931_send_hold_ack(struct pri *ctrl, q931_call *call);
+int q931_send_hold_rej(struct pri *ctrl, q931_call *call, int cause);
+
+int q931_send_retrieve(struct pri *ctrl, q931_call *call, int channel);
+int q931_send_retrieve_ack(struct pri *ctrl, q931_call *call, int channel);
+int q931_send_retrieve_rej(struct pri *ctrl, q931_call *call, int cause);
+
#endif
Modified: team/rmudgett/ntptmp/q931.c
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/q931.c?view=diff&rev=1092&r1=1091&r2=1092
==============================================================================
--- team/rmudgett/ntptmp/q931.c (original)
+++ team/rmudgett/ntptmp/q931.c Thu Sep 17 13:48:21 2009
@@ -80,10 +80,10 @@
/* Call Management */
{ Q931_HOLD, "HOLD" },
{ Q931_HOLD_ACKNOWLEDGE, "HOLD ACKNOWLEDGE" },
- { Q931_HOLD_REJECT, "HOLD REJECT" },
+ { Q931_HOLD_REJECT, "HOLD REJECT", { Q931_CAUSE } },
{ Q931_RETRIEVE, "RETRIEVE" },
{ Q931_RETRIEVE_ACKNOWLEDGE, "RETRIEVE ACKNOWLEDGE" },
- { Q931_RETRIEVE_REJECT, "RETRIEVE REJECT" },
+ { Q931_RETRIEVE_REJECT, "RETRIEVE REJECT", { Q931_CAUSE } },
{ Q931_RESUME, "RESUME" },
{ Q931_RESUME_ACKNOWLEDGE, "RESUME ACKNOWLEDGE", { Q931_CHANNEL_IDENT } },
{ Q931_RESUME_REJECT, "RESUME REJECT", { Q931_CAUSE } },
@@ -235,15 +235,37 @@
#if 1
/* Update call state with transition trace. */
-#define UPDATE_OURCALLSTATE(ctrl,c,newstate) do {\
- if (ctrl->debug & (PRI_DEBUG_Q931_STATE) && c->ourcallstate != newstate) \
- pri_message(ctrl, DBGHEAD "call %d on channel %d enters state %d (%s)\n", DBGINFO, \
- c->cr, c->channelno, newstate, q931_call_state_str(newstate)); \
- c->ourcallstate = newstate; \
+#define UPDATE_OURCALLSTATE(ctrl, call, newstate) \
+ do { \
+ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) && (call)->ourcallstate != (newstate)) { \
+ pri_message((ctrl), \
+ DBGHEAD "Call %d on channel %d enters state %d (%s). Hold state: %s\n", \
+ DBGINFO, (call)->cr, (call)->channelno, (newstate), \
+ q931_call_state_str(newstate), q931_hold_state_str((call)->hold_state)); \
+ } \
+ (call)->ourcallstate = (newstate); \
} while (0)
#else
/* Update call state with no trace. */
-#define UPDATE_OURCALLSTATE(ctrl,c,newstate) c->ourcallstate = newstate
+#define UPDATE_OURCALLSTATE(ctrl, call, newstate) (call)->ourcallstate = (newstate)
+#endif
+
+#if 1
+/* Update hold state with transition trace. */
+#define UPDATE_HOLD_STATE(ctrl, call, newstate) \
+ do { \
+ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) && (call)->hold_state != (newstate)) { \
+ pri_message((ctrl), \
+ DBGHEAD "Call %d on channel %d in state %d (%s) enters Hold state: %s\n", \
+ DBGINFO, (call)->cr, (call)->channelno, (call)->ourcallstate, \
+ q931_call_state_str((call)->ourcallstate), \
+ q931_hold_state_str(newstate)); \
+ } \
+ (call)->hold_state = (newstate); \
+ } while (0)
+#else
+/* Update hold state with no trace. */
+#define UPDATE_HOLD_STATE(ctrl, call, newstate) (call)->hold_state = (newstate)
#endif
struct ie {
@@ -271,8 +293,20 @@
*/
static int q931_encode_channel(const q931_call *call)
{
+ int held_call;
+
+ switch (call->hold_state) {
+ case Q931_HOLD_STATE_CALL_HELD:
+ case Q931_HOLD_STATE_RETRIEVE_REQ:
+ case Q931_HOLD_STATE_RETRIEVE_IND:
+ held_call = 1 << 18;
+ break;
+ default:
+ held_call = 0;
+ break;
+ }
return call->channelno | (call->ds1no << 8) | (call->ds1explicit << 16)
- | (call->cis_call << 17);
+ | (call->cis_call << 17) | held_call;
}
/*!
@@ -283,7 +317,7 @@
* \retval TRUE if in PTMP mode.
* \retval FALSE otherwise.
*/
-int q931_is_ptmp(struct pri *ctrl)
+int q931_is_ptmp(const struct pri *ctrl)
{
/* Check master control structure */
for (; ctrl->master; ctrl = ctrl->master) {
@@ -2138,7 +2172,7 @@
*
* \return String equivalent of the given Q.931 call state.
*/
-const char *q931_call_state_str(int callstate)
+const char *q931_call_state_str(enum Q931_CALL_STATE callstate)
{
static struct msgtype callstates[] = {
/* *INDENT-OFF* */
@@ -2164,7 +2198,30 @@
{ Q931_CALL_STATE_RESTART, "Restart" },
/* *INDENT-ON* */
};
- return code2str(callstate, callstates, sizeof(callstates) / sizeof(callstates[0]));
+ return code2str(callstate, callstates, ARRAY_LEN(callstates));
+}
+
+/*!
+ * \internal
+ * \brief Convert the Q.932 supplementary hold state to a string.
+ *
+ * \param state Q.932 supplementary hold state.
+ *
+ * \return String equivalent of the given hold state.
+ */
+static const char *q931_hold_state_str(enum Q931_HOLD_STATE state)
+{
+ static struct msgtype hold_states[] = {
+/* *INDENT-OFF* */
+ { Q931_HOLD_STATE_IDLE, "Idle" },
+ { Q931_HOLD_STATE_HOLD_REQ, "Hold Request" },
+ { Q931_HOLD_STATE_HOLD_IND, "Hold Indication" },
+ { Q931_HOLD_STATE_CALL_HELD, "Call Held" },
+ { Q931_HOLD_STATE_RETRIEVE_REQ, "Retrieve Request" },
+ { Q931_HOLD_STATE_RETRIEVE_IND, "Retrieve Indication" },
+/* *INDENT-ON* */
+ };
+ return code2str(state, hold_states, ARRAY_LEN(hold_states));
}
static void dump_call_state(int full_ie, struct pri *ctrl, q931_ie *ie, int len, char prefix)
@@ -3125,6 +3182,7 @@
{
stop_t303(cur);
pri_schedule_del(cur->pri, cur->retranstimer);
+ pri_schedule_del(cur->pri, cur->hold_timer);
pri_call_apdu_queue_cleanup(cur);
free(cur);
}
@@ -3233,9 +3291,10 @@
*ctrl->callpool = cur->next;
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
pri_message(ctrl,
- "NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",
+ "NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s, hold-state %s\n",
q931_call_state_str(cur->ourcallstate),
- q931_call_state_str(cur->peercallstate));
+ q931_call_state_str(cur->peercallstate),
+ q931_hold_state_str(cur->hold_state));
cleanup_and_free_call(c);
return;
}
@@ -4176,6 +4235,389 @@
return 0;
}
+/*!
+ * \internal
+ * \brief Send HOLD message response wait timeout.
+ *
+ * \param data Q.931 call leg.
+ *
+ * \return Nothing
+ */
+static void q931_hold_timeout(void *data)
+{
+ struct q931_call *call = data;
+ struct pri *ctrl = call->pri;
+
+ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
+ pri_message(ctrl, "Time-out waiting for HOLD response\n");
+ }
+
+ /* Ensure that the timer is deleted. */
+ pri_schedule_del(ctrl, call->hold_timer);
+ call->hold_timer = 0;
+
+ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE);
+
+ q931_clr_subcommands(ctrl);
+ ctrl->schedev = 1;
+ ctrl->ev.e = PRI_EVENT_HOLD_REJ;
+ ctrl->ev.hold_rej.channel = q931_encode_channel(call);
+ ctrl->ev.hold_rej.call = call->master_call;
+ ctrl->ev.hold_rej.cause = PRI_CAUSE_MESSAGE_TYPE_NONEXIST;
+ ctrl->ev.hold_rej.subcmds = &ctrl->subcmds;
+}
+
+/*!
+ * \internal
+ * \brief Determine if a hold request is allowed now.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ *
+ * \retval TRUE if we can send a HOLD request.
+ * \retval FALSE if not allowed.
+ */
+static int q931_is_hold_allowed(const struct pri *ctrl, const q931_call *call)
+{
+ int allowed;
+
+ allowed = 0;
+ switch (call->ourcallstate) {
+ case Q931_CALL_STATE_CALL_RECEIVED:
+ case Q931_CALL_STATE_CONNECT_REQUEST:
+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+ if (q931_is_ptmp(ctrl)) {
+ /* HOLD request only allowed in these states if point-to-point mode. */
+ break;
+ }
+ /* Fall through */
+ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_CALL_DELIVERED:
+ case Q931_CALL_STATE_ACTIVE:
+ switch (call->hold_state) {
+ case Q931_HOLD_STATE_IDLE:
+ allowed = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case Q931_CALL_STATE_DISCONNECT_INDICATION:
+ case Q931_CALL_STATE_RELEASE_REQUEST:
+ /* Ignore HOLD request in these states. */
+ break;
+ default:
+ break;
+ }
+
+ return allowed;
+}
+
+static int hold_ies[] = {
+ -1
+};
+
+/*!
+ * \brief Send the HOLD message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_send_hold(struct pri *ctrl, q931_call *call)
+{
+ if (!q931_is_hold_allowed(ctrl, call)) {
+ return -1;
+ }
+ pri_schedule_del(ctrl, call->hold_timer);
+ call->hold_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T_HOLD],
+ q931_hold_timeout, call);
+ if (send_message(ctrl, call, Q931_HOLD, hold_ies)) {
+ pri_schedule_del(ctrl, call->hold_timer);
+ call->hold_timer = 0;
+ return -1;
+ }
+ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_HOLD_REQ);
+ return 0;
+}
+
+static int hold_ack_ies[] = {
+ -1
+};
+
+/*!
+ * \brief Send the HOLD ACKNOWLEDGE message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_send_hold_ack(struct pri *ctrl, q931_call *call)
+{
+ /* Stop the upper layer does not implement guard timer. */
+ pri_schedule_del(ctrl, call->hold_timer);
+ call->hold_timer = 0;
+
+ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD);
+
+ /* Call is now on hold so forget the channel. */
+ call->channelno = 0;/* No channel */
+ call->ds1no = 0;
+ call->ds1explicit = 0;
+ call->chanflags = 0;
+
+ return send_message(ctrl, call, Q931_HOLD_ACKNOWLEDGE, hold_ack_ies);
+}
+
+static int hold_reject_ies[] = {
+ Q931_CAUSE,
+ -1
+};
+
+/*!
+ * \brief Send the HOLD REJECT message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param cause Q.931 cause code for rejecting the hold request.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_send_hold_rej(struct pri *ctrl, q931_call *call, int cause)
+{
+ /* Stop the upper layer does not implement guard timer. */
+ pri_schedule_del(ctrl, call->hold_timer);
+ call->hold_timer = 0;
+
+ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE);
+
+ call->cause = cause;
+ call->causecode = CODE_CCITT;
+ call->causeloc = LOC_PRIV_NET_LOCAL_USER;
+ return send_message(ctrl, call, Q931_HOLD_REJECT, hold_reject_ies);
+}
+
+/*!
+ * \internal
+ * \brief Send HOLD message response guard timeout.
+ *
+ * \param data Q.931 call leg.
+ *
+ * \return Nothing
+ */
+static void q931_hold_guard_timeout(void *data)
+{
+ struct q931_call *call = data;
+ struct pri *ctrl = call->pri;
+
+ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
+ pri_message(ctrl,
+ "Time-out for upper layer HOLD response (assume not implemented)\n");
+ }
+
+ q931_send_hold_rej(ctrl, call, PRI_CAUSE_FACILITY_NOT_IMPLEMENTED);
+}
+
+/*!
+ * \internal
+ * \brief Send RETRIEVE message response wait timeout.
+ *
+ * \param data Q.931 call leg.
+ *
+ * \return Nothing
+ */
+static void q931_retrieve_timeout(void *data)
+{
+ struct q931_call *call = data;
+ struct pri *ctrl = call->pri;
+
+ if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
+ pri_message(ctrl, "Time-out waiting for RETRIEVE response\n");
+ }
+
+ /* Ensure that the timer is deleted. */
+ pri_schedule_del(ctrl, call->hold_timer);
+ call->hold_timer = 0;
+
+ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD);
+
+ /* Call is still on hold so forget the channel. */
+ call->channelno = 0;/* No channel */
+ call->ds1no = 0;
+ call->ds1explicit = 0;
+ call->chanflags = 0;
+
+ q931_clr_subcommands(ctrl);
+ ctrl->schedev = 1;
+ ctrl->ev.e = PRI_EVENT_RETRIEVE_REJ;
+ ctrl->ev.retrieve_rej.channel = q931_encode_channel(call);
+ ctrl->ev.retrieve_rej.call = call->master_call;
+ ctrl->ev.retrieve_rej.cause = PRI_CAUSE_MESSAGE_TYPE_NONEXIST;
+ ctrl->ev.retrieve_rej.subcmds = &ctrl->subcmds;
+}
+
+/*!
+ * \internal
+ * \brief Determine if a retrieve request is allowed now.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ *
+ * \retval TRUE if we can send a RETRIEVE request.
+ * \retval FALSE if not allowed.
+ */
+static int q931_is_retrieve_allowed(const struct pri *ctrl, const q931_call *call)
+{
+ int allowed;
+
+ allowed = 0;
+ switch (call->ourcallstate) {
+ case Q931_CALL_STATE_CALL_RECEIVED:
+ case Q931_CALL_STATE_CONNECT_REQUEST:
+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+ if (q931_is_ptmp(ctrl)) {
+ /* RETRIEVE request only allowed in these states if point-to-point mode. */
+ break;
+ }
+ /* Fall through */
+ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_CALL_DELIVERED:
+ case Q931_CALL_STATE_ACTIVE:
+ switch (call->hold_state) {
+ case Q931_HOLD_STATE_CALL_HELD:
+ allowed = 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case Q931_CALL_STATE_DISCONNECT_INDICATION:
+ case Q931_CALL_STATE_RELEASE_REQUEST:
+ /* Ignore RETRIEVE request in these states. */
+ break;
+ default:
+ break;
+ }
+
+ return allowed;
+}
+
+static int retrieve_ies[] = {
+ Q931_CHANNEL_IDENT,
+ -1
+};
+
+/*!
+ * \brief Send the RETRIEVE message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param channel Encoded channel id to use. If zero do not send channel id.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_send_retrieve(struct pri *ctrl, q931_call *call, int channel)
+{
+ if (!q931_is_retrieve_allowed(ctrl, call)) {
+ return -1;
+ }
+
+ if (channel) {
+ call->ds1no = (channel & 0xff00) >> 8;
+ call->ds1explicit = (channel & 0x10000) >> 16;
+ call->channelno = channel & 0xff;
+ if (ctrl->localtype == PRI_NETWORK) {
+ call->chanflags = FLAG_EXCLUSIVE;
+ } else {
+ call->chanflags = FLAG_PREFERRED;
+ }
+ } else {
+ /* Do not send Q931_CHANNEL_IDENT */
+ call->chanflags = 0;
+ }
+
+ pri_schedule_del(ctrl, call->hold_timer);
+ call->hold_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T_RETRIEVE],
+ q931_retrieve_timeout, call);
+ if (send_message(ctrl, call, Q931_RETRIEVE, retrieve_ies)) {
+ pri_schedule_del(ctrl, call->hold_timer);
+ call->hold_timer = 0;
+
+ /* Call is still on hold so forget the channel. */
+ call->channelno = 0;/* No channel */
+ call->ds1no = 0;
+ call->ds1explicit = 0;
+ call->chanflags = 0;
+ return -1;
+ }
+ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_RETRIEVE_REQ);
+ return 0;
+}
+
+static int retrieve_ack_ies[] = {
+ Q931_CHANNEL_IDENT,
+ -1
+};
+
+/*!
+ * \brief Send the RETRIEVE ACKNOWLEDGE message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param channel Encoded channel id to use.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_send_retrieve_ack(struct pri *ctrl, q931_call *call, int channel)
+{
+ call->ds1no = (channel & 0xff00) >> 8;
+ call->ds1explicit = (channel & 0x10000) >> 16;
+ call->channelno = channel & 0xff;
+ call->chanflags = FLAG_EXCLUSIVE;
+
+ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_IDLE);
+
+ return send_message(ctrl, call, Q931_RETRIEVE_ACKNOWLEDGE, retrieve_ack_ies);
+}
+
+static int retrieve_reject_ies[] = {
+ Q931_CAUSE,
+ -1
+};
+
+/*!
+ * \brief Send the RETRIEVE REJECT message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param cause Q.931 cause code for rejecting the retrieve request.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_send_retrieve_rej(struct pri *ctrl, q931_call *call, int cause)
+{
+ /* Call is still on hold so forget the channel. */
+ call->channelno = 0;/* No channel */
+ call->ds1no = 0;
+ call->ds1explicit = 0;
+ call->chanflags = 0;
+
+ UPDATE_HOLD_STATE(ctrl, call, Q931_HOLD_STATE_CALL_HELD);
+
+ call->cause = cause;
+ call->causecode = CODE_CCITT;
+ call->causeloc = LOC_PRIV_NET_LOCAL_USER;
+ return send_message(ctrl, call, Q931_RETRIEVE_REJECT, retrieve_reject_ies);
+}
+
static int pri_internal_clear(void *data);
/* Fake RELEASE for NT-PTMP initiated SETUPs w/o response */
@@ -4207,9 +4649,10 @@
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
pri_message(ctrl,
- "NEW_HANGUP DEBUG: Calling q931_hangup, ourstate %s, peerstate %s\n",
+ "NEW_HANGUP DEBUG: Calling q931_hangup, ourstate %s, peerstate %s, hold-state %s\n",
q931_call_state_str(c->ourcallstate),
- q931_call_state_str(c->peercallstate));
+ q931_call_state_str(c->peercallstate),
+ q931_hold_state_str(c->hold_state));
if (!ctrl || !c)
return -1;
/* If mandatory IE was missing, insist upon that cause code */
@@ -4227,7 +4670,7 @@
break;
case PRI_CAUSE_CHANNEL_UNACCEPTABLE:
case PRI_CAUSE_CALL_AWARDED_DELIVERED:
- case 26:
+ case PRI_CAUSE_NONSELECTED_USER_CLEARING:
/* We'll send RELEASE with these causes */
disconnect = 0;
break;
@@ -4518,15 +4961,26 @@
case Q931_NOTIFY:
q931_party_number_init(&c->redirection_number);
break;
+ case Q931_HOLD:
+ break;
+ case Q931_HOLD_ACKNOWLEDGE:
+ break;
+ case Q931_HOLD_REJECT:
+ c->cause = -1;
+ break;
+ case Q931_RETRIEVE:
+ c->channelno = 0xFF;
+ c->ds1no = 0;
+ c->ds1explicit = 0;
+ break;
+ case Q931_RETRIEVE_ACKNOWLEDGE:
+ break;
+ case Q931_RETRIEVE_REJECT:
+ c->cause = -1;
+ break;
case Q931_USER_INFORMATION:
case Q931_SEGMENT:
case Q931_CONGESTION_CONTROL:
- case Q931_HOLD:
- case Q931_HOLD_ACKNOWLEDGE:
- case Q931_HOLD_REJECT:
- case Q931_RETRIEVE:
- case Q931_RETRIEVE_ACKNOWLEDGE:
- case Q931_RETRIEVE_REJECT:
case Q931_RESUME:
case Q931_RESUME_ACKNOWLEDGE:
case Q931_RESUME_REJECT:
@@ -5517,19 +5971,218 @@
ctrl->ev.notify.subcmds = &ctrl->subcmds;
ctrl->ev.notify.channel = q931_encode_channel(c);
ctrl->ev.notify.info = c->notify;
+ ctrl->ev.notify.call = c->master_call;
res = Q931_RES_HAVEEVENT;
break;
}
return res;
+ case Q931_HOLD:
+ switch (c->ourcallstate) {
+ case Q931_CALL_STATE_CALL_RECEIVED:
+ case Q931_CALL_STATE_CONNECT_REQUEST:
+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+ if (q931_is_ptmp(ctrl)) {
+ /* HOLD request only allowed in these states if point-to-point mode. */
+ q931_send_hold_rej(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
+ break;
+ }
+ /* Fall through */
+ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_CALL_DELIVERED:
+ case Q931_CALL_STATE_ACTIVE:
+ switch (c->hold_state) {
+ case Q931_HOLD_STATE_HOLD_REQ:
+ if (ctrl->localtype == PRI_NETWORK) {
+ /* The network ignores HOLD request on a hold collision. */
+ break;
+ }
+ /* Fall through */
+ case Q931_HOLD_STATE_IDLE:
+ ctrl->ev.e = PRI_EVENT_HOLD;
+ ctrl->ev.hold.channel = q931_encode_channel(c);
+ ctrl->ev.hold.call = c->master_call;
+ ctrl->ev.hold.subcmds = &ctrl->subcmds;
+ res = Q931_RES_HAVEEVENT;
+
+ UPDATE_HOLD_STATE(ctrl, c, Q931_HOLD_STATE_HOLD_IND);
+
+ /* Start the upper layer does not implement guard timer. */
+ pri_schedule_del(ctrl, c->hold_timer);
+ c->hold_timer = pri_schedule_event(ctrl,
+ ctrl->timers[PRI_TIMER_T_HOLD] / 2, q931_hold_guard_timeout, c);
+ break;
+ default:
+ q931_send_hold_rej(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
+ break;
+ }
+ break;
+ case Q931_CALL_STATE_DISCONNECT_INDICATION:
+ case Q931_CALL_STATE_RELEASE_REQUEST:
+ /* Ignore HOLD request in these states. */
+ break;
+ default:
+ q931_send_hold_rej(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
+ break;
+ }
+ break;
+ case Q931_HOLD_ACKNOWLEDGE:
+ switch (c->hold_state) {
+ case Q931_HOLD_STATE_HOLD_REQ:
+ ctrl->ev.e = PRI_EVENT_HOLD_ACK;
+ ctrl->ev.hold_ack.channel = q931_encode_channel(c);
+ ctrl->ev.hold_ack.call = c->master_call;
+ ctrl->ev.hold_ack.subcmds = &ctrl->subcmds;
+ res = Q931_RES_HAVEEVENT;
+
+ UPDATE_HOLD_STATE(ctrl, c, Q931_HOLD_STATE_CALL_HELD);
+
+ /* Call is now on hold so forget the channel. */
+ c->channelno = 0;/* No channel */
+ c->ds1no = 0;
+ c->ds1explicit = 0;
+ c->chanflags = 0;
+
+ /* Stop T-HOLD timer */
+ pri_schedule_del(ctrl, c->hold_timer);
+ c->hold_timer = 0;
+ break;
+ default:
+ /* Ignore response. Response is late or spurrious. */
+ break;
+ }
+ break;
+ case Q931_HOLD_REJECT:
+ switch (c->hold_state) {
+ case Q931_HOLD_STATE_HOLD_REQ:
+ if (missingmand) {
+ /* Still, let hold rejection continue. */
+ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
+ }
+ ctrl->ev.e = PRI_EVENT_HOLD_REJ;
+ ctrl->ev.hold_rej.channel = q931_encode_channel(c);
+ ctrl->ev.hold_rej.call = c->master_call;
+ ctrl->ev.hold_rej.cause = c->cause;
+ ctrl->ev.hold_rej.subcmds = &ctrl->subcmds;
+ res = Q931_RES_HAVEEVENT;
+
+ UPDATE_HOLD_STATE(ctrl, c, Q931_HOLD_STATE_IDLE);
+
+ /* Stop T-HOLD timer */
+ pri_schedule_del(ctrl, c->hold_timer);
+ c->hold_timer = 0;
+ break;
+ default:
+ /* Ignore response. Response is late or spurrious. */
+ break;
+ }
+ break;
+ case Q931_RETRIEVE:
+ switch (c->ourcallstate) {
+ case Q931_CALL_STATE_CALL_RECEIVED:
+ case Q931_CALL_STATE_CONNECT_REQUEST:
+ case Q931_CALL_STATE_INCOMING_CALL_PROCEEDING:
+ if (q931_is_ptmp(ctrl)) {
+ /* RETRIEVE request only allowed in these states if point-to-point mode. */
+ q931_send_retrieve_rej(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
+ break;
+ }
+ /* Fall through */
+ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_CALL_DELIVERED:
+ case Q931_CALL_STATE_ACTIVE:
+ switch (c->hold_state) {
+ case Q931_HOLD_STATE_RETRIEVE_REQ:
+ if (ctrl->localtype == PRI_NETWORK) {
+ /* The network ignores RETRIEVE request on a retrieve collision. */
+ break;
+ }
+ /* Fall through */
+ case Q931_HOLD_STATE_CALL_HELD:
+ ctrl->ev.e = PRI_EVENT_RETRIEVE;
+ ctrl->ev.retrieve.channel = q931_encode_channel(c);
+ ctrl->ev.retrieve.call = c->master_call;
+ ctrl->ev.retrieve.flexible = !(c->chanflags & FLAG_EXCLUSIVE);
+ ctrl->ev.retrieve.subcmds = &ctrl->subcmds;
+ res = Q931_RES_HAVEEVENT;
+
+ UPDATE_HOLD_STATE(ctrl, c, Q931_HOLD_STATE_RETRIEVE_IND);
+
+ /*
+ * Stop any T-RETRIEVE timer.
+ * The upper layer must implement HOLD for a call to even get
+ * on hold.
+ */
+ pri_schedule_del(ctrl, c->hold_timer);
+ c->hold_timer = 0;
+ break;
+ default:
+ q931_send_retrieve_rej(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
+ break;
+ }
+ break;
+ case Q931_CALL_STATE_DISCONNECT_INDICATION:
+ case Q931_CALL_STATE_RELEASE_REQUEST:
+ /* Ignore RETRIEVE request in these states. */
+ break;
+ default:
+ q931_send_retrieve_rej(ctrl, c, PRI_CAUSE_WRONG_CALL_STATE);
+ break;
+ }
+ break;
+ case Q931_RETRIEVE_ACKNOWLEDGE:
+ switch (c->hold_state) {
+ case Q931_HOLD_STATE_RETRIEVE_REQ:
+ UPDATE_HOLD_STATE(ctrl, c, Q931_HOLD_STATE_IDLE);
+
+ /* Stop T-RETRIEVE timer */
+ pri_schedule_del(ctrl, c->hold_timer);
+ c->hold_timer = 0;
+
+ ctrl->ev.e = PRI_EVENT_RETRIEVE_ACK;
+ ctrl->ev.retrieve_ack.channel = q931_encode_channel(c);
+ ctrl->ev.retrieve_ack.call = c->master_call;
+ ctrl->ev.retrieve_ack.subcmds = &ctrl->subcmds;
+ res = Q931_RES_HAVEEVENT;
+ break;
+ default:
+ /* Ignore response. Response is late or spurrious. */
+ break;
+ }
+ break;
+ case Q931_RETRIEVE_REJECT:
+ switch (c->hold_state) {
+ case Q931_HOLD_STATE_RETRIEVE_REQ:
+ UPDATE_HOLD_STATE(ctrl, c, Q931_HOLD_STATE_CALL_HELD);
+
+ /* Call is still on hold so forget the channel. */
+ c->channelno = 0;/* No channel */
+ c->ds1no = 0;
+ c->ds1explicit = 0;
+ c->chanflags = 0;
+
+ /* Stop T-RETRIEVE timer */
+ pri_schedule_del(ctrl, c->hold_timer);
+ c->hold_timer = 0;
+
+ if (missingmand) {
+ /* Still, let retrive rejection continue. */
+ c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
+ }
+ ctrl->ev.e = PRI_EVENT_RETRIEVE_REJ;
+ ctrl->ev.retrieve_rej.channel = q931_encode_channel(c);
+ ctrl->ev.retrieve_rej.call = c->master_call;
+ ctrl->ev.retrieve_rej.cause = c->cause;
+ ctrl->ev.retrieve_rej.subcmds = &ctrl->subcmds;
+ res = Q931_RES_HAVEEVENT;
+ break;
+ default:
+ /* Ignore response. Response is late or spurrious. */
+ break;
+ }
+ break;
case Q931_USER_INFORMATION:
case Q931_SEGMENT:
case Q931_CONGESTION_CONTROL:
- case Q931_HOLD:
- case Q931_HOLD_ACKNOWLEDGE:
- case Q931_HOLD_REJECT:
- case Q931_RETRIEVE:
- case Q931_RETRIEVE_ACKNOWLEDGE:
- case Q931_RETRIEVE_REJECT:
case Q931_RESUME:
case Q931_RESUME_ACKNOWLEDGE:
case Q931_RESUME_REJECT:
More information about the libpri-commits
mailing list