[libpri-commits] rmudgett: branch 1.4 r1275 - /branches/1.4/
SVN commits to the libpri project
libpri-commits at lists.digium.com
Tue Nov 10 13:27:38 CST 2009
Author: rmudgett
Date: Tue Nov 10 13:27:34 2009
New Revision: 1275
URL: http://svnview.digium.com/svn/libpri?view=rev&rev=1275
Log:
Add dummy call reference support.
Fixes problem where PTMP NT mode responds erroneously to a FACILITY
message from a phone on the dummy call reference. LibPRI behaved as if
the dummy call reference were an invalid call reference and proceeded to
respond on the global call reference.
Modified:
branches/1.4/libpri.h
branches/1.4/pri.c
branches/1.4/pri_internal.h
branches/1.4/q931.c
Modified: branches/1.4/libpri.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/libpri.h?view=diff&rev=1275&r1=1274&r2=1275
==============================================================================
--- branches/1.4/libpri.h (original)
+++ branches/1.4/libpri.h Tue Nov 10 13:27:34 2009
@@ -929,6 +929,14 @@
/* Create a new call */
q931_call *pri_new_call(struct pri *pri);
+/*!
+ * \brief Deterimine if the given call control pointer is a dummy call.
+ *
+ * \retval TRUE if given call is a dummy call.
+ * \retval FALSE otherwise.
+ */
+int pri_is_dummy_call(q931_call *call);
+
/* Retrieve CRV reference for GR-303 calls. Returns >0 on success. */
int pri_get_crv(struct pri *pri, q931_call *call, int *callmode);
Modified: branches/1.4/pri.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri.c?view=diff&rev=1275&r1=1274&r2=1275
==============================================================================
--- branches/1.4/pri.c (original)
+++ branches/1.4/pri.c Tue Nov 10 13:27:34 2009
@@ -226,18 +226,44 @@
return res;
}
-/* Pass in the master for this function */
void __pri_free_tei(struct pri * p)
{
- free(p);
+ if (p) {
+ struct q931_call *call;
+
+ call = p->dummy_call;
+ if (call) {
+ pri_schedule_del(call->pri, call->retranstimer);
+ pri_call_apdu_queue_cleanup(call);
+ }
+ 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)
{
+ struct d_ctrl_dummy *dummy_ctrl;
struct pri *p;
- if (!(p = calloc(1, sizeof(*p))))
- return NULL;
+ switch (switchtype) {
+ case PRI_SWITCH_GR303_EOC:
+ case PRI_SWITCH_GR303_TMC:
+ case PRI_SWITCH_GR303_TMC_SWITCHING:
+ case PRI_SWITCH_GR303_EOC_PATH:
+ p = calloc(1, sizeof(*p));
+ if (!p) {
+ return NULL;
+ }
+ dummy_ctrl = NULL;
+ break;
+ default:
+ dummy_ctrl = calloc(1, sizeof(*dummy_ctrl));
+ if (!dummy_ctrl) {
+ return NULL;
+ }
+ p = &dummy_ctrl->ctrl;
+ break;
+ }
p->bri = bri;
p->fd = fd;
@@ -265,7 +291,14 @@
p->q931_rxcount = 0;
p->q931_txcount = 0;
#endif
- if (switchtype == PRI_SWITCH_GR303_EOC) {
+ if (dummy_ctrl) {
+ /* Initialize the dummy call reference call record. */
+ dummy_ctrl->ctrl.dummy_call = &dummy_ctrl->dummy_call;
+ q931_init_call_record(&dummy_ctrl->ctrl, dummy_ctrl->ctrl.dummy_call,
+ Q931_DUMMY_CALL_REFERENCE);
+ }
+ switch (switchtype) {
+ case PRI_SWITCH_GR303_EOC:
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
p->sapi = Q921_SAPI_GR303_EOC;
p->tei = Q921_TEI_GR303_EOC_OPS;
@@ -274,7 +307,8 @@
free(p);
p = NULL;
}
- } else if (switchtype == PRI_SWITCH_GR303_TMC) {
+ break;
+ case PRI_SWITCH_GR303_TMC:
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
p->sapi = Q921_SAPI_GR303_TMC_CALLPROC;
p->tei = Q921_TEI_GR303_TMC_CALLPROC;
@@ -283,14 +317,19 @@
free(p);
p = NULL;
}
- } else if (switchtype == PRI_SWITCH_GR303_TMC_SWITCHING) {
+ break;
+ case PRI_SWITCH_GR303_TMC_SWITCHING:
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
p->sapi = Q921_SAPI_GR303_TMC_SWITCHING;
p->tei = Q921_TEI_GR303_TMC_SWITCHING;
- } else if (switchtype == PRI_SWITCH_GR303_EOC_PATH) {
+ break;
+ case PRI_SWITCH_GR303_EOC_PATH:
p->protodisc = GR303_PROTOCOL_DISCRIMINATOR;
p->sapi = Q921_SAPI_GR303_EOC;
p->tei = Q921_TEI_GR303_EOC_PATH;
+ break;
+ default:
+ break;
}
/* Start Q.921 layer, Wait if we're the network */
if (p)
@@ -935,6 +974,14 @@
return q931_new_call(pri);
}
+int pri_is_dummy_call(q931_call *call)
+{
+ if (!call) {
+ return 0;
+ }
+ return q931_is_dummy_call(call);
+}
+
void pri_dump_event(struct pri *pri, pri_event *e)
{
if (!pri || !e)
Modified: branches/1.4/pri_internal.h
URL: http://svnview.digium.com/svn/libpri/branches/1.4/pri_internal.h?view=diff&rev=1275&r1=1274&r2=1275
==============================================================================
--- branches/1.4/pri_internal.h (original)
+++ branches/1.4/pri_internal.h Tue Nov 10 13:27:34 2009
@@ -114,6 +114,13 @@
q931_call **callpool;
q931_call *localpool;
+ /*!
+ * \brief Q.931 Dummy call reference call associated with this TEI.
+ * \note If present then this call is allocated as part of the
+ * D channel control structure.
+ */
+ q931_call *dummy_call;
+
/* do we do overlap dialing */
int overlapdial;
@@ -506,6 +513,14 @@
int pri_winner;
};
+/*! D channel control structure with associated dummy call reference record. */
+struct d_ctrl_dummy {
+ /*! D channel control structure. */
+ struct pri ctrl;
+ /*! Dummy call reference call record. */
+ struct q931_call dummy_call;
+};
+
extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);
extern pri_event *pri_schedule_run(struct pri *pri);
@@ -522,6 +537,8 @@
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);
void __pri_free_tei(struct pri *p);
+
+void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr);
void q931_party_name_init(struct q931_party_name *name);
void q931_party_number_init(struct q931_party_number *number);
@@ -589,4 +606,17 @@
return pri->bri && (((pri)->localtype == PRI_CPE) && ((pri)->tei == Q921_TEI_GROUP));
}
+#define Q931_DUMMY_CALL_REFERENCE -1
+
+/*!
+ * \brief Deterimine if the given call control pointer is a dummy call.
+ *
+ * \retval TRUE if given call is a dummy call.
+ * \retval FALSE otherwise.
+ */
+static inline int q931_is_dummy_call(const q931_call *call)
+{
+ return (call->cr == Q931_DUMMY_CALL_REFERENCE) ? 1 : 0;
+}
+
#endif
Modified: branches/1.4/q931.c
URL: http://svnview.digium.com/svn/libpri/branches/1.4/q931.c?view=diff&rev=1275&r1=1274&r2=1275
==============================================================================
--- branches/1.4/q931.c (original)
+++ branches/1.4/q931.c Tue Nov 10 13:27:34 2009
@@ -3307,30 +3307,38 @@
return "Unknown Message Type";
}
+/* Decode the call reference */
static inline int q931_cr(q931_h *h)
{
- int cr = 0;
+ int cr;
int x;
+
if (h->crlen > 3) {
pri_error(NULL, "Call Reference Length Too long: %d\n", h->crlen);
- return -1;
+ return Q931_DUMMY_CALL_REFERENCE;
}
switch (h->crlen) {
- case 2:
- for (x=0;x<h->crlen;x++) {
- cr <<= 8;
- cr |= h->crv[x];
- }
- break;
- case 1:
- cr = h->crv[0];
- if (cr & 0x80) {
- cr &= ~0x80;
- cr |= 0x8000;
- }
- break;
- default:
- pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen);
+ case 2:
+ cr = 0;
+ for (x = 0; x < h->crlen; ++x) {
+ cr <<= 8;
+ cr |= h->crv[x];
+ }
+ break;
+ case 1:
+ cr = h->crv[0];
+ if (cr & 0x80) {
+ cr &= ~0x80;
+ cr |= 0x8000;
+ }
+ break;
+ case 0:
+ cr = Q931_DUMMY_CALL_REFERENCE;
+ break;
+ default:
+ pri_error(NULL, "Call Reference Length not supported: %d\n", h->crlen);
+ cr = Q931_DUMMY_CALL_REFERENCE;
+ break;
}
return cr;
}
@@ -3370,11 +3378,72 @@
pri_error(ctrl, "!! %c Unknown IE %d (cs%d, len = %d)\n", prefix, Q931_IE_IE(base_ie), Q931_IE_CODESET(base_ie), ielen(ie));
}
+/*!
+ * \brief Initialize the call record.
+ *
+ * \param ctrl D channel controller.
+ * \param call Q.931 call leg.
+ *
+ * \note The call record is assumed to already be memset() to zero.
+ *
+ * \return Nothing
+ */
+void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr)
+{
+ call->cr = cr;
+ call->slotmap = -1;
+ call->channelno = -1;
+ if (cr != Q931_DUMMY_CALL_REFERENCE) {
+ call->newcall = 1;
+ }
+ call->ourcallstate = Q931_CALL_STATE_NULL;
+ call->peercallstate = Q931_CALL_STATE_NULL;
+ call->sugcallstate = Q931_CALL_STATE_NOT_SET;
+ call->ri = -1;
+ call->transcapability = -1;
+ call->transmoderate = -1;
+ call->transmultiple = -1;
+ call->userl1 = -1;
+ call->userl2 = -1;
+ call->userl3 = -1;
+ call->rateadaption = -1;
+ call->progress = -1;
+ call->causecode = -1;
+ call->causeloc = -1;
+ call->cause = -1;
+ call->useruserprotocoldisc = -1;
+ call->aoc_units = -1;
+ call->changestatus = -1;
+ call->reversecharge = -1;
+ call->pri_winner = -1;
+ call->master_call = call;
+ q931_party_number_init(&call->redirection_number);
+ q931_party_address_init(&call->called);
+ q931_party_id_init(&call->local_id);
+ q931_party_id_init(&call->remote_id);
+ q931_party_redirecting_init(&call->redirecting);
+
+ /* PRI is set to whoever called us */
+ if (BRI_TE_PTMP(ctrl)) {
+ /*
+ * Point to the master to avoid stale pointer problems if
+ * the TEI is removed later.
+ */
+ call->pri = PRI_MASTER(ctrl);
+ } else {
+ call->pri = ctrl;
+ }
+}
+
static q931_call *q931_getcall(struct pri *ctrl, int cr)
{
q931_call *cur;
q931_call *prev;
struct pri *master;
+
+ if (cr == Q931_DUMMY_CALL_REFERENCE) {
+ return ctrl->dummy_call;
+ }
/* Find the master - He has the call pool */
master = PRI_MASTER(ctrl);
@@ -3414,47 +3483,7 @@
}
/* Initialize call structure. */
- cur->cr = cr;
- cur->slotmap = -1;
- cur->channelno = -1;
- cur->newcall = 1;
- cur->ourcallstate = Q931_CALL_STATE_NULL;
- cur->peercallstate = Q931_CALL_STATE_NULL;
- cur->sugcallstate = Q931_CALL_STATE_NOT_SET;
- cur->ri = -1;
- cur->transcapability = -1;
- cur->transmoderate = -1;
- cur->transmultiple = -1;
- cur->userl1 = -1;
- cur->userl2 = -1;
- cur->userl3 = -1;
- cur->rateadaption = -1;
- cur->progress = -1;
- cur->causecode = -1;
- cur->causeloc = -1;
- cur->cause = -1;
- cur->useruserprotocoldisc = -1;
- 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 (BRI_TE_PTMP(ctrl)) {
- /*
- * Point to the master to avoid stale pointer problems if
- * the TEI is removed later.
- */
- cur->pri = master;
- } else {
- cur->pri = ctrl;
- }
+ q931_init_call_record(ctrl, cur, cr);
/* Append to end of list */
if (prev) {
@@ -3511,6 +3540,10 @@
int slavesleft;
int slaveidx;
+ if (q931_is_dummy_call(c)) {
+ /* Cannot destroy the dummy call. */
+ return;
+ }
if (c->master_call != c) {
slave = c;
c = slave->master_call;
@@ -3711,7 +3744,9 @@
cref = q931_cr(h);
pri_message(ctrl, "%c Call Ref: len=%2d (reference %d/0x%X) (%s)\n",
c, h->crlen, cref & 0x7FFF, cref & 0x7FFF,
- (cref & 0x8000) ? "Terminator" : "Originator");
+ (cref == Q931_DUMMY_CALL_REFERENCE)
+ ? "Dummy"
+ : (cref & 0x8000) ? "Terminator" : "Originator");
/* Message header begins at the end of the call reference number */
mh = (q931_mh *)(h->contents + h->crlen);
@@ -3778,7 +3813,9 @@
h->pd = ctrl->protodisc;
}
h->x0 = 0; /* Reserved 0 */
- if (!ctrl->bri) {
+ if (q931_is_dummy_call(call)) {
+ h->crlen = 0;
+ } else if (!ctrl->bri) {
/* Two bytes of Call Reference. */
h->crlen = 2;
/* Invert the top bit to make it from our sense */
@@ -3807,18 +3844,11 @@
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)
+ if (uiframe) {
q921_transmit_uiframe(ctrl, h, len);
- else
+ } 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 */
@@ -3893,6 +3923,43 @@
ctrl = ctrl->subchannel;
}
if (ctrl) {
+ int uiframe;
+
+ switch (msgtype) {
+ case Q931_SETUP:
+ /*
+ * 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.
+ */
+ uiframe = call->outboundbroadcast;
+ break;
+ case Q931_FACILITY:
+ if (ctrl->tei == Q921_TEI_GROUP) {
+ /* Broadcast TEI. */
+ if (q931_is_dummy_call(call)) {
+ /*
+ * This is a FACILITY message on the dummy call reference
+ * for the broadcast TEI.
+ */
+ uiframe = 1;
+ } else {
+ pri_error(ctrl,
+ "Attempting to broadcast %s on cref %d\n",
+ msg2str(msgtype), call->cr);
+ return -1;
+ }
+ } else {
+ uiframe = 0;
+ }
+ break;
+ default:
+ uiframe = 0;
+ break;
+ }
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl,
"Sending message for call %p on %p TEI/SAPI %d/%d, call->pri is %p, TEI/SAPI %d/%d\n",
@@ -3900,7 +3967,7 @@
ctrl, ctrl->tei, ctrl->sapi,
call->pri, call->pri->tei, call->pri->sapi);
}
- q931_xmit(ctrl, h, len, 1, (msgtype == Q931_SETUP) ? 1 : 0);
+ q931_xmit(ctrl, h, len, 1, uiframe);
}
call->acked = 1;
return 0;
@@ -5375,6 +5442,9 @@
c->ri = -1;
break;
case Q931_FACILITY:
+ if (q931_is_dummy_call(c)) {
+ q931_party_address_init(&c->called);
+ }
break;
case Q931_SETUP:
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
@@ -7288,7 +7358,10 @@
int q931_call_setcrv(struct pri *ctrl, q931_call *call, int crv, int callmode)
{
- call->cr = (crv << 3) & 0x7fff;
- call->cr |= (callmode & 0x7);
+ /* Do not allow changing the dummy call reference */
+ if (!q931_is_dummy_call(call)) {
+ call->cr = (crv << 3) & 0x7fff;
+ call->cr |= (callmode & 0x7);
+ }
return 0;
}
More information about the libpri-commits
mailing list