Restructure the Q.931 call record to layer 2 link association.
This is in anticipation of extracting a layer 2 link structure out of struct pri. Also completes fixing timer value access for the rest of libpri. The timer access must always be on the D channel control structure (Master). May have fixed some events from timeouts not being passed to the upper layer. The timeout events must always be on the D channel control structure (Master). git-svn-id: https://origsvn.digium.com/svn/libpri/branches/1.4@2070 2fbb986a-6c06-0410-b554-c9c1f0a7f128
This commit is contained in:
parent
cd588eccce
commit
53c142990f
37
pri.c
37
pri.c
@ -293,6 +293,7 @@ void __pri_free_tei(struct pri * p)
|
||||
call = p->dummy_call;
|
||||
if (call) {
|
||||
pri_schedule_del(call->pri, call->retranstimer);
|
||||
call->retranstimer = 0;
|
||||
pri_call_apdu_queue_cleanup(call);
|
||||
}
|
||||
free(p->msg_line);
|
||||
@ -303,6 +304,7 @@ void __pri_free_tei(struct pri * 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)
|
||||
{
|
||||
int create_dummy_call;
|
||||
struct d_ctrl_dummy *dummy_ctrl;
|
||||
struct pri *p;
|
||||
|
||||
@ -311,19 +313,32 @@ struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master,
|
||||
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;
|
||||
create_dummy_call = 0;
|
||||
break;
|
||||
default:
|
||||
if (bri && node == PRI_CPE && tei == Q921_TEI_GROUP) {
|
||||
/*
|
||||
* BRI TE PTMP will not use its own group dummy call record. It
|
||||
* will use the specific TEI dummy call instead.
|
||||
*/
|
||||
create_dummy_call = 0;
|
||||
} else {
|
||||
create_dummy_call = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (create_dummy_call) {
|
||||
dummy_ctrl = calloc(1, sizeof(*dummy_ctrl));
|
||||
if (!dummy_ctrl) {
|
||||
return NULL;
|
||||
}
|
||||
p = &dummy_ctrl->ctrl;
|
||||
break;
|
||||
} else {
|
||||
p = calloc(1, sizeof(*p));
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
dummy_ctrl = NULL;
|
||||
}
|
||||
if (!master) {
|
||||
/* This is the master record. */
|
||||
@ -402,12 +417,20 @@ struct pri *__pri_new_tei(int fd, int node, int switchtype, struct pri *master,
|
||||
break;
|
||||
}
|
||||
|
||||
if (p->tei == Q921_TEI_GROUP && p->sapi == Q921_SAPI_LAYER2_MANAGEMENT && p->localtype == PRI_CPE) {
|
||||
if (p->tei == Q921_TEI_GROUP && p->sapi == Q921_SAPI_LAYER2_MANAGEMENT
|
||||
&& p->localtype == PRI_CPE) {
|
||||
p->subchannel = __pri_new_tei(-1, p->localtype, p->switchtype, p, NULL, NULL, NULL, Q921_TEI_PRI, 1);
|
||||
if (!p->subchannel) {
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Make the group link use the just created specific TEI link
|
||||
* dummy call instead. It makes no sense for TE PTMP interfaces
|
||||
* to broadcast messages on the dummy call or to broadcast any
|
||||
* messages for that matter.
|
||||
*/
|
||||
p->dummy_call = p->subchannel->dummy_call;
|
||||
} else
|
||||
q921_start(p);
|
||||
|
||||
|
@ -2556,8 +2556,9 @@ static int etsi_ect_link_id_rsp(enum APDU_CALLBACK_REASON reason, struct pri *ct
|
||||
|
||||
switch (reason) {
|
||||
case APDU_CALLBACK_REASON_MSG_RESULT:
|
||||
call_2 = q931_find_call(ctrl, apdu->response.user.value);
|
||||
if (!call_2) {
|
||||
call_2 = apdu->response.user.ptr;
|
||||
if (!q931_is_call_valid(ctrl, call_2)) {
|
||||
/* Call is no longer present. */
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2636,7 +2637,7 @@ int etsi_initiate_transfer(struct pri *ctrl, q931_call *call_1, q931_call *call_
|
||||
response.invoke_id = ctrl->last_invoke;
|
||||
response.timeout_time = ctrl->timers[PRI_TIMER_T_RESPONSE];
|
||||
response.callback = etsi_ect_link_id_rsp;
|
||||
response.user.value = call_2->cr;
|
||||
response.user.ptr = call_2;
|
||||
|
||||
/* Remember that if we queue a facility IE for a facility message we
|
||||
* have to explicitly send the facility message ourselves */
|
||||
|
@ -448,9 +448,10 @@ struct decoded_bc {
|
||||
|
||||
/* q931_call datastructure */
|
||||
struct q931_call {
|
||||
struct pri *pri; /* PRI */
|
||||
struct pri *pri; /* D channel controller (master) */
|
||||
struct pri *link; /* Q.921 link associated with this call. */
|
||||
struct q931_call *next;
|
||||
int cr; /* Call Reference */
|
||||
q931_call *next;
|
||||
/* Slotmap specified (bitmap of channels 31/24-1) (Channel Identifier IE) (-1 means not specified) */
|
||||
int slotmap;
|
||||
/* An explicit channel (Channel Identifier IE) (-1 means not specified) */
|
||||
@ -914,7 +915,7 @@ void libpri_copy_string(char *dst, const char *src, size_t size);
|
||||
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_init_call_record(struct pri *link, struct q931_call *call, int cr);
|
||||
|
||||
void pri_sr_init(struct pri_sr *req);
|
||||
|
||||
|
@ -195,7 +195,7 @@ void q921_start(struct pri *link);
|
||||
|
||||
extern pri_event *q921_receive(struct pri *pri, q921_h *h, int len);
|
||||
|
||||
extern int q921_transmit_iframe(struct pri *pri, int tei, void *buf, int len, int cr);
|
||||
int q921_transmit_iframe(struct pri *link, void *buf, int len, int cr);
|
||||
|
||||
int q921_transmit_uiframe(struct pri *link, void *buf, int len);
|
||||
|
||||
|
@ -450,13 +450,11 @@ enum Q931_RANKED_CALL_STATE {
|
||||
|
||||
extern int maintenance_service(struct pri *pri, int span, int channel, int changestatus);
|
||||
|
||||
extern int maintenance_service_ack(struct pri *pri, q931_call *call);
|
||||
|
||||
|
||||
/* Q.SIG specific */
|
||||
#define QSIG_IE_TRANSIT_COUNT 0x31
|
||||
|
||||
extern int q931_receive(struct pri *pri, int tei, q931_h *h, int len);
|
||||
int q931_receive(struct pri *link, q931_h *h, int len);
|
||||
|
||||
extern int q931_alerting(struct pri *pri, q931_call *call, int channel, int info);
|
||||
|
||||
@ -491,8 +489,7 @@ 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);
|
||||
|
||||
struct q931_call *q931_find_call(struct pri *ctrl, int cr);
|
||||
struct q931_call *q931_new_call(struct pri *pri);
|
||||
struct q931_call *q931_new_call(struct pri *ctrl);
|
||||
|
||||
extern int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req);
|
||||
|
||||
|
30
q921.c
30
q921.c
@ -798,28 +798,19 @@ static struct pri *pri_find_tei(struct pri *ctrl, int sapi, int tei)
|
||||
}
|
||||
|
||||
/* This is the equivalent of a DL-DATA request, as well as the I-frame queued up outcome */
|
||||
int q921_transmit_iframe(struct pri *link, int tei, void *buf, int len, int cr)
|
||||
int q921_transmit_iframe(struct pri *link, void *buf, int len, int cr)
|
||||
{
|
||||
q921_frame *f, *prev=NULL;
|
||||
struct pri *ctrl;
|
||||
|
||||
ctrl = PRI_MASTER(link);
|
||||
|
||||
if (BRI_NT_PTMP(ctrl)) {
|
||||
if (tei == Q921_TEI_GROUP) {
|
||||
pri_error(ctrl, "Huh?! For NT-PTMP, we shouldn't be sending I-frames out the group TEI\n");
|
||||
if (PTMP_MODE(ctrl)) {
|
||||
if (link->tei == Q921_TEI_GROUP) {
|
||||
pri_error(ctrl, "Huh?! For PTMP, we shouldn't be sending I-frames out the group TEI\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
link = pri_find_tei(ctrl, Q921_SAPI_CALL_CTRL, tei);
|
||||
if (!link) {
|
||||
pri_error(ctrl, "Huh?! Unable to locate PRI associated with TEI %d. Did we have to ditch it due to error conditions?\n", tei);
|
||||
return 0;
|
||||
}
|
||||
} else if (BRI_TE_PTMP(ctrl)) {
|
||||
/* We don't care what the tei is, since we only support one sub and one TEI */
|
||||
link = ctrl->subchannel;
|
||||
|
||||
if (BRI_TE_PTMP(ctrl)) {
|
||||
switch (link->q921_state) {
|
||||
case Q921_TEI_UNASSIGNED:
|
||||
q921_setstate(link, Q921_ESTABLISH_AWAITING_TEI);
|
||||
@ -831,8 +822,9 @@ int q921_transmit_iframe(struct pri *link, int tei, void *buf, int len, int cr)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Should just be PTP modes, which shouldn't have subs */
|
||||
/* PTP modes, which shouldn't have subs */
|
||||
}
|
||||
|
||||
/* Figure B.7/Q.921 Page 70 */
|
||||
@ -2269,9 +2261,9 @@ static pri_event *q921_iframe_rx(struct pri *link, q921_h *h, int len)
|
||||
}
|
||||
if (delay_q931_receive) {
|
||||
/* Q.921 has finished processing the frame so we can give it to Q.931 now. */
|
||||
res = q931_receive(link, link->tei, (q931_h *) h->i.data, len - 4);
|
||||
res = q931_receive(link, (q931_h *) h->i.data, len - 4);
|
||||
if (res != -1 && (res & Q931_RES_HAVEEVENT)) {
|
||||
eres = &link->ev;
|
||||
eres = &ctrl->ev;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -2519,9 +2511,9 @@ static pri_event *__q921_receive_qualified(struct pri *link, q921_h *h, int len)
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_DUMP) {
|
||||
q931_dump(ctrl, h->h.tei, (q931_h *) h->u.data, len - 3, 0);
|
||||
}
|
||||
res = q931_receive(link, link->tei, (q931_h *) h->u.data, len - 3);
|
||||
res = q931_receive(link, (q931_h *) h->u.data, len - 3);
|
||||
if (res != -1 && (res & Q931_RES_HAVEEVENT)) {
|
||||
ev = &link->ev;
|
||||
ev = &ctrl->ev;
|
||||
}
|
||||
break;
|
||||
case 0x08:
|
||||
|
274
q931.c
274
q931.c
@ -3778,7 +3778,7 @@ static inline void q931_dumpie(struct pri *ctrl, int codeset, q931_ie *ie, char
|
||||
/*!
|
||||
* \brief Initialize the call record.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param link Q.921 link associated with the call.
|
||||
* \param call Q.931 call leg.
|
||||
* \param cr Call Reference identifier.
|
||||
*
|
||||
@ -3786,8 +3786,10 @@ static inline void q931_dumpie(struct pri *ctrl, int codeset, q931_ie *ie, char
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr)
|
||||
void q931_init_call_record(struct pri *link, struct q931_call *call, int cr)
|
||||
{
|
||||
struct pri *ctrl;
|
||||
|
||||
call->cr = cr;
|
||||
call->slotmap = -1;
|
||||
call->channelno = -1;
|
||||
@ -3822,15 +3824,17 @@ void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr)
|
||||
q931_party_number_init(&call->ani);
|
||||
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 {
|
||||
/* The call is now attached to whoever called us */
|
||||
ctrl = PRI_MASTER(link);
|
||||
call->pri = ctrl;
|
||||
if (cr == Q931_DUMMY_CALL_REFERENCE) {
|
||||
/* Dummy calls are always for the given link. */
|
||||
call->link = link;
|
||||
} else if (BRI_TE_PTMP(ctrl)) {
|
||||
/* Always uses the specific TEI link. */
|
||||
call->link = ctrl->subchannel;
|
||||
} else {
|
||||
call->link = link;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3838,17 +3842,20 @@ void q931_init_call_record(struct pri *ctrl, struct q931_call *call, int cr)
|
||||
* \internal
|
||||
* \brief Create a new call record.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param link Q.921 link associated with the call.
|
||||
* \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)
|
||||
static struct q931_call *q931_create_call_record(struct pri *link, int cr)
|
||||
{
|
||||
struct q931_call *call;
|
||||
struct q931_call *prev;
|
||||
struct pri *master;
|
||||
struct pri *ctrl;
|
||||
|
||||
/* Find the master - He has the call pool */
|
||||
ctrl = PRI_MASTER(link);
|
||||
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "-- Making new call for cref %d\n", cr);
|
||||
@ -3860,62 +3867,60 @@ static struct q931_call *q931_create_call_record(struct pri *ctrl, int cr)
|
||||
}
|
||||
|
||||
/* Initialize call structure. */
|
||||
q931_init_call_record(ctrl, call, cr);
|
||||
|
||||
/* Find the master - He has the call pool */
|
||||
master = PRI_MASTER(ctrl);
|
||||
q931_init_call_record(link, call, cr);
|
||||
|
||||
/* Append to the list end */
|
||||
if (*master->callpool) {
|
||||
if (*ctrl->callpool) {
|
||||
/* Find the list end. */
|
||||
for (prev = *master->callpool; prev->next; prev = prev->next) {
|
||||
for (prev = *ctrl->callpool; prev->next; prev = prev->next) {
|
||||
}
|
||||
prev->next = call;
|
||||
} else {
|
||||
/* List was empty. */
|
||||
*master->callpool = call;
|
||||
*ctrl->callpool = call;
|
||||
}
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Find a call in the active call pool.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param link Q.921 link associated with the call.
|
||||
* \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)
|
||||
static struct q931_call *q931_find_call(struct pri *link, int cr)
|
||||
{
|
||||
struct q931_call *cur;
|
||||
struct pri *master;
|
||||
struct pri *ctrl;
|
||||
|
||||
if (cr == Q931_DUMMY_CALL_REFERENCE) {
|
||||
return ctrl->dummy_call;
|
||||
return link->dummy_call;
|
||||
}
|
||||
|
||||
/* Find the master - He has the call pool */
|
||||
master = PRI_MASTER(ctrl);
|
||||
ctrl = PRI_MASTER(link);
|
||||
|
||||
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. */
|
||||
if (link->tei == Q921_TEI_GROUP) {
|
||||
/* Broadcast TEI. This is bad. We are using the wrong link 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. */
|
||||
for (cur = *ctrl->callpool; cur; cur = cur->next) {
|
||||
if (cur->cr == cr && cur->link == link) {
|
||||
/* Found existing call. The call reference and link matched. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (cur = *master->callpool; cur; cur = cur->next) {
|
||||
for (cur = *ctrl->callpool; cur; cur = cur->next) {
|
||||
if (cur->cr == cr) {
|
||||
/* Found existing call. */
|
||||
switch (ctrl->switchtype) {
|
||||
@ -3926,8 +3931,9 @@ struct q931_call *q931_find_call(struct pri *ctrl, int cr)
|
||||
break;
|
||||
default:
|
||||
if (!ctrl->bri) {
|
||||
/* PRI is set to whoever called us */
|
||||
/* The call is now attached to whoever called us */
|
||||
cur->pri = ctrl;
|
||||
cur->link = link;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3938,51 +3944,72 @@ struct q931_call *q931_find_call(struct pri *ctrl, int cr)
|
||||
return cur;
|
||||
}
|
||||
|
||||
static struct q931_call *q931_getcall(struct pri *ctrl, int cr)
|
||||
static struct q931_call *q931_getcall(struct pri *link, int cr)
|
||||
{
|
||||
struct q931_call *cur;
|
||||
struct pri *ctrl;
|
||||
|
||||
cur = q931_find_call(ctrl, cr);
|
||||
cur = q931_find_call(link, cr);
|
||||
if (cur) {
|
||||
return cur;
|
||||
}
|
||||
|
||||
/* No call record exists, make a new one */
|
||||
return q931_create_call_record(ctrl, cr);
|
||||
if (cr == Q931_DUMMY_CALL_REFERENCE) {
|
||||
/* Do not create new dummy call records. */
|
||||
return NULL;
|
||||
}
|
||||
ctrl = PRI_MASTER(link);
|
||||
if (link->tei == Q921_TEI_GROUP
|
||||
&& BRI_NT_PTMP(ctrl)) {
|
||||
/* Do not create NT PTMP broadcast call records here. */
|
||||
pri_error(ctrl,
|
||||
"NT PTMP cannot create call record for cref %d on the broadcast TEI.\n", cr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* No call record exists, make a new one */
|
||||
return q931_create_call_record(link, cr);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Create a new call record for an outgoing call.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
*
|
||||
* \retval call on success.
|
||||
* \retval NULL on error.
|
||||
*/
|
||||
struct q931_call *q931_new_call(struct pri *ctrl)
|
||||
{
|
||||
struct q931_call *cur;
|
||||
struct pri *master;
|
||||
struct pri *link;
|
||||
int first_cref;
|
||||
int cref;
|
||||
|
||||
/* Find the master - He has the call pool */
|
||||
master = PRI_MASTER(ctrl);
|
||||
ctrl = PRI_MASTER(ctrl);
|
||||
|
||||
/* Find a new call reference value. */
|
||||
first_cref = master->cref;
|
||||
first_cref = ctrl->cref;
|
||||
do {
|
||||
cref = Q931_CALL_REFERENCE_FLAG | master->cref;
|
||||
cref = Q931_CALL_REFERENCE_FLAG | ctrl->cref;
|
||||
|
||||
/* Next call reference. */
|
||||
++master->cref;
|
||||
if (!master->bri) {
|
||||
if (master->cref > 32767) {
|
||||
master->cref = 1;
|
||||
++ctrl->cref;
|
||||
if (!ctrl->bri) {
|
||||
if (ctrl->cref > 32767) {
|
||||
ctrl->cref = 1;
|
||||
}
|
||||
} else {
|
||||
if (master->cref > 127) {
|
||||
master->cref = 1;
|
||||
if (ctrl->cref > 127) {
|
||||
ctrl->cref = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Is the call reference value in use? */
|
||||
for (cur = *master->callpool; cur; cur = cur->next) {
|
||||
for (cur = *ctrl->callpool; cur; cur = cur->next) {
|
||||
if (cur->cr == cref) {
|
||||
/* Yes it is in use. */
|
||||
if (first_cref == master->cref) {
|
||||
if (first_cref == ctrl->cref) {
|
||||
/* All call reference values are in use! */
|
||||
return NULL;
|
||||
}
|
||||
@ -3991,7 +4018,8 @@ struct q931_call *q931_new_call(struct pri *ctrl)
|
||||
}
|
||||
} while (cur);
|
||||
|
||||
return q931_create_call_record(ctrl, cref);
|
||||
link = ctrl;
|
||||
return q931_create_call_record(link, cref);
|
||||
}
|
||||
|
||||
static void stop_t303(struct q931_call *call);
|
||||
@ -4475,20 +4503,27 @@ static void init_header(struct pri *ctrl, q931_call *call, unsigned char *buf, q
|
||||
*mhb = mh;
|
||||
}
|
||||
|
||||
static int q931_xmit(struct pri *ctrl, int tei, q931_h *h, int len, int cr, int uiframe)
|
||||
static void q931_xmit(struct pri *link, q931_h *h, int len, int cr, int uiframe)
|
||||
{
|
||||
struct pri *ctrl;
|
||||
|
||||
ctrl = PRI_MASTER(link);
|
||||
#ifdef LIBPRI_COUNTERS
|
||||
ctrl->q931_txcount++;
|
||||
#endif
|
||||
if (uiframe) {
|
||||
q921_transmit_uiframe(ctrl, h, len);
|
||||
if (link->tei != Q921_TEI_GROUP) {
|
||||
pri_error(ctrl, "Huh?! Attempting to send UI-frame on TEI %d\n", link->tei);
|
||||
return;
|
||||
}
|
||||
q921_transmit_uiframe(link, h, len);
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_DUMP) {
|
||||
/*
|
||||
* The transmit operation might dump the Q.921 header, so logging
|
||||
* the Q.931 message body after the transmit puts the sections of
|
||||
* the message in the right order in the log,
|
||||
*/
|
||||
q931_dump(ctrl, tei, h, len, 1);
|
||||
q931_dump(ctrl, link->tei, h, len, 1);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -4499,11 +4534,10 @@ static int q931_xmit(struct pri *ctrl, int tei, q931_h *h, int len, int cr, int
|
||||
* Q.931 message as appropriate at that time.
|
||||
*/
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_DUMP) {
|
||||
q931_to_q921_passing_dump(ctrl, tei, h, len);
|
||||
q931_to_q921_passing_dump(ctrl, link->tei, h, len);
|
||||
}
|
||||
q921_transmit_iframe(ctrl, tei, h, len, cr);
|
||||
q921_transmit_iframe(link, h, len, cr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -4532,7 +4566,6 @@ static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[
|
||||
int x;
|
||||
int codeset;
|
||||
int uiframe;
|
||||
int tei;
|
||||
|
||||
if (call->outboundbroadcast && call->master_call == call && msgtype != Q931_SETUP) {
|
||||
pri_error(ctrl,
|
||||
@ -4541,6 +4574,13 @@ static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!call->link) {
|
||||
pri_error(ctrl,
|
||||
"Call w/ cref:%d is not associated with a link. TEI removed due to error conditions?\n",
|
||||
call->cr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
len = sizeof(buf);
|
||||
init_header(ctrl, call, buf, &h, &mh, &len, (msgtype >> 8));
|
||||
@ -4561,7 +4601,6 @@ static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[
|
||||
/* Invert the logic */
|
||||
len = sizeof(buf) - len;
|
||||
|
||||
tei = call->pri->tei;
|
||||
uiframe = 0;
|
||||
if (BRI_NT_PTMP(ctrl)) {
|
||||
/* NT PTMP is the only mode that can broadcast Q.931 messages. */
|
||||
@ -4578,7 +4617,7 @@ static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[
|
||||
uiframe = 1;
|
||||
break;
|
||||
case Q931_FACILITY:
|
||||
if (tei == Q921_TEI_GROUP) {
|
||||
if (call->link->tei == Q921_TEI_GROUP) {
|
||||
/* Broadcast TEI. */
|
||||
if (q931_is_dummy_call(call)) {
|
||||
/*
|
||||
@ -4600,24 +4639,18 @@ static int send_message(struct pri *ctrl, q931_call *call, int msgtype, int ies[
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
/* This message is only interesting for NT PTMP mode. */
|
||||
pri_message(ctrl,
|
||||
"Sending message for call %p on call->pri: %p with TEI/SAPI %d/%d\n",
|
||||
call, call->pri, call->pri->tei, call->pri->sapi);
|
||||
"Sending message for call %p on call->link: %p with TEI/SAPI %d/%d\n",
|
||||
call, call->link, call->link->tei, call->link->sapi);
|
||||
}
|
||||
} else if (call->pri->subchannel && BRI_TE_PTMP(ctrl)) {
|
||||
/*
|
||||
* Get the best available TEI value for the debug dump display.
|
||||
* We may not actually have a TEI assigned at the moment.
|
||||
*/
|
||||
tei = call->pri->subchannel->tei;
|
||||
}
|
||||
q931_xmit(call->pri, tei, h, len, 1, uiframe);
|
||||
q931_xmit(call->link, h, len, 1, uiframe);
|
||||
call->acked = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int maintenance_service_ies[] = { Q931_IE_CHANGE_STATUS, Q931_CHANNEL_IDENT, -1 };
|
||||
|
||||
int maintenance_service_ack(struct pri *ctrl, q931_call *c)
|
||||
static int maintenance_service_ack(struct pri *ctrl, q931_call *c)
|
||||
{
|
||||
int pd = MAINTENANCE_PROTOCOL_DISCRIMINATOR_1;
|
||||
int mt = ATT_SERVICE_ACKNOWLEDGE;
|
||||
@ -4629,6 +4662,9 @@ int maintenance_service_ack(struct pri *ctrl, q931_call *c)
|
||||
return send_message(ctrl, c, (pd << 8) | mt, maintenance_service_ies);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \note Maintenance service messages only supported in PRI mode.
|
||||
*/
|
||||
int maintenance_service(struct pri *ctrl, int span, int channel, int changestatus)
|
||||
{
|
||||
struct q931_call *c;
|
||||
@ -5131,6 +5167,32 @@ int q931_release(struct pri *ctrl, q931_call *c, int cause)
|
||||
|
||||
static int restart_ies[] = { Q931_CHANNEL_IDENT, Q931_RESTART_INDICATOR, -1 };
|
||||
|
||||
/*!
|
||||
* \brief Send the RESTART message to the peer.
|
||||
*
|
||||
* \param ctrl D channel controller.
|
||||
* \param channel Encoded channel id to use.
|
||||
*
|
||||
* \note
|
||||
* Sending RESTART in NT PTMP mode is not supported at the
|
||||
* present time.
|
||||
*
|
||||
* \note
|
||||
* NT PTMP should broadcast the RESTART if there is a TEI
|
||||
* allocated. Otherwise it should immediately ACK the RESTART
|
||||
* itself to avoid the T316 timeout delay (2 minutes) since
|
||||
* there might not be anything connected. The broadcast could
|
||||
* be handled in a similar manner to the broadcast SETUP.
|
||||
*
|
||||
* \todo Need to implement T316 to protect against missing
|
||||
* RESTART_ACKNOWLEDGE and STATUS messages.
|
||||
*
|
||||
* \todo NT PTMP mode should implement some protection from
|
||||
* receiving a RESTART on channels in use by another TEI.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
int q931_restart(struct pri *ctrl, int channel)
|
||||
{
|
||||
struct q931_call *c;
|
||||
@ -5952,9 +6014,6 @@ static void pri_fake_clearing(void *data)
|
||||
|
||||
static void pri_create_fake_clearing(struct q931_call *c, struct pri *master)
|
||||
{
|
||||
/* Point to the master so the timeout event can come out. */
|
||||
c->pri = master;
|
||||
|
||||
pri_schedule_del(master, c->retranstimer);
|
||||
c->retranstimer = pri_schedule_event(master, 0, pri_fake_clearing, c);
|
||||
}
|
||||
@ -6446,16 +6505,19 @@ static void q931_set_subcall_winner(struct q931_call *subcall)
|
||||
}
|
||||
}
|
||||
|
||||
static struct q931_call *q931_get_subcall(struct pri *ctrl, struct q931_call *master_call)
|
||||
static struct q931_call *q931_get_subcall(struct pri *link, struct q931_call *master_call)
|
||||
{
|
||||
int i;
|
||||
struct q931_call *cur;
|
||||
struct pri *ctrl;
|
||||
int firstfree = -1;
|
||||
|
||||
ctrl = PRI_MASTER(link);
|
||||
|
||||
/* First try to locate our subcall */
|
||||
for (i = 0; i < ARRAY_LEN(master_call->subcalls); ++i) {
|
||||
if (master_call->subcalls[i]) {
|
||||
if (master_call->subcalls[i]->pri == ctrl) {
|
||||
if (master_call->subcalls[i]->link == link) {
|
||||
return master_call->subcalls[i];
|
||||
}
|
||||
} else if (firstfree == -1) {
|
||||
@ -6475,7 +6537,8 @@ static struct q931_call *q931_get_subcall(struct pri *ctrl, struct q931_call *ma
|
||||
return NULL;
|
||||
}
|
||||
*cur = *master_call;
|
||||
cur->pri = ctrl;
|
||||
//cur->pri = ctrl;/* We get this assignment for free. */
|
||||
cur->link = link;
|
||||
cur->next = NULL;
|
||||
cur->apdus = NULL;
|
||||
cur->bridged_call = NULL;
|
||||
@ -6495,16 +6558,17 @@ static struct q931_call *q931_get_subcall(struct pri *ctrl, struct q931_call *ma
|
||||
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "Adding subcall %p for TEI %d to call %p at position %d\n",
|
||||
cur, ctrl->tei, master_call, firstfree);
|
||||
cur, link->tei, master_call, firstfree);
|
||||
}
|
||||
/* Should only get here if the TEI is not found */
|
||||
return cur;
|
||||
}
|
||||
|
||||
int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
|
||||
int q931_receive(struct pri *link, q931_h *h, int len)
|
||||
{
|
||||
q931_mh *mh;
|
||||
struct q931_call *c;
|
||||
struct pri *ctrl;
|
||||
q931_ie *ie;
|
||||
unsigned int x;
|
||||
int y;
|
||||
@ -6518,6 +6582,7 @@ int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
|
||||
int allow_event;
|
||||
int allow_posthandle;
|
||||
|
||||
ctrl = PRI_MASTER(link);
|
||||
memset(last_ie, 0, sizeof(last_ie));
|
||||
#ifdef LIBPRI_COUNTERS
|
||||
ctrl->q931_rxcount++;
|
||||
@ -6537,7 +6602,7 @@ int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
|
||||
KLUDGE this by changing byte 4 from a 0xf (SERVICE)
|
||||
to a 0x7 (SERVICE ACKNOWLEDGE) */
|
||||
h->raw[h->crlen + 2] -= 0x8;
|
||||
q931_xmit(ctrl, ctrl->tei, h, len, 1, 0);
|
||||
q931_xmit(link, h, len, 1, 0);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@ -6552,13 +6617,13 @@ int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
|
||||
}
|
||||
|
||||
cref = q931_cr(h);
|
||||
c = q931_getcall(ctrl, cref);
|
||||
c = q931_getcall(link, cref);
|
||||
if (!c) {
|
||||
pri_error(ctrl, "Unable to locate call %d\n", cref);
|
||||
return -1;
|
||||
}
|
||||
if (c->master_call->outboundbroadcast && ctrl != PRI_MASTER(ctrl)) {
|
||||
c = q931_get_subcall(ctrl, c->master_call);
|
||||
if (c->master_call->outboundbroadcast && link != ctrl) {
|
||||
c = q931_get_subcall(link, c->master_call);
|
||||
if (!c) {
|
||||
pri_error(ctrl, "Unable to locate subcall for %d\n", cref);
|
||||
return -1;
|
||||
@ -6567,10 +6632,8 @@ int q931_receive(struct pri *ctrl, int tei, q931_h *h, int len)
|
||||
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
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);
|
||||
"Received message for call %p on link %p TEI/SAPI %d/%d\n",
|
||||
c, link, link->tei, link->sapi);
|
||||
}
|
||||
|
||||
/* Preliminary handling */
|
||||
@ -8456,10 +8519,6 @@ static void pri_dl_down_timeout(void *data)
|
||||
struct q931_call *c = data;
|
||||
struct pri *ctrl = c->pri;
|
||||
|
||||
/* Point to the master so the timeout event can come out. */
|
||||
ctrl = PRI_MASTER(ctrl);
|
||||
c->pri = ctrl;
|
||||
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
|
||||
pri_message(ctrl, "T309 timed out waiting for data link re-establishment\n");
|
||||
|
||||
@ -8475,10 +8534,6 @@ static void pri_dl_down_cancelcall(void *data)
|
||||
struct q931_call *c = data;
|
||||
struct pri *ctrl = c->pri;
|
||||
|
||||
/* Point to the master so the timeout event can come out. */
|
||||
ctrl = PRI_MASTER(ctrl);
|
||||
c->pri = ctrl;
|
||||
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE)
|
||||
pri_message(ctrl, "Cancel call after data link failure\n");
|
||||
|
||||
@ -8551,11 +8606,6 @@ void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
|
||||
q931_dl_event2str(event), event);
|
||||
}
|
||||
|
||||
if (BRI_TE_PTMP(ctrl)) {
|
||||
/* The link is always the master */
|
||||
link = ctrl;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case Q931_DL_EVENT_TEI_REMOVAL:
|
||||
if (!BRI_NT_PTMP(ctrl)) {
|
||||
@ -8569,15 +8619,11 @@ void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
|
||||
* removed TEI.
|
||||
*/
|
||||
for (cur = *ctrl->callpool; cur; cur = cur->next) {
|
||||
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
|
||||
/* Don't do anything on the global call reference call record. */
|
||||
continue;
|
||||
}
|
||||
if (cur->outboundbroadcast) {
|
||||
/* Does this master call have a subcall on the link that went down? */
|
||||
call = NULL;
|
||||
for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) {
|
||||
if (cur->subcalls[idx] && cur->subcalls[idx]->pri == link) {
|
||||
if (cur->subcalls[idx] && cur->subcalls[idx]->link == link) {
|
||||
/* This subcall is on the link that went down. */
|
||||
call = cur->subcalls[idx];
|
||||
break;
|
||||
@ -8587,13 +8633,23 @@ void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
|
||||
/* No subcall is on the link that went down. */
|
||||
continue;
|
||||
}
|
||||
} else if (cur->pri != link) {
|
||||
} else if (cur->link != link) {
|
||||
/* This call is not on the link that went down. */
|
||||
continue;
|
||||
} else {
|
||||
call = cur;
|
||||
}
|
||||
|
||||
if (!(cur->cr & ~Q931_CALL_REFERENCE_FLAG)) {
|
||||
/* Simply destroy the global call reference call record. */
|
||||
if (ctrl->debug & PRI_DEBUG_Q931_STATE) {
|
||||
pri_message(ctrl, "TEI=%d Destroying global call record\n",
|
||||
link->tei);
|
||||
}
|
||||
q931_destroycall(ctrl, call);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: We are gambling that no T309 timer's have had a chance
|
||||
* to expire. They should not expire since we are either called
|
||||
@ -8605,7 +8661,7 @@ void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
|
||||
call->cr, call->channelno, call->ourcallstate,
|
||||
q931_call_state_str(call->ourcallstate));
|
||||
}
|
||||
call->pri = ctrl;/* Point to a safer place until the call is destroyed. */
|
||||
call->link = NULL;
|
||||
pri_schedule_del(ctrl, call->retranstimer);
|
||||
call->retranstimer = pri_schedule_event(ctrl, 0, pri_dl_down_cancelcall,
|
||||
call);
|
||||
@ -8622,7 +8678,7 @@ void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
|
||||
/* Does this master call have a subcall on the link that went down? */
|
||||
call = NULL;
|
||||
for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) {
|
||||
if (cur->subcalls[idx] && cur->subcalls[idx]->pri == link) {
|
||||
if (cur->subcalls[idx] && cur->subcalls[idx]->link == link) {
|
||||
/* This subcall is on the link that went down. */
|
||||
call = cur->subcalls[idx];
|
||||
break;
|
||||
@ -8632,7 +8688,7 @@ void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
|
||||
/* No subcall is on the link that went down. */
|
||||
continue;
|
||||
}
|
||||
} else if (cur->pri != link) {
|
||||
} else if (cur->link != link) {
|
||||
/* This call is not on the link that went down. */
|
||||
continue;
|
||||
} else {
|
||||
@ -8704,7 +8760,7 @@ void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
|
||||
/* Does this master call have a subcall on the link that came up? */
|
||||
call = NULL;
|
||||
for (idx = 0; idx < ARRAY_LEN(cur->subcalls); ++idx) {
|
||||
if (cur->subcalls[idx] && cur->subcalls[idx]->pri == link) {
|
||||
if (cur->subcalls[idx] && cur->subcalls[idx]->link == link) {
|
||||
/* This subcall is on the link that came up. */
|
||||
call = cur->subcalls[idx];
|
||||
break;
|
||||
@ -8714,7 +8770,7 @@ void q931_dl_event(struct pri *link, enum Q931_DL_EVENT event)
|
||||
/* No subcall is on the link that came up. */
|
||||
continue;
|
||||
}
|
||||
} else if (cur->pri != link) {
|
||||
} else if (cur->link != link) {
|
||||
/* This call is not on the link that came up. */
|
||||
continue;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user