PTMP NT mode call reference value ambiguity.

Since the TE side can pick CR values independently, the TE CR needs to be
qualified by TEI to distinguish CR values from other devices.  Without
doing this, multiple phones on the BRI line will have intermittent call
failures.

JIRA LIBPRI-30

Also eliminated some wierdness in q931_status() and several places where
it is called.


git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@1630 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
Richard Mudgett 2010-04-19 22:40:41 +00:00
parent 7babaeb2fe
commit e42108aaae
4 changed files with 187 additions and 121 deletions

View File

@ -513,8 +513,6 @@ struct q931_call {
-1 - No reverse charging
1 - Reverse charging
0,2-7 - Reserved for future use */
/*! \brief TEI associated with call */
int tei;
int t303_timer;
int t303_expirycnt;
@ -719,6 +717,7 @@ static inline int PTMP_MODE(const struct pri *ctrl)
}
#define Q931_DUMMY_CALL_REFERENCE -1
#define Q931_CALL_REFERENCE_FLAG 0x8000 /* Identify which end allocted the CR. */
/*!
* \brief Deterimine if the given call control pointer is a dummy call.

View File

@ -486,10 +486,11 @@ extern int q931_call_getcrv(struct pri *pri, q931_call *call, int *callmode);
extern int q931_call_setcrv(struct pri *pri, q931_call *call, int crv, int callmode);
extern q931_call *q931_new_call(struct pri *pri);
struct q931_call *q931_find_call(struct pri *ctrl, int cr);
struct q931_call *q931_new_call(struct pri *pri);
extern int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req);
extern void q931_dump(struct pri *pri, q931_h *h, int len, int txrx);
void q931_dump(struct pri *ctrl, int tei, q931_h *h, int len, int txrx);
void q931_destroycall(struct pri *pri, q931_call *c);

View File

@ -73,7 +73,7 @@ static void dump_packet(struct pri *pri, char *buf, int len, int txrx)
q921_h *h = (q921_h *)buf;
q921_dump(pri, h, len, 1, txrx);
if (!((h->h.data[0] & Q921_FRAMETYPE_MASK) & 0x3)) {
q931_dump(pri, (q931_h *)(h->i.data), len - 4 - 2 /* FCS */, txrx);
q931_dump(pri, h->h.tei, (q931_h *)(h->i.data), len - 4 - 2 /* FCS */, txrx);
}
fflush(stdout);
fflush(stderr);

272
q931.c
View File

