[libpri-commits] rmudgett: branch rmudgett/facility r1137 - /team/rmudgett/facility/
SVN commits to the libpri project
libpri-commits at lists.digium.com
Thu Sep 24 16:39:37 CDT 2009
Author: rmudgett
Date: Thu Sep 24 16:39:33 2009
New Revision: 1137
URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1137
Log:
Merged team/rmudgett/ntptmp branch differences up to -r1136.
Modified:
team/rmudgett/facility/libpri.h
team/rmudgett/facility/pri.c
team/rmudgett/facility/pri_internal.h
team/rmudgett/facility/pri_q921.h
team/rmudgett/facility/pri_q931.h
team/rmudgett/facility/q921.c
team/rmudgett/facility/q931.c
Modified: team/rmudgett/facility/libpri.h
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/facility/libpri.h?view=diff&rev=1137&r1=1136&r2=1137
==============================================================================
--- team/rmudgett/facility/libpri.h (original)
+++ team/rmudgett/facility/libpri.h Thu Sep 24 16:39:33 2009
@@ -623,10 +623,22 @@
int channel; /* Channel requested */
int cause;
int cref;
- q931_call *call; /* Opaque call pointer */
+ q931_call *call; /* Opaque call pointer of call hanging up. */
long aoc_units; /* Advise of Charge number of charged units */
char useruserinfo[260]; /* User->User info */
struct pri_subcommands *subcmds;
+ /*!
+ * \brief Opaque held call pointer for possible transfer to active call.
+ * \note The call_held and call_active pointers must not be NULL if
+ * transfer held call on disconnect is available.
+ */
+ q931_call *call_held;
+ /*!
+ * \brief Opaque active call pointer for possible transfer with held call.
+ * \note The call_held and call_active pointers must not be NULL if
+ * transfer held call on disconnect is available.
+ */
+ q931_call *call_active;
} pri_event_hangup;
typedef struct pri_event_restart_ack {
@@ -863,7 +875,24 @@
/* Hangup a call */
#define PRI_HANGUP
-int pri_hangup(struct pri *pri, q931_call *call, int cause);
+
+#define HANGUP_DEBUG
+
+#ifdef HANGUP_DEBUG
+#define pri_hangup(a, b, c) \
+ __debug_pri_hangup((a), (b), (c), __FUNCTION__)
+
+
+#else
+
+#define pri_hangup(a, b, c) \
+ __debug_pri_hangup((a), (b), (c), __FUNCTION__)
+
+#endif
+
+int __normal_pri_hangup(struct pri *pri, q931_call *call, int cause);
+
+int __debug_pri_hangup(struct pri *pri, q931_call *call, int cause, const char *caller);
#define PRI_DESTROYCALL
void pri_destroycall(struct pri *pri, q931_call *call);
Modified: team/rmudgett/facility/pri.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/facility/pri.c?view=diff&rev=1137&r1=1136&r2=1137
==============================================================================
--- team/rmudgett/facility/pri.c (original)
+++ team/rmudgett/facility/pri.c Thu Sep 24 16:39:33 2009
@@ -152,6 +152,7 @@
ctrl->timers[PRI_TIMER_T313] = 4 * 1000; /* Wait for CONNECT acknowledge, CPE side only */
ctrl->timers[PRI_TIMER_TM20] = 2500; /* Max time awaiting XID response - Q.921 Appendix IV */
ctrl->timers[PRI_TIMER_NM20] = 3; /* Number of XID retransmits - Q.921 Appendix IV */
+ ctrl->timers[PRI_TIMER_T303] = 4 * 1000; /* Length between SETUP retransmissions and timeout */
ctrl->timers[PRI_TIMER_T_HOLD] = 4 * 1000; /* Wait for HOLD request response. */
ctrl->timers[PRI_TIMER_T_RETRIEVE] = 4 * 1000;/* Wait for RETRIEVE request response. */
@@ -228,7 +229,7 @@
/* Pass in the master for this function */
void __pri_free_tei(struct pri * p)
{
- free (p);
+ free(p);
}
struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master, pri_io_cb rd, pri_io_cb wr, void *userdata, int tei, int bri)
@@ -645,6 +646,8 @@
int pri_connected_line_update(struct pri *ctrl, q931_call *call, const struct pri_party_connected_line *connected)
{
struct q931_party_id party_id;
+ unsigned idx;
+ struct q931_call *subcall;
if (!ctrl || !call) {
return -1;
@@ -657,6 +660,16 @@
return 0;
}
call->local_id = party_id;
+
+ /* Update all subcalls with new local_id. */
+ if (call->outboundbroadcast && call->master_call == call) {
+ for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
+ subcall = call->subcalls[idx];
+ if (subcall) {
+ subcall->local_id = party_id;
+ }
+ }
+ }
switch (call->ourcallstate) {
case Q931_CALL_STATE_CALL_INITIATED:
@@ -699,6 +712,9 @@
int pri_redirecting_update(struct pri *ctrl, q931_call *call, const struct pri_party_redirecting *redirecting)
{
+ unsigned idx;
+ struct q931_call *subcall;
+
if (!ctrl || !call) {
return -1;
}
@@ -707,6 +723,21 @@
pri_copy_party_id_to_q931(&call->redirecting.to, &redirecting->to);
q931_party_id_fixup(ctrl, &call->redirecting.to);
call->redirecting.reason = redirecting->reason;
+
+ /*
+ * Update all subcalls with new redirecting.to information and reason.
+ * I do not think we will ever have any subcalls when this data is relevant,
+ * but update it just in case.
+ */
+ if (call->outboundbroadcast && call->master_call == call) {
+ for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
+ subcall = call->subcalls[idx];
+ if (subcall) {
+ subcall->redirecting.to = call->redirecting.to;
+ subcall->redirecting.reason = redirecting->reason;
+ }
+ }
+ }
switch (call->ourcallstate) {
case Q931_CALL_STATE_NULL:
@@ -846,14 +877,23 @@
}
}
-int pri_hangup(struct pri *pri, q931_call *call, int cause)
+int __normal_pri_hangup(struct pri *pri, q931_call *call, int cause)
{
if (!pri || !call)
return -1;
if (cause == -1)
/* normal clear cause */
cause = 16;
+
return q931_hangup(pri, call, cause);
+}
+
+int __debug_pri_hangup(struct pri *pri, q931_call *call, int cause, const char *caller)
+{
+ if (caller)
+ pri_error(pri, "%s:pri_hangup(%p, %p, %d)\n", caller, pri, call, cause);
+
+ return __normal_pri_hangup(pri, call, cause);
}
int pri_reset(struct pri *pri, int channel)
@@ -1022,7 +1062,7 @@
vsnprintf(tmp, sizeof(tmp), fmt, ap);
va_end(ap);
if (__pri_message)
- __pri_message(pri, tmp);
+ __pri_message(PRI_MASTER(pri), tmp);
else
fputs(tmp, stdout);
}
@@ -1035,7 +1075,7 @@
vsnprintf(tmp, sizeof(tmp), fmt, ap);
va_end(ap);
if (__pri_error)
- __pri_error(pri, tmp);
+ __pri_error(PRI_MASTER(pri), tmp);
else
fputs(tmp, stderr);
}
Modified: team/rmudgett/facility/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/facility/pri_internal.h?view=diff&rev=1137&r1=1136&r2=1137
==============================================================================
--- team/rmudgett/facility/pri_internal.h (original)
+++ team/rmudgett/facility/pri_internal.h Thu Sep 24 16:39:33 2009
@@ -300,6 +300,7 @@
/* Internal switch types */
#define PRI_SWITCH_GR303_EOC_PATH 19
#define PRI_SWITCH_GR303_TMC_SWITCHING 20
+#define Q931_MAX_TEI 8
struct apdu_event {
int message; /* What message to send the ADPU in */
@@ -488,6 +489,18 @@
-1 - No reverse charging
1 - Reverse charging
0,2-7 - Reserved for future use */
+ int t303_timer;
+ int t303_expirycnt;
+
+ int hangupinitiated;
+ int outboundbroadcast;
+ int performing_fake_clearing;
+ /* These valid in slave call only */
+ struct q931_call *master_call;
+
+ /* These valid in master call only */
+ struct q931_call *subcalls[Q931_MAX_TEI];
+ int pri_winner;
};
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
@@ -532,4 +545,35 @@
int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number);
+static inline struct pri * PRI_MASTER(struct pri *mypri)
+{
+ struct pri *pri = mypri;
+
+ if (!pri)
+ return NULL;
+
+ while (pri->master)
+ pri = pri->master;
+
+ return pri;
+}
+
+static inline int BRI_NT_PTMP(struct pri *mypri)
+{
+ struct pri *pri;
+
+ pri = PRI_MASTER(mypri);
+
+ return pri->bri && (((pri)->localtype == PRI_NETWORK) && ((pri)->tei == Q921_TEI_GROUP));
+}
+
+static inline int BRI_TE_PTMP(struct pri *mypri)
+{
+ struct pri *pri;
+
+ pri = PRI_MASTER(mypri);
+
+ return pri->bri && (((pri)->localtype == PRI_CPE) && ((pri)->tei == Q921_TEI_GROUP));
+}
+
#endif
Modified: team/rmudgett/facility/pri_q921.h
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/facility/pri_q921.h?view=diff&rev=1137&r1=1136&r2=1137
==============================================================================
--- team/rmudgett/facility/pri_q921.h (original)
+++ team/rmudgett/facility/pri_q921.h Thu Sep 24 16:39:33 2009
@@ -192,6 +192,8 @@
extern int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr);
+extern int q921_transmit_uiframe(struct pri *pri, void *buf, int len);
+
extern pri_event *q921_dchannel_up(struct pri *pri);
extern pri_event *q921_dchannel_down(struct pri *pri);
Modified: team/rmudgett/facility/pri_q931.h
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/facility/pri_q931.h?view=diff&rev=1137&r1=1136&r2=1137
==============================================================================
--- team/rmudgett/facility/pri_q931.h (original)
+++ team/rmudgett/facility/pri_q931.h Thu Sep 24 16:39:33 2009
@@ -470,12 +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);
+int q931_send_hold(struct pri *ctrl, struct q931_call *call);
+int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call);
+int q931_send_hold_rej(struct pri *ctrl, struct q931_call *call, int cause);
+
+int q931_send_retrieve(struct pri *ctrl, struct q931_call *call, int channel);
+int q931_send_retrieve_ack(struct pri *ctrl, struct q931_call *call, int channel);
+int q931_send_retrieve_rej(struct pri *ctrl, struct q931_call *call, int cause);
#endif
Modified: team/rmudgett/facility/q921.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/facility/q921.c?view=diff&rev=1137&r1=1136&r2=1137
==============================================================================
--- team/rmudgett/facility/q921.c (original)
+++ team/rmudgett/facility/q921.c Thu Sep 24 16:39:33 2009
@@ -27,6 +27,7 @@
* terms granted here.
*/
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -477,6 +478,45 @@
}
}
+int q921_transmit_uiframe(struct pri *pri, void *buf, int len)
+{
+ uint8_t ubuf[512];
+ q921_h *h = (void *)&ubuf[0];
+
+ if (len >= 512) {
+ pri_error(pri, "Requested to send UI frame larger than 512 bytes!\n");
+ return -1;
+ }
+
+ memset(ubuf, 0, sizeof(ubuf));
+ h->h.sapi = 0;
+ h->h.ea1 = 0;
+ h->h.ea2 = 1;
+ h->h.tei = pri->tei;
+ h->u.m3 = 0;
+ h->u.m2 = 0;
+ h->u.p_f = 0; /* Poll bit set */
+ h->u.ft = Q921_FRAMETYPE_U;
+
+ switch(pri->localtype) {
+ case PRI_NETWORK:
+ h->h.c_r = 1;
+ break;
+ case PRI_CPE:
+ h->h.c_r = 0;
+ break;
+ default:
+ pri_error(pri, "Don't know how to U/A on a type %d node\n", pri->localtype);
+ return -1;
+ }
+
+ memcpy(h->u.data, buf, len);
+
+ q921_transmit(pri, h, len + 3);
+
+ return 0;
+}
+
int q921_transmit_iframe(struct pri *pri, void *buf, int len, int cr)
{
q921_frame *f, *prev=NULL;
@@ -515,6 +555,7 @@
pri->txqueue = f;
/* Immediately transmit unless we're in a recovery state, or the window
size is too big */
+ pri_message(pri, "TEI/SAPI: %d/%d state %d retran %d busy %d\n", pri->tei, pri->sapi, pri->q921_state, pri->retrans, pri->busy);
if ((pri->q921_state == Q921_LINK_CONNECTION_ESTABLISHED) && (!pri->retrans && !pri->busy)) {
if (pri->windowlen < pri->window) {
q921_send_queued_iframes(pri);
@@ -559,10 +600,11 @@
pri->t203_timer = pri_schedule_event(pri, pri->timers[PRI_TIMER_T200], t200_expire, pri);
} else {
if (pri->debug & PRI_DEBUG_Q921_DUMP)
- pri_message(pri, "T203 counter expired in weird state %d\n", pri->q921_state);
+ pri_message(pri, "T203 counter expired in weird state %d on pri with sapi %d and tei %d\n", pri->q921_state, pri->sapi, pri->tei);
pri->t203_timer = 0;
}
}
+
static pri_event *q921_handle_iframe(struct pri *pri, q921_i *i, int len)
{
int res;
@@ -865,8 +907,14 @@
static pri_event *q921_receive_MDL(struct pri *pri, q921_u *h, int len)
{
int ri;
- struct pri *sub;
+ struct pri *sub = pri;
int tei;
+
+ if (!BRI_NT_PTMP(pri) && !BRI_TE_PTMP(pri)) {
+ pri_error(pri, "Received MDL/TEI managemement message, but configured for mode other than PTMP!\n");
+ return NULL;
+ }
+
if (pri->debug & PRI_DEBUG_Q921_STATE)
pri_message(pri, "Received MDL message\n");
if (h->data[0] != 0x0f) {
@@ -881,17 +929,19 @@
tei = (h->data[4] >> 1);
switch(h->data[3]) {
case Q921_TEI_IDENTITY_REQUEST:
+ if (!BRI_NT_PTMP(pri)) {
+ return NULL;
+ }
+
if (tei != 127) {
pri_error(pri, "Received TEI identity request with invalid TEI %d\n", tei);
q921_send_tei(pri, Q921_TEI_IDENTITY_DENIED, ri, tei, 1);
}
- /* Go to master */
- for (sub = pri; sub->master; sub = sub->master);
tei = 64;
-/*! \todo XXX Error: The following loop never terminates! */
- while(sub->subchannel) {
- if(sub->subchannel->tei == tei)
+ while (sub->subchannel) {
+ if (sub->subchannel->tei == tei)
++tei;
+ sub = sub->subchannel;
}
sub->subchannel = __pri_new_tei(-1, pri->localtype, pri->switchtype, pri, NULL, NULL, NULL, tei, 1);
if (!sub->subchannel) {
@@ -901,6 +951,9 @@
q921_send_tei(pri, Q921_TEI_IDENTITY_ASSIGNED, ri, tei, 1);
break;
case Q921_TEI_IDENTITY_ASSIGNED:
+ if (!BRI_TE_PTMP(pri))
+ return NULL;
+
if (ri != pri->ri) {
pri_message(pri, "TEI assignment received for invalid Ri %02x (our is %02x)\n", ri, pri->ri);
return NULL;
@@ -922,6 +975,8 @@
pri->q921_state = Q921_TEI_ASSIGNED;
break;
case Q921_TEI_IDENTITY_CHECK_REQUEST:
+ if (!BRI_TE_PTMP(pri))
+ return NULL;
/* We're assuming one TEI per PRI in TE PTMP mode */
/* If no subchannel (TEI) ignore */
@@ -934,6 +989,8 @@
break;
case Q921_TEI_IDENTITY_REMOVE:
+ if (!BRI_TE_PTMP(pri))
+ return NULL;
/* XXX: Assuming multiframe mode has been disconnected already */
if (!pri->subchannel)
return NULL;
@@ -975,6 +1032,10 @@
pri_error(pri, "!! Received short I-frame (expected 4, got %d)\n", len);
break;
}
+
+ /* T203 is rescheduled only on reception of I frames or S frames */
+ reschedule_t203(pri);
+
return q921_handle_iframe(pri, &h->i, len);
break;
case 1:
@@ -986,6 +1047,10 @@
pri_error(pri, "!! Received short S-frame (expected 4, got %d)\n", len);
break;
}
+
+ /* T203 is rescheduled only on reception of I frames or S frames */
+ reschedule_t203(pri);
+
switch(h->s.ss) {
case 0:
/* Receiver Ready */
@@ -1135,7 +1200,6 @@
/* Acknowledge */
q921_send_ua(pri, h->u.p_f);
ev = q921_dchannel_down(pri);
- q921_restart(pri, 0);
return ev;
case 3:
if (h->u.m2 == 3) {
@@ -1195,6 +1259,31 @@
return NULL;
}
+static pri_event *q921_handle_unmatched_frame(struct pri *pri, q921_h *h, int len)
+{
+ pri = PRI_MASTER(pri);
+
+ pri_error(pri, "Could not find candidate subchannel for received frame with SAPI/TEI of %d/%d.\n", h->h.sapi, h->h.tei);
+
+ if (h->h.tei < 64) {
+ pri_error(pri, "Do not support manual TEI range. Discarding\n");
+ return NULL;
+ }
+
+ if (h->h.sapi != Q921_SAPI_CALL_CTRL) {
+ pri_error(pri, "Message with SAPI other than CALL CTRL is discarded\n");
+ return NULL;
+ }
+
+ pri_error(pri, "Sending TEI release, in order to re-establish TEI state\n");
+
+ /* Q.921 says we should send the remove message twice, in case of link corruption */
+ q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1);
+ q921_send_tei(pri, Q921_TEI_IDENTITY_REMOVE, 0, h->h.tei, 1);
+
+ return NULL;
+}
+
static pri_event *__q921_receive(struct pri *pri, q921_h *h, int len)
{
pri_event *ev;
@@ -1208,26 +1297,22 @@
if (h->h.ea1 || !(h->h.ea2))
return NULL;
-#if 0 /* Will be rejected by subchannel analyzis */
- /* Check for broadcasts - not yet handled */
- if (h->h.tei == Q921_TEI_GROUP)
- return NULL;
-#endif
-
if (!((h->h.sapi == pri->sapi) && ((h->h.tei == pri->tei) || (h->h.tei == Q921_TEI_GROUP)))) {
/* Check for SAPIs we don't yet handle */
/* If it's not us, try any subchannels we have */
if (pri->subchannel)
return q921_receive(pri->subchannel, h, len + 2);
else {
- return NULL;
+ /* This means we couldn't find a candidate subchannel for it...
+ * Time for some corrective action */
+
+ return q921_handle_unmatched_frame(pri, h, len);
}
}
if (pri->debug & PRI_DEBUG_Q921_DUMP)
pri_message(pri, "Handling message for SAPI/TEI=%d/%d\n", h->h.sapi, h->h.tei);
ev = __q921_receive_qualified(pri, h, len);
- reschedule_t203(pri);
return ev;
}
Modified: team/rmudgett/facility/q931.c
URL: http://svnview.digium.com/svn/libpri/team/rmudgett/facility/q931.c?view=diff&rev=1137&r1=1136&r2=1137
==============================================================================
--- team/rmudgett/facility/q931.c (original)
+++ team/rmudgett/facility/q931.c Thu Sep 24 16:39:33 2009
@@ -91,7 +91,9 @@
{ Q931_SUSPEND_ACKNOWLEDGE, "SUSPEND ACKNOWLEDGE" },
{ Q931_SUSPEND_REJECT, "SUSPEND REJECT" },
};
+
static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int missingmand);
+static void nt_ptmp_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct q931_call *c, int *allow_event, int *allow_posthandle);
struct msgtype att_maintenance_msgs[] = {
{ ATT_SERVICE, "SERVICE", { Q931_CHANNEL_IDENT } },
@@ -116,6 +118,7 @@
{ PRI_CAUSE_NO_ANSWER, "User alerting, no answer" },
{ PRI_CAUSE_CALL_REJECTED, "Call Rejected" },
{ PRI_CAUSE_NUMBER_CHANGED, "Number changed" },
+ { PRI_CAUSE_NONSELECTED_USER_CLEARING, "Non-selected user clearing" },
{ PRI_CAUSE_DESTINATION_OUT_OF_ORDER, "Destination out of order" },
{ PRI_CAUSE_INVALID_NUMBER_FORMAT, "Invalid number format" },
{ PRI_CAUSE_FACILITY_REJECTED, "Facility rejected" },
@@ -128,13 +131,14 @@
{ PRI_CAUSE_ACCESS_INFO_DISCARDED, "Access information discarded" },
{ PRI_CAUSE_REQUESTED_CHAN_UNAVAIL, "Requested channel not available" },
{ PRI_CAUSE_PRE_EMPTED, "Pre-empted" },
+ { PRI_CAUSE_RESOURCE_UNAVAIL_UNSPECIFIED, "Resource unavailable, unspecified" },
{ PRI_CAUSE_FACILITY_NOT_SUBSCRIBED, "Facility not subscribed" },
{ PRI_CAUSE_OUTGOING_CALL_BARRED, "Outgoing call barred" },
{ PRI_CAUSE_INCOMING_CALL_BARRED, "Incoming call barred" },
{ PRI_CAUSE_BEARERCAPABILITY_NOTAUTH, "Bearer capability not authorized" },
{ PRI_CAUSE_BEARERCAPABILITY_NOTAVAIL, "Bearer capability not available" },
+ { PRI_CAUSE_SERVICEOROPTION_NOTAVAIL, "Service or option not available, unspecified" },
{ PRI_CAUSE_BEARERCAPABILITY_NOTIMPL, "Bearer capability not implemented" },
- { PRI_CAUSE_SERVICEOROPTION_NOTAVAIL, "Service or option not available, unspecified" },
{ PRI_CAUSE_CHAN_NOT_IMPLEMENTED, "Channel not implemented" },
{ PRI_CAUSE_FACILITY_NOT_IMPLEMENTED, "Facility not implemented" },
{ PRI_CAUSE_INVALID_CALL_REFERENCE, "Invalid call reference value" },
@@ -237,9 +241,10 @@
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)); \
+ DBGHEAD "%s %d enters state %d (%s). Hold state: %s\n", \
+ DBGINFO, ((call) == (call)->master_call) ? "Call" : "Subcall", \
+ (call)->cr, (newstate), q931_call_state_str(newstate), \
+ q931_hold_state_str((call)->master_call->hold_state)); \
} \
(call)->ourcallstate = (newstate); \
} while (0)
@@ -250,20 +255,21 @@
#if 1
/* Update hold state with transition trace. */
-#define UPDATE_HOLD_STATE(ctrl, call, newstate) \
+#define UPDATE_HOLD_STATE(ctrl, master_call, newstate) \
do { \
- if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) && (call)->hold_state != (newstate)) { \
+ if (((ctrl)->debug & PRI_DEBUG_Q931_STATE) \
+ && (master_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), \
+ DBGHEAD "Call %d in state %d (%s) enters Hold state: %s\n", \
+ DBGINFO, (master_call)->cr, (master_call)->ourcallstate, \
+ q931_call_state_str((master_call)->ourcallstate), \
q931_hold_state_str(newstate)); \
} \
- (call)->hold_state = (newstate); \
+ (master_call)->hold_state = (newstate); \
} while (0)
#else
/* Update hold state with no trace. */
-#define UPDATE_HOLD_STATE(ctrl, call, newstate) (call)->hold_state = (newstate)
+#define UPDATE_HOLD_STATE(ctrl, master_call, newstate) (master_call)->hold_state = (newstate)
#endif
struct ie {
@@ -292,19 +298,27 @@
static int q931_encode_channel(const q931_call *call)
{
int held_call;
-
- switch (call->hold_state) {
+ int channelno;
+ int ds1no;
+
+ switch (call->master_call->hold_state) {
case Q931_HOLD_STATE_CALL_HELD:
case Q931_HOLD_STATE_RETRIEVE_REQ:
case Q931_HOLD_STATE_RETRIEVE_IND:
held_call = 1 << 18;
+
+ /* So a -1 does not wipe out the held_call flag. */
+ channelno = call->channelno & 0xFF;
+ ds1no = call->ds1no & 0xFF;
break;
default:
held_call = 0;
- break;
- }
- return call->channelno | (call->ds1no << 8) | (call->ds1explicit << 16)
- | (call->cis_call << 17) | held_call;
+ channelno = call->channelno;
+ ds1no = call->ds1no;
+ break;
+ }
+ return channelno | (ds1no << 8) | (call->ds1explicit << 16) | (call->cis_call << 17)
+ | held_call;
}
/*!
@@ -853,7 +867,7 @@
return 0;
}
- if (((ctrl->switchtype != PRI_SWITCH_QSIG) && (call->ds1no > 0)) || call->ds1explicit) {
+ if (!ctrl->bri && (((ctrl->switchtype != PRI_SWITCH_QSIG) && (call->ds1no > 0)) || call->ds1explicit)) {
/* We are specifying the interface. Octet 3.1 */
ie->data[pos++] |= 0x40;
ie->data[pos++] = 0x80 | call->ds1no;
@@ -3082,20 +3096,25 @@
struct pri *master;
/* Find the master - He has the call pool */
- if (ctrl->master) {
- master = ctrl->master;
- } else {
- master = ctrl;
- }
+ master = PRI_MASTER(ctrl);
cur = *master->callpool;
prev = NULL;
while (cur) {
if (cur->cr == cr) {
- if (!ctrl->bri && ctrl->switchtype != PRI_SWITCH_GR303_EOC_PATH
- && ctrl->switchtype != PRI_SWITCH_GR303_TMC_SWITCHING
- && cur->pri != ctrl) {
- cur->pri = ctrl;
+ /* Found existing call. */
+ switch (ctrl->switchtype) {
+ case PRI_SWITCH_GR303_EOC:
+ case PRI_SWITCH_GR303_EOC_PATH:
+ case PRI_SWITCH_GR303_TMC:
+ case PRI_SWITCH_GR303_TMC_SWITCHING:
+ break;
+ default:
+ if (!ctrl->bri) {
+ /* PRI is set to whoever called us */
+ cur->pri = ctrl;
+ }
+ break;
}
return cur;
}
@@ -3137,6 +3156,8 @@
cur->aoc_units = -1;
cur->changestatus = -1;
cur->reversecharge = -1;
+ cur->pri_winner = -1;
+ cur->master_call = cur;
q931_party_number_init(&cur->redirection_number);
q931_party_address_init(&cur->called);
q931_party_id_init(&cur->local_id);
@@ -3144,7 +3165,7 @@
q931_party_redirecting_init(&cur->redirecting);
/* PRI is set to whoever called us */
- if (q931_is_ptmp(ctrl) && (ctrl->localtype == PRI_CPE)) {
+ if (BRI_TE_PTMP(ctrl)) {
/*
* Point to the master to avoid stale pointer problems if
* the TEI is removed later.
@@ -3188,17 +3209,113 @@
return q931_getcall(ctrl, ctrl->cref | 0x8000);
}
+static void stop_t303(struct q931_call *call);
+
+static void cleanup_and_free_call(struct q931_call *cur)
+{
+ stop_t303(cur);
+ pri_schedule_del(cur->pri, cur->retranstimer);
+ pri_call_apdu_queue_cleanup(cur);
+ free(cur);
+}
+
+static void pri_create_fake_clearing(struct q931_call *c, struct pri *master);
+
static void q931_destroy(struct pri *ctrl, int cr, q931_call *c)
{
q931_call *cur, *prev;
+ q931_call *slave = NULL;
+ int i, slavesleft = 0;
+ int slaveidx = -1;
+
+ if (c->master_call != c) {
+ slave = c;
+ c = slave->master_call;
+ }
/* For destroying, make sure we are using the master span, since it maintains the call pool */
- for (;ctrl->master; ctrl = ctrl->master);
+ ctrl = PRI_MASTER(ctrl);
prev = NULL;
cur = *ctrl->callpool;
while(cur) {
if ((c && (cur == c)) || (!c && (cur->cr == cr))) {
+ if (slave) {
+ for (i = 0; i < Q931_MAX_TEI; i++) {
+ if (cur->subcalls[i] == slave) {
+ pri_error(ctrl, "Destroying subcall %p of call %p at %d\n", slave, cur, i);
+ cleanup_and_free_call(slave);
+ cur->subcalls[i] = NULL;
+ slaveidx = i;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < Q931_MAX_TEI; i++) {
+ if (cur->subcalls[i]) {
+ pri_error(ctrl, "Subcall still present at %d\n", i);
+ slavesleft++;
+ }
+ }
+
+ /* We have 3 different phases to deal with:
+ * 1.) Sent outbound call, but no response, indicated by t203 present
+ * 2.) Sent outbound call, with responses, indicated by lack of t203 and subcalls present
+ * 3.) Outbound call connected, indicated by pri_winner > -1
+ *
+ * If chan_dahdi hangs up in phase:
+ * 1.) T303 will be present, and we will fake clear in this case
+ * 2.) pri_winner will be < 0 and subcalls will be present.
+ * 3.) pri_winner will be > -1 and we will free the master when the winner dies.
+ *
+ * If remote ends hang up in phase:
+ * 1.) Impossible, defined by phase.
+ * 2.) When last end hangs up, we should cause a fake clearing.
+ * 3.) Pass events to winner up and be freed when winner is freed
+ *
+ * Exceptional conditions in phase:
+ * 1.) None.
+ * 2.) None.
+ * 3.) We hang up a call so quickly that it hangs up before other competing lines finish hangup sequence
+ * Subcalls present still even though we have hung up the winner.
+ *
+ * So, we could say:
+ * If, when the library user hangs up the master call, and there are more than one subcall up, we fake clear
+ * regardless of whether or not we drop down to one subcall left in the clearing process.
+ *
+ * If there are only one call up, we mirror what it does.
+ *
+ * OR
+ *
+ * Phase 2. them clearing:
+ * For handling of Phase 2 (indicated by not running and pri_winner not present):
+ * We create a fake hangup sequence after all the subcalls have been destroyed and after
+ *
+ * "" us clearing:
+ * For we need to start the fake clearing, but it needs to be half of a fake clearing, not a full one (since we already had a hangup).
+ *
+ * For handling of Phase 3 plus exceptions:
+ *
+ * If pri_winner exists, we mirror him in terms of events (which provides our hangup sequence), and when we have the complete
+ * hangup sequence completed (destroy called on master call), if there still exist non winner subcalls at this time, we declare the master
+ * call as dead and free it when the last subcall clears.
+ */
+
+ if ((slave && !slavesleft) &&
+ ((cur->pri_winner < 0) || (slave && slaveidx != cur->pri_winner))) {
+ pri_create_fake_clearing(cur, ctrl);
+ return;
+ }
+
+ if (slavesleft) {
+ return;
+ }
+
+ /* Master call or normal call destruction. */
+ if ((cur->pri_winner > -1) && cur->outboundbroadcast) {
+ pri_error(ctrl, "Since we already had a winner, we should just be able to kill the call anyways\n");
+ }
if (prev)
prev->next = cur->next;
else
@@ -3209,10 +3326,8 @@
q931_call_state_str(cur->ourcallstate),
q931_call_state_str(cur->peercallstate),
q931_hold_state_str(cur->hold_state));
- pri_schedule_del(ctrl, cur->retranstimer);
pri_schedule_del(ctrl, cur->hold_timer);
- pri_call_apdu_queue_cleanup(cur);
- free(cur);
+ cleanup_and_free_call(cur);
return;
}
prev = cur;
@@ -3221,10 +3336,12 @@
pri_error(ctrl, "Can't destroy call %d!\n", cr);
}
+#if 0
static void q931_destroycall(struct pri *ctrl, int cr)
{
q931_destroy(ctrl, cr, NULL);
}
+#endif
void __q931_destroycall(struct pri *ctrl, q931_call *call)
@@ -3408,9 +3525,20 @@
*mhb = mh;
}
-static int q931_xmit(struct pri *ctrl, q931_h *h, int len, int cr)
-{
- q921_transmit_iframe(ctrl, h, len, cr);
+static int q931_xmit(struct pri *ctrl, q931_h *h, int len, int cr, int uiframe)
+{
+ /*
+ * For NT-PTMP mode, we need to check the following:
+ * MODE = NT-PTMP
+ * MESSAGE = SETUP
+ *
+ * If those are true, we need to send the SETUP in a UI frame
+ * instead of an I-frame.
+ */
+ if (BRI_NT_PTMP(ctrl) && uiframe)
+ q921_transmit_uiframe(ctrl, h, len);
+ else
+ q921_transmit_iframe(ctrl, h, len, cr);
/* The transmit operation might dump the q921 header, so logging the q931
message body after the transmit puts the sections of the message in the
right order in the log */
@@ -3447,6 +3575,13 @@
int offset=0;
int x;
int codeset;
+
+ if (call->outboundbroadcast && call->master_call == call && msgtype != Q931_SETUP) {
+ pri_error(ctrl,
+ "Attempting to use master call record to send %s on BRI PTMP NT %p\n",
+ msg2str(msgtype), ctrl);
+ return -1;
+ }
memset(buf, 0, sizeof(buf));
len = sizeof(buf);
@@ -3469,7 +3604,7 @@
len = sizeof(buf) - len;
ctrl = call->pri;
- if (q931_is_ptmp(ctrl) && (ctrl->localtype == PRI_CPE)) {
+ if (BRI_TE_PTMP(ctrl)) {
/*
* Must use the BRI subchannel structure to send with the correct TEI.
* Note: If the subchannel is NULL then there is no TEI assigned and
@@ -3478,7 +3613,8 @@
ctrl = ctrl->subchannel;
}
if (ctrl) {
- q931_xmit(ctrl, h, len, 1);
+ pri_message(ctrl, "Sending message for call %p on %p TEI/SAPI %d/%d, call->pri is %p, TEI/SAPI %d/%d\n", call, ctrl, ctrl->tei, ctrl->sapi, call->pri, call->pri->tei, call->pri->sapi);
+ q931_xmit(ctrl, h, len, 1, (msgtype == Q931_SETUP) ? 1 : 0);
}
call->acked = 1;
return 0;
@@ -3601,7 +3737,8 @@
static int notify_ies[] = { Q931_IE_NOTIFY_IND, Q931_IE_REDIRECTION_NUMBER, -1 };
/*!
- * \brief Send a NOTIFY message with optional redirection number.
+ * \internal
+ * \brief Actually send a NOTIFY message with optional redirection number.
*
* \param ctrl D channel controller.
* \param call Q.931 call leg
@@ -3611,7 +3748,7 @@
* \retval 0 on success.
* \retval -1 on error.
*/
-int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number)
+static int q931_notify_redirection_helper(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number)
{
if (number) {
call->redirection_number = *number;
@@ -3620,6 +3757,48 @@
}
call->notify = notify;
return send_message(ctrl, call, Q931_NOTIFY, notify_ies);
+}
+
+/*!
+ * \brief Send a NOTIFY message with optional redirection number.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg
+ * \param notify Notification indicator
+ * \param number Redirection number to send if not NULL.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_notify_redirection(struct pri *ctrl, q931_call *call, int notify, const struct q931_party_number *number)
+{
+ int status;
+ unsigned idx;
+ struct q931_call *subcall;
+
+ if (call->outboundbroadcast && call->master_call == call) {
+ status = 0;
+ for (idx = 0; idx < Q931_MAX_TEI; ++idx) {
+ subcall = call->subcalls[idx];
+ if (subcall) {
+ /* Send to all subcalls that have given a positive response. */
+ switch (subcall->ourcallstate) {
+ case Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING:
+ case Q931_CALL_STATE_CALL_DELIVERED:
+ case Q931_CALL_STATE_ACTIVE:
+ if (q931_notify_redirection_helper(ctrl, subcall, notify, number)) {
+ status = -1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ } else {
+ status = q931_notify_redirection_helper(ctrl, call, notify, number);
+ }
+ return status;
}
int q931_notify(struct pri *ctrl, q931_call *c, int channel, int info)
@@ -3821,10 +4000,12 @@
ctrl->ev.hangup.channel = q931_encode_channel(c);
ctrl->ev.hangup.cause = c->cause;
ctrl->ev.hangup.cref = c->cr;
- ctrl->ev.hangup.call = c;
+ ctrl->ev.hangup.call = c->master_call;
ctrl->ev.hangup.aoc_units = c->aoc_units;
+ ctrl->ev.hangup.call_held = NULL;
+ ctrl->ev.hangup.call_active = NULL;
libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
- q931_hangup(ctrl, c, c->cause);
+ pri_hangup(ctrl, c, c->cause);
}
/* T305 expiry, first time */
@@ -3966,6 +4147,55 @@
/*! Call Independent Signalling SETUP ie's */
static int cis_setup_ies[] = { Q931_BEARER_CAPABILITY, Q931_CHANNEL_IDENT, Q931_IE_FACILITY, Q931_CALLING_PARTY_NUMBER, Q931_CALLED_PARTY_NUMBER, Q931_SENDING_COMPLETE, -1 };
+
+static void stop_t303(struct q931_call *call)
+{
+ /* T303 should only be running on the master call */
+ pri_schedule_del(call->master_call->pri, call->master_call->t303_timer);
+ call->master_call->t303_timer = 0;
+}
+
+static void t303_expiry(void *data);
+
+static void start_t303(struct q931_call *call)
+{
+ if (call->t303_timer) {
+ pri_error(call->pri, "Should not have T303 set when starting again. Stopping first\n");
+ stop_t303(call);
+ }
+
+ //pri_error(call->pri, "T303 should be %d\n", call->pri->timers[PRI_TIMER_T303]);
+ call->t303_timer = pri_schedule_event(call->pri, call->pri->timers[PRI_TIMER_T303], t303_expiry, call);
+}
+
+static void pri_fake_clearing(void *data);
+
+static void t303_expiry(void *data)
+{
+ struct q931_call *c = data;
+ struct pri *ctrl = c->pri;
+ int res;
+
+ c->t303_expirycnt++;
+ c->t303_timer = 0;
+
+ if (c->t303_expirycnt < 2) {
+ if (ctrl->subchannel && !ctrl->bri)
+ res = send_message(ctrl, c, Q931_SETUP, gr303_setup_ies);
+ else if (c->cis_call)
+ res = send_message(ctrl, c, Q931_SETUP, cis_setup_ies);
+ else
+ res = send_message(ctrl, c, Q931_SETUP, setup_ies);
+
+ if (res) {
+ pri_error(c->pri, "Error resending setup message!\n");
+ }
+ start_t303(c);
+ } else {
+ c->cause = PRI_CAUSE_NO_USER_RESPONSE;
+ pri_fake_clearing(c);
+ }
+}
int q931_setup(struct pri *ctrl, q931_call *c, struct pri_sr *req)
{
@@ -4044,6 +4274,11 @@
c->sendhangupack = 1;
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_CALL_INITIATED);
c->peercallstate = Q931_CALL_STATE_OVERLAP_SENDING;
+ c->t303_expirycnt = 0;
+ if (BRI_NT_PTMP(ctrl)) {
+ c->outboundbroadcast = 1;
+ }
+ start_t303(c);
}
return res;
@@ -4066,7 +4301,7 @@
res = send_message(ctrl, c, Q931_RELEASE_COMPLETE, release_complete_ies);
c->alive = 0;
/* release the structure */
- res += q931_hangup(ctrl,c,cause);
+ res += pri_hangup(ctrl,c,cause);
return res;
}
@@ -4086,9 +4321,35 @@
/*!
* \internal
+ * \brief Find the winning subcall if it exists or current call if not outboundbroadcast.
+ *
+ * \param call Starting Q.931 call record of search.
+ *
+ * \retval winning-call or given call if not outboundbroadcast.
+ * \retval NULL if no winning call yet.
+ */
+static struct q931_call *q931_find_winning_call(struct q931_call *call)
+{
+ struct q931_call *master;
+
+ master = call->master_call;
+ if (master->outboundbroadcast) {
+ /* We have potential subcalls. Now get the winning call if declared yet. */
+ if (master->pri_winner < 0) {
+ /* Winner not declared yet.*/
+ call = NULL;
+ } else {
+ call = master->subcalls[master->pri_winner];
+ }
+ }
+ return call;
+}
+
+/*!
+ * \internal
* \brief Send HOLD message response wait timeout.
*
- * \param data Q.931 call leg.
+ * \param data Q.931 call leg. (Master Q.931 subcall structure)
*
* \return Nothing
*/
@@ -4121,12 +4382,12 @@
* \brief Determine if a hold request is allowed now.
*
* \param ctrl D channel controller.
- * \param call Q.931 call leg
+ * \param call Q.931 call leg. (Master Q.931 subcall structure)
*
* \retval TRUE if we can send a HOLD request.
* \retval FALSE if not allowed.
*/
-static int q931_is_hold_allowed(const struct pri *ctrl, const q931_call *call)
+static int q931_is_hold_allowed(const struct pri *ctrl, const struct q931_call *call)
{
int allowed;
@@ -4170,20 +4431,23 @@
* \brief Send the HOLD message.
*
* \param ctrl D channel controller.
- * \param call Q.931 call leg
+ * \param call Q.931 call leg. (Master Q.931 subcall structure)
*
* \retval 0 on success.
* \retval -1 on error.
*/
-int q931_send_hold(struct pri *ctrl, q931_call *call)
-{
- if (!q931_is_hold_allowed(ctrl, call)) {
+int q931_send_hold(struct pri *ctrl, struct q931_call *call)
+{
+ struct q931_call *winner;
+
+ winner = q931_find_winning_call(call);
+ if (!winner || !q931_is_hold_allowed(ctrl, call)) {
return -1;
}
pri_schedule_del(ctrl, call->hold_timer);
call->hold_timer = pri_schedule_event(ctrl, ctrl->timers[PRI_TIMER_T_HOLD],
q931_hold_timeout, call);
- if (send_message(ctrl, call, Q931_HOLD, hold_ies)) {
+ if (send_message(ctrl, winner, Q931_HOLD, hold_ies)) {
pri_schedule_del(ctrl, call->hold_timer);
call->hold_timer = 0;
return -1;
@@ -4200,26 +4464,33 @@
* \brief Send the HOLD ACKNOWLEDGE message.
*
* \param ctrl D channel controller.
- * \param call Q.931 call leg
+ * \param call Q.931 call leg. (Master Q.931 subcall structure)
*
* \retval 0 on success.
* \retval -1 on error.
*/
-int q931_send_hold_ack(struct pri *ctrl, q931_call *call)
-{
+int q931_send_hold_ack(struct pri *ctrl, struct q931_call *call)
+{
+ struct q931_call *winner;
+
/* 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);
+ winner = q931_find_winning_call(call);
+ if (!winner) {
+ return -1;
+ }
+
/* 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);
+ winner->channelno = 0;/* No channel */
+ winner->ds1no = 0;
+ winner->ds1explicit = 0;
+ winner->chanflags = 0;
+
+ return send_message(ctrl, winner, Q931_HOLD_ACKNOWLEDGE, hold_ack_ies);
}
static int hold_reject_ies[] = {
@@ -4228,23 +4499,18 @@
};
/*!
- * \brief Send the HOLD REJECT message.
+ * \internal
+ * \brief Send the HOLD REJECT message only.
*
* \param ctrl D channel controller.
- * \param call Q.931 call leg
+ * \param call Q.931 call leg. (subcall)
* \param cause Q.931 cause code for rejecting the hold request.
*
* \retval 0 on success.
* \retval -1 on error.
*/
-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);
-
+static int q931_send_hold_rej_msg(struct pri *ctrl, struct q931_call *call, int cause)
+{
call->cause = cause;
call->causecode = CODE_CCITT;
call->causeloc = LOC_PRIV_NET_LOCAL_USER;
@@ -4252,10 +4518,38 @@
}
/*!
+ * \brief Send the HOLD REJECT message.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg. (Master Q.931 subcall structure)
+ * \param cause Q.931 cause code for rejecting the hold request.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int q931_send_hold_rej(struct pri *ctrl, struct q931_call *call, int cause)
+{
+ struct q931_call *winner;
+
+ /* 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);
+
+ winner = q931_find_winning_call(call);
+ if (!winner) {
+ return -1;
+ }
+
+ return q931_send_hold_rej_msg(ctrl, winner, cause);
+}
+
+/*!
* \internal
[... 1273 lines stripped ...]
More information about the libpri-commits
mailing list