[libpri-commits] rmudgett: branch rmudgett/ntptmp r1089 - /team/rmudgett/ntptmp/
SVN commits to the libpri project
libpri-commits at lists.digium.com
Wed Sep 16 19:10:12 CDT 2009
Author: rmudgett
Date: Wed Sep 16 19:10:08 2009
New Revision: 1089
URL: http://svn.asterisk.org/svn-view/libpri?view=rev&rev=1089
Log:
Merged team/mattf/libpri-1.4-ntptmp branch up to -r1071.
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_q921.h
team/rmudgett/ntptmp/q921.c
team/rmudgett/ntptmp/q931.c
Propchange: team/rmudgett/ntptmp/
------------------------------------------------------------------------------
svnmerge-integrated = /branches/1.4:1-1088
Modified: team/rmudgett/ntptmp/libpri.h
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/libpri.h?view=diff&rev=1089&r1=1088&r2=1089
==============================================================================
--- team/rmudgett/ntptmp/libpri.h (original)
+++ team/rmudgett/ntptmp/libpri.h Wed Sep 16 19:10:08 2009
@@ -802,7 +802,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/ntptmp/pri.c
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/pri.c?view=diff&rev=1089&r1=1088&r2=1089
==============================================================================
--- team/rmudgett/ntptmp/pri.c (original)
+++ team/rmudgett/ntptmp/pri.c Wed Sep 16 19:10:08 2009
@@ -150,6 +150,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 */
/* Set any switch specific override default values */
switch (switchtype) {
@@ -223,7 +224,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)
@@ -838,14 +839,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)
@@ -1014,7 +1024,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);
}
@@ -1027,7 +1037,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/ntptmp/pri_internal.h
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/pri_internal.h?view=diff&rev=1089&r1=1088&r2=1089
==============================================================================
--- team/rmudgett/ntptmp/pri_internal.h (original)
+++ team/rmudgett/ntptmp/pri_internal.h Wed Sep 16 19:10:08 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 */
@@ -468,6 +469,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);
@@ -512,4 +525,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/ntptmp/pri_q921.h
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/pri_q921.h?view=diff&rev=1089&r1=1088&r2=1089
==============================================================================
--- team/rmudgett/ntptmp/pri_q921.h (original)
+++ team/rmudgett/ntptmp/pri_q921.h Wed Sep 16 19:10:08 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/ntptmp/q921.c
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/q921.c?view=diff&rev=1089&r1=1088&r2=1089
==============================================================================
--- team/rmudgett/ntptmp/q921.c (original)
+++ team/rmudgett/ntptmp/q921.c Wed Sep 16 19:10:08 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/ntptmp/q931.c
URL: http://svn.asterisk.org/svn-view/libpri/team/rmudgett/ntptmp/q931.c?view=diff&rev=1089&r1=1088&r2=1089
==============================================================================
--- team/rmudgett/ntptmp/q931.c (original)
+++ team/rmudgett/ntptmp/q931.c Wed Sep 16 19:10:08 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 } },
@@ -819,7 +821,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;
@@ -3025,17 +3027,13 @@
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) {
- return cur;
+ goto done;
}
prev = cur;
cur = cur->next;
@@ -3075,29 +3073,24 @@
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);
q931_party_id_init(&cur->remote_id);
q931_party_redirecting_init(&cur->redirecting);
- /* PRI is set to whoever called us */
- if (q931_is_ptmp(ctrl) && (ctrl->localtype == PRI_CPE)) {
- /*
- * Point to the master to avoid stale pointer problems if
- * the TEI is removed later.
- */
- cur->pri = master;
- } else {
- cur->pri = ctrl;
- }
-
/* Append to end of list */
if (prev) {
prev->next = cur;
} else {
*master->callpool = cur;
}
+
+done:
+ /* PRI is set to whoever called us */
+ cur->pri = ctrl;
return cur;
}
@@ -3126,17 +3119,114 @@
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 (c->subcalls[i] == slave) {
+ pri_error(ctrl, "Destroying subcall %p of call %p at %d\n", slave, c, i);
+ cleanup_and_free_call(slave);
+ c->subcalls[i] = NULL;
+ slaveidx = i;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < Q931_MAX_TEI; i++) {
+ if (c->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) &&
+ ((c->pri_winner < 0) || (slave && slaveidx != c->pri_winner))) {
+ pri_create_fake_clearing(c, ctrl);
+ return;
+ }
+
+ if (!slavesleft)
+ goto ultimate_destruction;
+
+ return;
+
+ultimate_destruction:
+ if ((c->pri_winner > -1) && c->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
@@ -3146,9 +3236,7 @@
"NEW_HANGUP DEBUG: Destroying the call, ourstate %s, peerstate %s\n",
q931_call_state_str(cur->ourcallstate),
q931_call_state_str(cur->peercallstate));
- pri_schedule_del(ctrl, cur->retranstimer);
- pri_call_apdu_queue_cleanup(cur);
- free(cur);
+ cleanup_and_free_call(c);
return;
}
prev = cur;
@@ -3157,10 +3245,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)
@@ -3344,9 +3434,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 */
@@ -3414,7 +3515,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(call->pri, h, len, 1, (msgtype == Q931_SETUP) ? 1 : 0);
}
call->acked = 1;
return 0;
@@ -3757,10 +3859,10 @@
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;
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 */
@@ -3902,6 +4004,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 = 18;
+ pri_fake_clearing(c);
+ }
+}
int q931_setup(struct pri *ctrl, q931_call *c, struct pri_sr *req)
{
@@ -3980,6 +4131,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;
@@ -4002,7 +4158,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;
}
@@ -4020,10 +4176,34 @@
return 0;
}
-int q931_hangup(struct pri *ctrl, q931_call *c, int cause)
+static int pri_internal_clear(void *data);
+
+/* Fake RELEASE for NT-PTMP initiated SETUPs w/o response */
+static void pri_fake_clearing(void *data)
+{
+ struct q931_call *c = data;
+ struct pri *ctrl = c->pri;
+
+ c->performing_fake_clearing = 1;
+ if (pri_internal_clear(c) == Q931_RES_HAVEEVENT)
+ ctrl->schedev = 1;
+}
+
+static void pri_create_fake_clearing(struct q931_call *c, struct pri *master)
+{
+ c->pri = master;
+
+ pri_schedule_del(master, c->retranstimer);
+ c->retranstimer = pri_schedule_event(master, 0, pri_fake_clearing, c);
+}
+
+//static int q931_get_subcall_count(struct q931_call *call);
+
+static int __q931_hangup(struct pri *ctrl, q931_call *c, int cause)
{
int disconnect = 1;
int release_compl = 0;
+ int t303_was_running = c->master_call->t303_timer;
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
pri_message(ctrl,
@@ -4058,16 +4238,28 @@
disconnect = 0;
}
+ c->hangupinitiated = 1;
+ stop_t303(c);
+
/* All other causes we send with DISCONNECT */
switch(c->ourcallstate) {
case Q931_CALL_STATE_NULL:
if (c->peercallstate == Q931_CALL_STATE_NULL)
/* free the resources if we receive or send REL_COMPL */
- q931_destroycall(ctrl, c->cr);
+ __q931_destroycall(ctrl, c);
else if (c->peercallstate == Q931_CALL_STATE_RELEASE_REQUEST)
q931_release_complete(ctrl,c,cause);
break;
case Q931_CALL_STATE_CALL_INITIATED:
+ if (BRI_NT_PTMP(ctrl) && (c->master_call == c) && c->outboundbroadcast && t303_was_running) {
+ //c->fakeclearing = 1;
+ //c->alive = 0;
+ /* We need to fake a received clearing sequence in this case... */
+ pri_error(ctrl, "Faking clearing\n");
+ pri_create_fake_clearing(c, PRI_MASTER(ctrl));
+ /* This means that we never got a response from a TEI */
+ return 0;
+ }
/* we sent SETUP */
case Q931_CALL_STATE_OVERLAP_SENDING:
/* received SETUP_ACKNOWLEDGE */
@@ -4151,6 +4343,46 @@
return 0;
}
+static void initiate_hangup_if_needed(struct pri *pri, q931_call *call, int cause);
+
+int q931_hangup(struct pri *ctrl, q931_call *call, int cause)
+{
+ int i;
+
+ /* Master is called with hangup - initiate hangup with slaves */
+ if (BRI_NT_PTMP(ctrl) && call->master_call->outboundbroadcast) {
+ if (call->master_call == call) {
+ int slaves = 0;
+ for (i = 0; i < Q931_MAX_TEI; i++) {
+ if (call->subcalls[i]) {
+ slaves++;
+ if (i == call->master_call->pri_winner) {
+ __q931_hangup(call->subcalls[i]->pri, call->subcalls[i], cause);
+ } else {
+ initiate_hangup_if_needed(call->subcalls[i]->pri, call->subcalls[i], cause);
+ }
+ pri_error(ctrl, "%s: Hanging up %d, winner %d\n", __FUNCTION__, i, call->master_call->pri_winner);
+ }
+ }
+
+ call->hangupinitiated = 1;
+
+ if ((!slaves && (call->master_call->pri_winner < 0)) || (call->performing_fake_clearing)) {
+ __q931_hangup(ctrl, call, cause);
+ }
+ pri_error(ctrl, "%s: Slaves %d\n", __FUNCTION__, slaves);
+ return 0;
+ } else {
+ pri_error(ctrl, "%s: Slave hangup\n", __FUNCTION__);
+ return __q931_hangup(ctrl, call, cause);
+ }
+ } else {
+ pri_error(ctrl, "%s: other hangup\n", __FUNCTION__);
+ return __q931_hangup(ctrl, call, cause);
+ }
+ return 0;
+}
+
static int prepare_to_handle_maintenance_message(struct pri *ctrl, q931_mh *mh, q931_call *c)
{
if ((!ctrl) || (!mh) || (!c)) {
@@ -4307,10 +4539,106 @@
pri_error(ctrl, "!! Don't know how to pre-handle message type %s (%d)\n", msg2str(mh->msg), mh->msg);
q931_status(ctrl,c, PRI_CAUSE_MESSAGE_TYPE_NONEXIST);
if (c->newcall)
- q931_destroycall(ctrl,c->cr);
+ __q931_destroycall(ctrl, c);
return -1;
}
return 0;
+}
+
+static struct q931_call * q931_get_subcall_winner(struct q931_call *call)
+{
+ if (call->master_call->pri_winner < 0) {
+ return NULL;
+ } else
+ return call->subcalls[call->pri_winner];
+
+}
+
+static void initiate_hangup_if_needed(struct pri *pri, q931_call *call, int cause)
+{
+ if (!call->hangupinitiated) {
+ q931_hangup(pri, call, cause);
+ call->alive = 0;
+ }
+}
+
+#if 0
+static int q931_get_subcall_count(struct q931_call *call)
+{
+ int count = 0;
+ int i;
+ call = call->master_call;
+
+ for (i = 0; i < Q931_MAX_TEI; i++) {
+ if (call->subcalls[i])
+ count++;
+ }
+
+ return count;
+}
+#endif
+
+static void q931_set_subcall_winner(struct q931_call *subcall)
+{
+ struct q931_call *realcall = subcall->master_call;
+ int i;
+
+ /* Set the winner first */
+ for (i = 0; i < Q931_MAX_TEI; i++) {
+ if (realcall->subcalls[i] && realcall->subcalls[i] == subcall) {
+ realcall->pri_winner = i;
+ }
+ }
+
+ if (realcall->pri_winner < 0) {
+ pri_message(subcall->pri, "We should always find the winner in the list!\n");
+ return;
+ }
+
+ /* Start tear down of calls that were not chosen */
+ for (i = 0; i < Q931_MAX_TEI; i++) {
+ if (realcall->subcalls[i] && realcall->subcalls[i] != subcall) {
+ initiate_hangup_if_needed(realcall->subcalls[i]->pri, realcall->subcalls[i], 26);
+ }
+ }
+}
+
+static struct q931_call * q931_get_subcall(struct q931_call *call, struct pri *ctrl)
+{
+ int i;
+ struct q931_call *cur = NULL;
+ int firstfree = -1;
+
+ /* First try to locate our subcall */
+ for (i = 0; i < Q931_MAX_TEI; i++) {
+ if (call->subcalls[i]) {
+ if (call->subcalls[i]->pri == ctrl) {
+ return call->subcalls[i];
+ }
+ } else if (firstfree == -1)
+ firstfree = i;
+ }
+
+ if (firstfree < 0) {
+ pri_error(ctrl, "Tried to add more than %d TEIs to call and failed\n", Q931_MAX_TEI);
+ return NULL;
+ }
+
+ cur = malloc(sizeof(*cur));
+ if (!cur) {
+ pri_error(ctrl, "Unable to allocate call\n");
+ return NULL;
+ }
+ *cur = *call;
+ call->subcalls[firstfree] = cur;
+ cur->pri = ctrl;
+ cur->master_call = call;
+ /* T303 should only be on on the master call */
+ cur->t303_timer = 0;
+ pri_error(ctrl, "Adding subcall %p for TEI %d to call %p at position %d\n", cur, ctrl->tei, call, firstfree);
+ /* Should only get here if the TEI is not found */
+ return cur;
+
}
int q931_receive(struct pri *ctrl, q931_h *h, int len)
@@ -4347,7 +4675,7 @@
KLUDGE this by changing byte 4 from a 0xf (SERVICE)
to a 0x7 (SERVICE ACKNOWLEDGE) */
h->raw[h->crlen + 2] -= 0x8;
- q931_xmit(ctrl, h, len, 1);
+ q931_xmit(ctrl, h, len, 1, 0);
return 0;
}
cref = q931_cr(h);
@@ -4356,6 +4684,16 @@
pri_error(ctrl, "Unable to locate call %d\n", cref);
return -1;
}
+
+ if (BRI_NT_PTMP(ctrl) && (ctrl != PRI_MASTER(ctrl)) && !c->newcall && c->outboundbroadcast) {
+ c = q931_get_subcall(c, ctrl);
+ if (!c) {
+ pri_error(ctrl, "Unable to locate subcall %d\n", cref);
+ return -1;
+ }
+ }
+
+ pri_message(ctrl, "Received message for call %p on %p TEI/SAPI %d/%d, call->pri is %p TEI/SAPI %d/%d\n", c, ctrl, ctrl->tei, ctrl->sapi, c->pri, c->pri->tei, c->pri->sapi);
/* Preliminary handling */
if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
prepare_to_handle_maintenance_message(ctrl, mh, c);
@@ -4455,7 +4793,21 @@
if ((h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_1) || (h->pd == MAINTENANCE_PROTOCOL_DISCRIMINATOR_2)) {
res = post_handle_maintenance_message(ctrl, h->pd, mh, c);
} else {
- res = post_handle_q931_message(ctrl, mh, c, missingmand);
+ int allow_event = 1, allow_posthandle = 1;
+
+ if (BRI_NT_PTMP(ctrl) && c->master_call->outboundbroadcast) {
+ nt_ptmp_handle_q931_message(ctrl, mh, c, &allow_event, &allow_posthandle);
+ }
+
+ if (allow_posthandle) {
+ res = post_handle_q931_message(ctrl, mh, c, missingmand);
+
+ if (res == Q931_RES_HAVEEVENT && !allow_event) {
+ res = 0;
+ }
+ } else {
+ res = 0;
+ }
}
return res;
}
@@ -4515,6 +4867,67 @@
return -1;
}
+/* This is where we interact the subcalls state with the master_call's state */
+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 q931_call *master = c->master_call;
+ struct q931_call *winner = q931_get_subcall_winner(master);
+ int newstate;
+
+ /* For broadcast calls, we default to not allowing events to keep events received to a minimum
+ * and to allow post processing, since that is where hangup and subcall state handling and other processing is done */
+ *allow_event = 0;
+ *allow_posthandle = 1;
+ switch (mh->msg) {
+ case Q931_CALL_PROCEEDING:
+ if (master->ourcallstate < Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING) {
+ *allow_event = 1;
+ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_OUTGOING_CALL_PROCEEDING);
+ }
+ break;
+ case Q931_ALERTING:
+ if (master->ourcallstate < Q931_CALL_STATE_CALL_DELIVERED) {
+ *allow_event = 1;
+ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_CALL_DELIVERED);
+ }
+ break;
+ case Q931_CONNECT:
+ if (!winner) {
+ UPDATE_OURCALLSTATE(ctrl, master, Q931_CALL_STATE_ACTIVE);
+ q931_set_subcall_winner(c);
+ *allow_event = 1;
+ } else {
+ /* Call clearing occurs of non selected calls occurs in
+ * q931_set_subcall_winner() - All we need to do is make sure
+ * that this connect is not acknowledged */
+ *allow_posthandle = 0;
+ }
+ break;
+ case Q931_DISCONNECT:
+ newstate = Q931_CALL_STATE_DISCONNECT_INDICATION;
+ goto process_hangup;
+ case Q931_RELEASE:
+ case Q931_RELEASE_COMPLETE:
+ newstate = Q931_CALL_STATE_NULL;
+process_hangup:
+ if (!winner) {
+ /* If there's not a winner, we just take the cause and pass it up to the
+ * master_call */
+ master->cause = c->cause;
+ } else {
+ /* There *is* a winner */
+ if (c == winner) {
+ /* .. and we're it: */
+ *allow_event = 1;
+ UPDATE_OURCALLSTATE(ctrl, master, newstate);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
/*!
* \internal
* \brief Fill in the FACILITY event fields.
@@ -4530,7 +4943,7 @@
ctrl->ev.facility.subcmds = &ctrl->subcmds;
ctrl->ev.facility.channel = q931_encode_channel(call);
ctrl->ev.facility.cref = call->cr;
- ctrl->ev.facility.call = call;
+ ctrl->ev.facility.call = call->master_call;
/* Need to do this for backward compatibility with struct pri_event_facname */
libpri_copy_string(ctrl->ev.facility.callingname, call->remote_id.name.str,
@@ -4564,7 +4977,7 @@
case Q931_RESTART:
if (missingmand) {
q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
- q931_destroycall(ctrl, c->cr);
+ __q931_destroycall(ctrl, c);
break;
}
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_RESTART);
@@ -4670,7 +5083,7 @@
ctrl->ev.ring.flexible = ! (c->chanflags & FLAG_EXCLUSIVE);
ctrl->ev.ring.cref = c->cr;
- ctrl->ev.ring.call = c;
+ ctrl->ev.ring.call = c->master_call;
ctrl->ev.ring.layer1 = c->userl1;
ctrl->ev.ring.complete = c->complete;
ctrl->ev.ring.ctype = c->transcapability;
@@ -4690,6 +5103,7 @@
return Q931_RES_HAVEEVENT;
case Q931_ALERTING:
+ stop_t303(c);
if (c->newcall) {
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
break;
@@ -4700,7 +5114,7 @@
ctrl->ev.ringing.subcmds = &ctrl->subcmds;
ctrl->ev.ringing.channel = q931_encode_channel(c);
ctrl->ev.ringing.cref = c->cr;
- ctrl->ev.ringing.call = c;
+ ctrl->ev.ringing.call = c->master_call;
ctrl->ev.ringing.progress = c->progress;
ctrl->ev.ringing.progressmask = c->progressmask;
@@ -4718,6 +5132,7 @@
return Q931_RES_HAVEEVENT;
case Q931_CONNECT:
+ stop_t303(c);
if (c->newcall) {
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
break;
@@ -4733,7 +5148,7 @@
ctrl->ev.answer.subcmds = &ctrl->subcmds;
ctrl->ev.answer.channel = q931_encode_channel(c);
ctrl->ev.answer.cref = c->cr;
- ctrl->ev.answer.call = c;
+ ctrl->ev.answer.call = c->master_call;
ctrl->ev.answer.progress = c->progress;
ctrl->ev.answer.progressmask = c->progressmask;
libpri_copy_string(ctrl->ev.answer.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.answer.useruserinfo));
@@ -4782,13 +5197,14 @@
case Q931_PROGRESS:
if (missingmand) {
q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
- q931_destroycall(ctrl, c->cr);
+ __q931_destroycall(ctrl, c);
break;
}
ctrl->ev.e = PRI_EVENT_PROGRESS;
ctrl->ev.proceeding.cause = c->cause;
/* Fall through */
case Q931_CALL_PROCEEDING:
+ stop_t303(c);
ctrl->ev.proceeding.subcmds = &ctrl->subcmds;
if (c->newcall) {
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
@@ -4810,7 +5226,7 @@
ctrl->ev.proceeding.progress = c->progress;
ctrl->ev.proceeding.progressmask = c->progressmask;
ctrl->ev.proceeding.cref = c->cr;
- ctrl->ev.proceeding.call = c;
+ ctrl->ev.proceeding.call = c->master_call;
cur = c->apdus;
while (cur) {
@@ -4838,7 +5254,7 @@
case Q931_STATUS:
if (missingmand) {
q931_status(ctrl, c, PRI_CAUSE_MANDATORY_IE_MISSING);
- q931_destroycall(ctrl, c->cr);
+ __q931_destroycall(ctrl, c);
break;
}
if (c->newcall) {
@@ -4865,7 +5281,7 @@
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;
libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
/* Free resources */
@@ -4878,9 +5294,9 @@
} else if (c->sendhangupack) {
res = Q931_RES_HAVEEVENT;
ctrl->ev.e = PRI_EVENT_HANGUP_ACK;
- q931_hangup(ctrl, c, c->cause);
+ pri_hangup(ctrl, c, c->cause);
} else {
- q931_hangup(ctrl, c, c->cause);
+ pri_hangup(ctrl, c, c->cause);
res = 0;
}
if (res)
@@ -4888,13 +5304,15 @@
}
break;
case Q931_RELEASE_COMPLETE:
+ stop_t303(c);
+ c->hangupinitiated = 1;
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
c->peercallstate = Q931_CALL_STATE_NULL;
ctrl->ev.hangup.subcmds = &ctrl->subcmds;
ctrl->ev.hangup.channel = q931_encode_channel(c);
ctrl->ev.hangup.cause = c->cause;
ctrl->ev.hangup.cref = c->cr;
- ctrl->ev.hangup.call = c;
+ ctrl->ev.hangup.call = c->master_call;
ctrl->ev.hangup.aoc_units = c->aoc_units;
libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
c->useruserinfo[0] = '\0';
@@ -4909,12 +5327,14 @@
pri_hangup(ctrl, c, c->cause);
} else
res = 0;
+
if (res)
return res;
else
- q931_hangup(ctrl,c,c->cause);
+ pri_hangup(ctrl,c,c->cause);
break;
case Q931_RELEASE:
+ c->hangupinitiated = 1;
if (missingmand) {
/* Force cause to be mandatory IE missing */
c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
@@ -4930,7 +5350,7 @@
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;
libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
c->useruserinfo[0] = '\0';
@@ -4938,10 +5358,13 @@
while we sent it, assume a NULL state */
if (c->newcall)
q931_release_complete(ctrl,c,PRI_CAUSE_INVALID_CALL_REFERENCE);
- else
+ else if (c->outboundbroadcast && (c != q931_get_subcall_winner(c->master_call)))
+ return pri_hangup(ctrl, c, -1);
+ else
return Q931_RES_HAVEEVENT;
break;
case Q931_DISCONNECT:
+ c->hangupinitiated = 1;
if (missingmand) {
/* Still let user call release */
c->cause = PRI_CAUSE_MANDATORY_IE_MISSING;
@@ -4965,14 +5388,14 @@
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;
libpri_copy_string(ctrl->ev.hangup.useruserinfo, c->useruserinfo, sizeof(ctrl->ev.hangup.useruserinfo));
c->useruserinfo[0] = '\0';
if (c->alive)
return Q931_RES_HAVEEVENT;
else
- q931_hangup(ctrl,c,c->cause);
+ pri_hangup(ctrl,c,c->cause);
break;
case Q931_RESTART_ACKNOWLEDGE:
UPDATE_OURCALLSTATE(ctrl, c, Q931_CALL_STATE_NULL);
@@ -4992,14 +5415,14 @@
[... 78 lines stripped ...]
More information about the libpri-commits
mailing list