@ -3396,7 +3396,7 @@ static inline int q931_cr(q931_h *h)
cr = h->crv[0];
if (cr & 0x80) {
cr &= ~0x80;
cr |= 0x8000;
cr |= Q931_CALL_REFERENCE_FLAG;
}
break;
case 0:
@ -3502,10 +3502,63 @@ void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr)
}
}
static q931_call *q931_getcall(struct pri *ctrl, int cr)
/*!
* \internal
* \brief Create a new call record.
*
* \param ctrl D channel controller.
* \param cr Call Reference identifier.
*
* \retval record on success.
* \retval NULL on error.
*/
static struct q931_call *q931_create_call_record(struct pri *ctrl, int cr)
{
q931_call *cur;
q931_call *prev;
struct q931_call *call;
struct q931_call *prev;
struct pri *master;
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, "-- Making new call for cref %d\n", cr);
}
call = calloc(1, sizeof(*call));
if (!call) {
return NULL;
}
/* Initialize call structure. */
q931_init_call_record(ctrl, call, cr);
/* Find the master - He has the call pool */
master = PRI_MASTER(ctrl);
/* Append to the list end */
if (*master->callpool) {
/* Find the list end. */
for (prev = *master->callpool; prev->next; prev = prev->next) {
}
prev->next = call;
} else {
/* List was empty. */
*master->callpool = call;
}
return call;
}
/*!
* \brief Find a call in the active call pool.
*
* \param ctrl D channel controller.
* \param cr Call Reference identifier.
*
* \retval call if found.
* \retval NULL if not found.
*/
struct q931_call *q931_find_call(struct pri *ctrl, int cr)
{
struct q931_call *cur;
struct pri *master;
if (cr == Q931_DUMMY_CALL_REFERENCE) {
@ -3515,9 +3568,22 @@ static q931_call *q931_getcall(struct pri *ctrl, int cr)
/* Find the master - He has the call pool */
master = PRI_MASTER(ctrl);
cur = *master->callpool;
prev = NULL;
while (cur) {
if (BRI_NT_PTMP(ctrl) && !(cr & Q931_CALL_REFERENCE_FLAG)) {
if (ctrl->tei == Q921_TEI_GROUP) {
/* Broadcast TEI. This is bad. We are using the wrong ctrl structure. */
pri_error(ctrl, "Looking for cref %d when using broadcast TEI.\n", cr);
return NULL;
}
/* We are looking for a call reference value that the other side allocated. */
for (cur = *master->callpool; cur; cur = cur->next) {
if (cur->cr == cr && cur->pri == ctrl) {
/* Found existing call. The call reference and TEI matched. */
break;
}
}
} else {
for (cur = *master->callpool; cur; cur = cur->next) {
if (cur->cr == cr) {
/* Found existing call. */
switch (ctrl->switchtype) {
@ -3533,57 +3599,67 @@ static q931_call *q931_getcall(struct pri *ctrl, int cr)
}
break;
}
return cur;
break;
}
prev = cur;
cur = cur->next;
}
/* No call exists, make a new one */
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, "-- Making new call for cr %d\n", cr);
}
cur = calloc(1, sizeof(*cur));
if (!cur) {
return NULL;
}
/* Initialize call structure. */
q931_init_call_record(ctrl, cur, cr);
/* Append to end of list */
if (prev) {
prev->next = cur;
} else {
*master->callpool = cur;
}
return cur;
}
q931_call *q931_new_call(struct pri *ctrl)
static struct q931_call *q931_getcall(struct pri *ctrl, int cr)
{
q931_call *cur;
struct q931_call *cur;
cur = q931_find_call(ctrl, cr);
if (cur) {
return cur;
}
/* No call record exists, make a new one */
return q931_create_call_record(ctrl, cr);
}
struct q931_call *q931_new_call(struct pri *ctrl)
{
struct q931_call *cur;
struct pri *master;
int first_cref;
int cref;
/* Find the master - He has the call pool */
master = PRI_MASTER(ctrl);
/* Find a new call reference value. */
first_cref = master->cref;
do {
cur = *ctrl->callpool;
ctrl->cref++;
if (!ctrl->bri) {
if (ctrl->cref > 32767)
ctrl->cref = 1;
} else {
if (ctrl->cref > 127)
ctrl->cref = 1;
}
while(cur) {
if (cur->cr == (0x8000 | ctrl->cref))
break;
cur = cur->next;
}
} while(cur);
cref = Q931_CALL_REFERENCE_FLAG | master->cref;
return q931_getcall(ctrl, ctrl->cref | 0x8000);
/* Next call reference. */
++master->cref;
if (!master->bri) {
if (master->cref > 32767) {
master->cref = 1;
}
} else {
if (master->cref > 127) {
master->cref = 1;
}
}
/* Is the call reference value in use? */
for (cur = *master->callpool; cur; cur = cur->next) {
if (cur->cr == cref) {
/* Yes it is in use. */
if (first_cref == master->cref) {
/* All call reference values are in use! */
return NULL;
}
break;
}
}
} while (cur);
return q931_create_call_record(ctrl, cref);
}
static void stop_t303(struct q931_call *call);
@ -3797,7 +3873,7 @@ static char *disc2str(int disc)
return code2str(disc, discs, sizeof(discs) / sizeof(discs[0]));
}
void q931_dump(struct pri *ctrl, q931_h *h, int len, int txrx)
void q931_dump(struct pri *ctrl, int tei, q931_h *h, int len, int txrx)
{
q931_mh *mh;
char c;
@ -3809,11 +3885,12 @@ void q931_dump(struct pri *ctrl, q931_h *h, int len, int txrx)
c = txrx ? '>' : '<';
pri_message(ctrl, "%c Protocol Discriminator: %s (%d) len=%d\n", c, disc2str(h->pd), h->pd, len);
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 == Q931_DUMMY_CALL_REFERENCE)
pri_message(ctrl, "%c TEI=%d Call Ref: len=%2d (reference %d/0x%X) (%s)\n",
c, tei, h->crlen, cref & ~Q931_CALL_REFERENCE_FLAG,
cref & ~Q931_CALL_REFERENCE_FLAG, (cref == Q931_DUMMY_CALL_REFERENCE)
? "Dummy"
: (cref & 0x8000) ? "Terminator" : "Originator");
: (cref & Q931_CALL_REFERENCE_FLAG)
? "Sent to originator" : "Sent from originator");
/* Message header begins at the end of the call reference number */
mh = (q931_mh *)(h->contents + h->crlen);
@ -3885,19 +3962,20 @@ static void init_header(struct pri *ctrl, q931_call *call, unsigned char *buf, q
} else if (!ctrl->bri) {
/* Two bytes of Call Reference. */
h->crlen = 2;
/* Invert the top bit to make it from our sense */
crv = (unsigned) call->cr;
h->crv[0] = ((crv >> 8) ^ 0x80) & 0xff;
h->crv[1] = crv & 0xff;
if (ctrl->subchannel && !ctrl->bri) {
/* On GR-303, top bit is always 0 */
h->crv[0] &= 0x7f;
if (ctrl->subchannel) {
/* On GR-303, Q931_CALL_REFERENCE_FLAG is always 0 */
crv = ((unsigned) call->cr) & ~Q931_CALL_REFERENCE_FLAG;
} else {
/* Invert the Q931_CALL_REFERENCE_FLAG to make it from our sense */
crv = ((unsigned) call->cr) ^ Q931_CALL_REFERENCE_FLAG;
}
h->crv[0] = (crv >> 8) & 0xff;
h->crv[1] = crv & 0xff;
} else {
h->crlen = 1;
/* Invert the top bit to make it from our sense */
crv = (unsigned) call->cr;
h->crv[0] = (((crv >> 8) ^ 0x80) & 0x80) | (crv & 0x7f);
/* Invert the Q931_CALL_REFERENCE_FLAG to make it from our sense */
crv = ((unsigned) call->cr) ^ Q931_CALL_REFERENCE_FLAG;
h->crv[0] = ((crv >> 8) & 0x80) | (crv & 0x7f);
}
*hb = h;
@ -3920,7 +3998,7 @@ static int q931_xmit(struct pri *ctrl, int tei, q931_h *h, int len, int cr, int
message body after the transmit puts the sections of the message in the
right order in the log */
if (ctrl->debug & PRI_DEBUG_Q931_DUMP)
q931_dump(ctrl, h, len, 1);
q931_dump(ctrl, tei, h, len, 1);
#ifdef LIBPRI_COUNTERS
ctrl->q931_txcount++;
#endif
@ -4048,7 +4126,7 @@ int maintenance_service(struct pri *ctrl, int span, int channel, int changestatu
int pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1;
int mt = ATT_SERVICE;
c = q931_getcall(ctrl, 0 | 0x8000);
c = q931_getcall(ctrl, 0 | Q931_CALL_REFERENCE_FLAG);
if (!c) {
return -1;
}
@ -4072,30 +4150,12 @@ int maintenance_service(struct pri *ctrl, int span, int channel, int changestatu
static int status_ies[] = { Q931_CAUSE, Q931_IE_CALL_STATE, -1 };
static int q931_status(struct pri *ctrl, q931_call *c, int cause)
static int q931_status(struct pri *ctrl, q931_call *call, int cause)
{
q931_call *cur = NULL;
if (!cause)
cause = PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY;
if (c->cr > -1)
cur = *ctrl->callpool;
while(cur) {
if (cur->cr == c->cr) {
cur->cause=cause;
cur->causecode = CODE_CCITT;
cur->causeloc = LOC_USER;
break;
}
cur = cur->next;
}
if (!cur) {
pri_message(ctrl, "YYY Here we get reset YYY\n");
/* something went wrong, respond with "no such call" */
c->ourcallstate = Q931_CALL_STATE_NULL;
c->peercallstate = Q931_CALL_STATE_NULL;
cur=c;
}
return send_message(ctrl, cur, Q931_STATUS, status_ies);
call->cause = cause;
call->causecode = CODE_CCITT;
call->causeloc = LOC_USER;
return send_message(ctrl, call, Q931_STATUS, status_ies);
}
static int information_ies[] = { Q931_CALLED_PARTY_NUMBER, -1 };
@ -4525,7 +4585,7 @@ int q931_restart(struct pri *ctrl, int channel)
{
struct q931_call *c;
c = q931_getcall(ctrl, 0 | 0x8000);
c = q931_getcall(ctrl, 0 | Q931_CALL_REFERENCE_FLAG);
if (!c)
return -1;
if (!channel)
@ -5772,7 +5832,7 @@ static struct q931_call *q931_get_subcall(struct pri *ctrl, struct q931_call *ma
int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
{
q931_mh *mh;
q931_call *c;
struct q931_call *c;
q931_ie *ie;
unsigned int x;
int y;
@ -5786,7 +5846,7 @@ int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
memset(last_ie, 0, sizeof(last_ie));
if (ctrl->debug & PRI_DEBUG_Q931_DUMP)
q931_dump(ctrl, h, len, 0);
q931_dump(ctrl, tei, h, len, 0);
#ifdef LIBPRI_COUNTERS
ctrl->q931_rxcount++;
#endif
@ -7010,7 +7070,7 @@ static int post_handle_q931_message(struct pri *ctrl, struct q931_mh *mh, struct
if (c->newcall) {
q931_release_complete(ctrl, c, PRI_CAUSE_INVALID_CALL_REFERENCE);
} else
q931_status(ctrl,c, 0);
q931_status(ctrl,c, PRI_CAUSE_RESPONSE_TO_STATUS_ENQUIRY);
break;
case Q931_SETUP_ACKNOWLEDGE:
stop_t303(c);
@ -7432,7 +7492,8 @@ static void pri_dl_down_cancelcall(void *data)
/* Receive an indication from Layer 2 */
void q931_dl_indication(struct pri *ctrl, int event)
{
q931_call *cur = NULL;
struct q931_call *cur;
struct q931_call *winner;
/* Just return if T309 is not enabled. */
if (!ctrl || ctrl->timers[PRI_TIMER_T309] < 0)
@ -7443,8 +7504,7 @@ void q931_dl_indication(struct pri *ctrl, int event)
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, DBGHEAD "link is DOWN\n", DBGINFO);
}
cur = *ctrl->callpool;
while(cur) {
for (cur = *ctrl->callpool; cur; cur = cur->next) {
if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE) {
/* For a call in Active state, activate T309 only if there is no timer already running. */
if (!cur->retranstimer) {
@ -7466,15 +7526,13 @@ void q931_dl_indication(struct pri *ctrl, int event)
pri_schedule_del(ctrl, cur->retranstimer);
cur->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall, cur);
}
cur = cur->next;
}
break;
case PRI_EVENT_DCHAN_UP:
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl, DBGHEAD "link is UP\n", DBGINFO);
}
cur = *ctrl->callpool;
while(cur) {
for (cur = *ctrl->callpool; cur; cur = cur->next) {
if (cur->ourcallstate == Q931_CALL_STATE_ACTIVE && cur->retranstimer) {
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
pri_message(ctrl,
@ -7483,16 +7541,24 @@ void q931_dl_indication(struct pri *ctrl, int event)
}
pri_schedule_del(ctrl, cur->retranstimer);
cur->retranstimer = 0;
q931_status(ctrl, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
winner = q931_find_winning_call(cur);
if (winner) {
q931_status(ctrl, winner, PRI_CAUSE_NORMAL_UNSPECIFIED);
}
} else if (cur->ourcallstate != Q931_CALL_STATE_NULL &&
cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_REQUEST &&
cur->ourcallstate != Q931_CALL_STATE_DISCONNECT_INDICATION &&
cur->ourcallstate != Q931_CALL_STATE_RELEASE_REQUEST) {
/* The STATUS message sent here is not required by Q.931, but it may help anyway. */
q931_status(ctrl, cur, PRI_CAUSE_NORMAL_UNSPECIFIED);
/*
* The STATUS message sent here is not required by Q.931,
* but it may help anyway.
* This looks like a new call started while the link was down.
*/
winner = q931_find_winning_call(cur);
if (winner) {
q931_status(ctrl, winner, PRI_CAUSE_NORMAL_UNSPECIFIED);
}
}
cur = cur->next;
}
break;
default: