From 53c142990fd00aa5d862a03890a4aef5b4325e6d Mon Sep 17 00:00:00 2001 From: Richard Mudgett Date: Thu, 21 Oct 2010 16:37:10 +0000 Subject: [PATCH] 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 --- pri.c | 37 +++++-- pri_facility.c | 7 +- pri_internal.h | 7 +- pri_q921.h | 2 +- pri_q931.h | 7 +- q921.c | 50 ++++----- q931.c | 270 +++++++++++++++++++++++++++++-------------------- 7 files changed, 225 insertions(+), 155 deletions(-) diff --git a/pri.c b/pri.c index 6cb0e0d..36ee69c 100644 --- a/pri.c +++ b/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); diff --git a/pri_facility.c b/pri_facility.c index ed01b45..dc4b5c4 100644 --- a/pri_facility.c +++ b/pri_facility.c @@ -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 */ diff --git a/pri_internal.h b/pri_internal.h index 1123d24..c83329c 100644 --- a/pri_internal.h +++ b/pri_internal.h @@ -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); diff --git a/pri_q921.h b/pri_q921.h index 9bd400f..12d3997 100644 --- a/pri_q921.h +++ b/pri_q921.h @@ -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); diff --git a/pri_q931.h b/pri_q931.h index 4c317ae..aed19bd 100644 --- a/pri_q931.h +++ b/pri_q931.h @@ -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); diff --git a/q921.c b/q921.c index 7df4065..924cb0a 100644 --- a/q921.c +++ b/q921.c @@ -798,41 +798,33 @@ 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; - - switch (link->q921_state) { - case Q921_TEI_UNASSIGNED: - q921_setstate(link, Q921_ESTABLISH_AWAITING_TEI); - q921_tei_request(link); - break; - case Q921_ASSIGN_AWAITING_TEI: - q921_setstate(link, Q921_ESTABLISH_AWAITING_TEI); - break; - default: - break; + if (BRI_TE_PTMP(ctrl)) { + switch (link->q921_state) { + case Q921_TEI_UNASSIGNED: + q921_setstate(link, Q921_ESTABLISH_AWAITING_TEI); + q921_tei_request(link); + break; + case Q921_ASSIGN_AWAITING_TEI: + q921_setstate(link, Q921_ESTABLISH_AWAITING_TEI); + break; + 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: diff --git a/q931.c b/q931.c index 98927d1..34fafeb 100644 --- a/q931.c +++ b/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); + /* 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->pri = ctrl; + 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; } + 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(ctrl, cr); + 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 {