diff --git a/pri_internal.h b/pri_internal.h index d994ea2..eb49577 100644 --- a/pri_internal.h +++ b/pri_internal.h @@ -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. diff --git a/pri_q931.h b/pri_q931.h index b27e659..9ff4de6 100644 --- a/pri_q931.h +++ b/pri_q931.h @@ -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); diff --git a/pridump.c b/pridump.c index 878fb20..a43e473 100644 --- a/pridump.c +++ b/pridump.c @@ -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); diff --git a/q931.c b/q931.c index 6e85181..7e76ba4 100644 --- a/q931.c +++ b/q931.c @@ -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,88 +3502,164 @@ 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) { return ctrl->dummy_call; } - /* Find the master - He has the call pool */ + /* Find the master - He has the call pool */ master = PRI_MASTER(ctrl); - cur = *master->callpool; - prev = NULL; - while (cur) { - if (cur->cr == cr) { - /* Found existing call. */ - switch (ctrl->switchtype) { - case PRI_SWITCH_GR303_EOC: - case PRI_SWITCH_GR303_EOC_PATH: - case PRI_SWITCH_GR303_TMC: - case PRI_SWITCH_GR303_TMC_SWITCHING: + 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; - default: - if (!ctrl->bri) { - /* PRI is set to whoever called us */ - cur->pri = ctrl; + } + } + } else { + for (cur = *master->callpool; cur; cur = cur->next) { + if (cur->cr == cr) { + /* Found existing call. */ + switch (ctrl->switchtype) { + case PRI_SWITCH_GR303_EOC: + case PRI_SWITCH_GR303_EOC_PATH: + case PRI_SWITCH_GR303_TMC: + case PRI_SWITCH_GR303_TMC_SWITCHING: + break; + default: + if (!ctrl->bri) { + /* PRI is set to whoever called us */ + cur->pri = ctrl; + } + break; } break; } - return cur; } - 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: