C-Netz: Move callref to transaction. Callref on SpK only when its busy.

Only when busy, the channel has callref. This is required for audio
routing. During setup, the callref assigned to transaction and kept
there until release to/from upper layer.
This commit is contained in:
Andreas Eversberg
2016-08-01 19:17:13 +02:00
parent 1a3e536010
commit ce7a98206a
3 changed files with 70 additions and 36 deletions

View File

@@ -17,6 +17,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* Notes on channel state an callref:
*
* If channel state is busy, it is used as SpK, also it has callref.
*
* Each transaction has callref, but callref is only assigned to channel
* in SpK mode, so voice frames are routed there.
*
*/
#define CHAN cnetz->sender.kanal #define CHAN cnetz->sender.kanal
#include <stdio.h> #include <stdio.h>
@@ -338,6 +347,7 @@ cnetz_t *search_free_spk(void)
for (sender = sender_head; sender; sender = sender->next) { for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender; cnetz = (cnetz_t *) sender;
/* ignore busy channel */
if (cnetz->state != CNETZ_IDLE) if (cnetz->state != CNETZ_IDLE)
continue; continue;
/* return first free SpK */ /* return first free SpK */
@@ -358,7 +368,7 @@ cnetz_t *search_ogk(void)
for (sender = sender_head; sender; sender = sender->next) { for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender; cnetz = (cnetz_t *) sender;
/* if callref is set, we ignore busy channel with this callref */ /* ignore busy channel */
if (cnetz->state != CNETZ_IDLE) if (cnetz->state != CNETZ_IDLE)
continue; continue;
if (cnetz->chan_type == CHAN_TYPE_OGK) if (cnetz->chan_type == CHAN_TYPE_OGK)
@@ -436,14 +446,13 @@ inval:
PDEBUG(DCNETZ, DEBUG_INFO, "Call to mobile station, paging station id '%s'\n", dialing); PDEBUG(DCNETZ, DEBUG_INFO, "Call to mobile station, paging station id '%s'\n", dialing);
/* 6. trying to page mobile station */ /* 6. trying to page mobile station */
cnetz->sender.callref = callref;
trans = create_transaction(cnetz, TRANS_VAK, dialing[0] - '0', dialing[1] - '0', atoi(dialing + 2)); trans = create_transaction(cnetz, TRANS_VAK, dialing[0] - '0', dialing[1] - '0', atoi(dialing + 2));
if (!trans) { if (!trans) {
PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n");
sender->callref = 0; sender->callref = 0;
return -CAUSE_TEMPFAIL; return -CAUSE_TEMPFAIL;
} }
trans->callref = callref;
trans->try = 1; trans->try = 1;
return 0; return 0;
@@ -463,7 +472,9 @@ void call_out_disconnect(int callref, int cause)
for (sender = sender_head; sender; sender = sender->next) { for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender; cnetz = (cnetz_t *) sender;
if (sender->callref == callref) /* search transaction for this callref */
trans = search_transaction_callref(cnetz, callref);
if (trans)
break; break;
} }
if (!sender) { if (!sender) {
@@ -482,12 +493,14 @@ void call_out_disconnect(int callref, int cause)
} }
#endif #endif
#if 0
trans = cnetz->trans_list; trans = cnetz->trans_list;
if (!trans) { if (!trans) {
call_in_release(callref, cause); call_in_release(callref, cause);
sender->callref = 0; sender->callref = 0;
return; return;
} }
#endif
/* Release when not active */ /* Release when not active */
@@ -499,6 +512,7 @@ void call_out_disconnect(int callref, int cause)
cnetz_release(trans, cnetz_cause_isdn2cnetz(cause)); cnetz_release(trans, cnetz_cause_isdn2cnetz(cause));
call_in_release(callref, cause); call_in_release(callref, cause);
sender->callref = 0; sender->callref = 0;
trans->callref = 0;
break; break;
default: default:
PDEBUG(DCNETZ, DEBUG_INFO, "Call control disconnects on organisation channel, removing transaction.\n"); PDEBUG(DCNETZ, DEBUG_INFO, "Call control disconnects on organisation channel, removing transaction.\n");
@@ -521,7 +535,9 @@ void call_out_release(int callref, int cause)
for (sender = sender_head; sender; sender = sender->next) { for (sender = sender_head; sender; sender = sender->next) {
cnetz = (cnetz_t *) sender; cnetz = (cnetz_t *) sender;
if (sender->callref == callref) /* search transaction for this callref */
trans = search_transaction_callref(cnetz, callref);
if (trans)
break; break;
} }
if (!sender) { if (!sender) {
@@ -531,6 +547,7 @@ void call_out_release(int callref, int cause)
} }
sender->callref = 0; sender->callref = 0;
trans->callref = 0;
#if 0 #if 0
dont use this, because busy state is only entered when channel is actually used for voice dont use this, because busy state is only entered when channel is actually used for voice
@@ -656,27 +673,18 @@ void transaction_timeout(struct timer *timer)
break; break;
case TRANS_BQ: case TRANS_BQ:
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after channel allocation 'Belegung Quittung'\n"); PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after channel allocation 'Belegung Quittung'\n");
#if 0
if (trans->try == N) {
if (trans->mt_call) {
call_in_release(cnetz->sender.callref, CAUSE_OUTOFORDER);
cnetz->sender.callref = 0;
}
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
break;
}
#endif
trans_new_state(trans, TRANS_AF); trans_new_state(trans, TRANS_AF);
trans->repeat = 0; trans->repeat = 0;
break; break;
case TRANS_VHQ: case TRANS_VHQ:
if (cnetz->dsp_mode != DSP_MODE_SPK_V) if (cnetz->dsp_mode != DSP_MODE_SPK_V)
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response hile holding call 'Quittung Verbindung halten'\n"); PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response while holding call 'Quittung Verbindung halten'\n");
else else
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Lost signal from 'FuTln' (mobile station)\n"); PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Lost signal from 'FuTln' (mobile station)\n");
if (trans->mt_call || trans->mo_call) { if (trans->callref) {
call_in_release(cnetz->sender.callref, CAUSE_TEMPFAIL); call_in_release(trans->callref, CAUSE_TEMPFAIL);
cnetz->sender.callref = 0; cnetz->sender.callref = 0;
trans->callref = 0;
} }
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
break; break;
@@ -684,18 +692,21 @@ void transaction_timeout(struct timer *timer)
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after connect 'Durchschalten'\n"); PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after connect 'Durchschalten'\n");
call_in_release(cnetz->sender.callref, CAUSE_TEMPFAIL); call_in_release(cnetz->sender.callref, CAUSE_TEMPFAIL);
cnetz->sender.callref = 0; cnetz->sender.callref = 0;
trans->callref = 0;
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
break; break;
case TRANS_RTA: case TRANS_RTA:
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after ringing order 'Rufton anschalten'\n"); PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after ringing order 'Rufton anschalten'\n");
call_in_release(cnetz->sender.callref, CAUSE_TEMPFAIL); call_in_release(cnetz->sender.callref, CAUSE_TEMPFAIL);
cnetz->sender.callref = 0; cnetz->sender.callref = 0;
trans->callref = 0;
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
break; break;
case TRANS_AHQ: case TRANS_AHQ:
PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after answer 'Abhebequittung'\n"); PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after answer 'Abhebequittung'\n");
call_in_release(cnetz->sender.callref, CAUSE_TEMPFAIL); call_in_release(cnetz->sender.callref, CAUSE_TEMPFAIL);
cnetz->sender.callref = 0; cnetz->sender.callref = 0;
trans->callref = 0;
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
break; break;
case TRANS_MFT: case TRANS_MFT:
@@ -828,7 +839,7 @@ wbn:
/* select channel */ /* select channel */
spk = search_free_spk(); spk = search_free_spk();
if (!spk) { if (!spk) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "No free channel anymore, kicking transaction due to race condition!\n"); PDEBUG(DCNETZ, DEBUG_NOTICE, "No free channel anymore, rejecting call!\n");
destroy_transaction(trans); destroy_transaction(trans);
cnetz_go_idle(cnetz); cnetz_go_idle(cnetz);
break; break;
@@ -837,8 +848,7 @@ wbn:
PDEBUG(DCNETZ, DEBUG_INFO, "Staying on combined calling + traffic channel %d\n", spk->sender.kanal); PDEBUG(DCNETZ, DEBUG_INFO, "Staying on combined calling + traffic channel %d\n", spk->sender.kanal);
} else { } else {
PDEBUG(DCNETZ, DEBUG_INFO, "Assigning phone to traffic channel %d\n", spk->sender.kanal); PDEBUG(DCNETZ, DEBUG_INFO, "Assigning phone to traffic channel %d\n", spk->sender.kanal);
spk->sender.callref = cnetz->sender.callref; spk->sender.callref = trans->callref;
cnetz->sender.callref = 0;
/* sync RX time to current OgK time */ /* sync RX time to current OgK time */
spk->fsk_demod.bit_time = cnetz->fsk_demod.bit_time; spk->fsk_demod.bit_time = cnetz->fsk_demod.bit_time;
} }
@@ -1025,7 +1035,6 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz)
static telegramm_t telegramm; static telegramm_t telegramm;
transaction_t *trans = cnetz->trans_list; transaction_t *trans = cnetz->trans_list;
cnetz_t *ogk; cnetz_t *ogk;
int callref;
memset(&telegramm, 0, sizeof(telegramm)); memset(&telegramm, 0, sizeof(telegramm));
if (!trans) if (!trans)
@@ -1060,15 +1069,16 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz)
if (!cnetz->sender.loopback && (cnetz->sched_ts & 7) == 7 && cnetz->sched_r_m && !timer_running(&trans->timer)) { if (!cnetz->sender.loopback && (cnetz->sched_ts & 7) == 7 && cnetz->sched_r_m && !timer_running(&trans->timer)) {
/* next sub frame */ /* next sub frame */
if (trans->mo_call) { if (trans->mo_call) {
int callref = ++new_callref;
int rc; int rc;
rc = call_in_setup(callref, transaction2rufnummer(trans), trans->dialing); trans->callref = ++new_callref;
rc = call_in_setup(trans->callref, transaction2rufnummer(trans), trans->dialing);
if (rc < 0) { if (rc < 0) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "Call rejected (cause %d), releasing.\n", -rc); PDEBUG(DCNETZ, DEBUG_NOTICE, "Call rejected (cause %d), releasing.\n", -rc);
trans->callref = 0;
cnetz_release(trans, cnetz_cause_isdn2cnetz(-rc)); cnetz_release(trans, cnetz_cause_isdn2cnetz(-rc));
goto call_failed; goto call_failed;
} }
cnetz->sender.callref = callref; cnetz->sender.callref = trans->callref;
trans_new_state(trans, TRANS_DS); trans_new_state(trans, TRANS_DS);
trans->repeat = 0; trans->repeat = 0;
timer_start(&trans->timer, 0.0375 * F_DS); /* F_DS frames */ timer_start(&trans->timer, 0.0375 * F_DS); /* F_DS frames */
@@ -1077,7 +1087,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz)
trans_new_state(trans, TRANS_RTA); trans_new_state(trans, TRANS_RTA);
timer_start(&trans->timer, 0.0375 * F_RTA); /* F_RTA frames */ timer_start(&trans->timer, 0.0375 * F_RTA); /* F_RTA frames */
trans->repeat = 0; trans->repeat = 0;
call_in_alerting(cnetz->sender.callref); call_in_alerting(trans->callref);
} }
} }
break; break;
@@ -1123,14 +1133,15 @@ call_failed:
} }
if (trans->try == N) { if (trans->try == N) {
PDEBUG(DCNETZ, DEBUG_INFO, "Maximum retries, removing transaction\n"); PDEBUG(DCNETZ, DEBUG_INFO, "Maximum retries, removing transaction\n");
destroy_transaction(trans);
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
/* must destroy transaction after cnetz_release */
destroy_transaction(trans);
cnetz->sender.callref = 0;
cnetz_go_idle(cnetz); cnetz_go_idle(cnetz);
break; break;
} }
/* remove call from SpK (or OgK) */ /* remove call from SpK (or OgK+SpK) */
unlink_transaction(trans); unlink_transaction(trans);
callref = cnetz->sender.callref;
cnetz->sender.callref = 0; cnetz->sender.callref = 0;
/* idle channel */ /* idle channel */
cnetz_go_idle(cnetz); cnetz_go_idle(cnetz);
@@ -1138,13 +1149,13 @@ call_failed:
ogk = search_ogk(); ogk = search_ogk();
if (!ogk) { if (!ogk) {
PDEBUG(DCNETZ, DEBUG_NOTICE, "Cannot retry, because currently no OgK available (busy)\n"); PDEBUG(DCNETZ, DEBUG_NOTICE, "Cannot retry, because currently no OgK available (busy)\n");
destroy_transaction(trans);
cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH);
/* must destroy transaction after cnetz_release */
destroy_transaction(trans);
break; break;
} }
PDEBUG(DCNETZ, DEBUG_INFO, "Retry to assign channel.\n"); PDEBUG(DCNETZ, DEBUG_INFO, "Retry to assign channel.\n");
/* attach call to OgK */ /* attach call to OgK */
ogk->sender.callref = callref;
link_transaction(trans, ogk); link_transaction(trans, ogk);
/* change state */ /* change state */
if (trans->mo_call) if (trans->mo_call)
@@ -1247,7 +1258,7 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm)
trans_new_state(trans, TRANS_AHQ); trans_new_state(trans, TRANS_AHQ);
trans->repeat = 0; trans->repeat = 0;
timer_stop(&trans->timer); timer_stop(&trans->timer);
call_in_answer(cnetz->sender.callref, transaction2rufnummer(trans)); call_in_answer(trans->callref, transaction2rufnummer(trans));
break; break;
case OPCODE_AT_K: case OPCODE_AT_K:
if (!match_fuz(cnetz, telegramm, cnetz->cell_nr)) { if (!match_fuz(cnetz, telegramm, cnetz->cell_nr)) {
@@ -1264,9 +1275,10 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm)
trans_new_state(trans, TRANS_AT); trans_new_state(trans, TRANS_AT);
trans->repeat = 0; trans->repeat = 0;
timer_stop(&trans->timer); timer_stop(&trans->timer);
if (cnetz->sender.callref) { if (trans->callref) {
call_in_release(cnetz->sender.callref, CAUSE_NORMAL); call_in_release(trans->callref, CAUSE_NORMAL);
cnetz->sender.callref = 0; cnetz->sender.callref = 0;
trans->callref = 0;
} }
break; break;
default: default:
@@ -1373,9 +1385,10 @@ void cnetz_receive_telegramm_spk_v(cnetz_t *cnetz, telegramm_t *telegramm)
trans_new_state(trans, TRANS_AT); trans_new_state(trans, TRANS_AT);
trans->repeat = 0; trans->repeat = 0;
timer_stop(&trans->timer); timer_stop(&trans->timer);
if (cnetz->sender.callref) { if (trans->callref) {
call_in_release(cnetz->sender.callref, CAUSE_NORMAL); call_in_release(trans->callref, CAUSE_NORMAL);
cnetz->sender.callref = 0; cnetz->sender.callref = 0;
trans->callref = 0;
} }
break; break;
default: default:

View File

@@ -162,6 +162,25 @@ transaction_t *search_transaction_number(cnetz_t *cnetz, uint8_t futln_nat, uint
return NULL; return NULL;
} }
transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref)
{
transaction_t *trans = cnetz->trans_list;
/* just in case, this should not happen */
if (!callref)
return NULL;
while (trans) {
if (trans->callref == callref) {
const char *rufnummer = transaction2rufnummer(trans);
PDEBUG(DTRANS, DEBUG_DEBUG, "Found transaction for subscriber '%s'\n", rufnummer);
return trans;
}
trans = trans->next;
}
return NULL;
}
static const char *trans_state_name(int state) static const char *trans_state_name(int state)
{ {
switch (state) { switch (state) {

View File

@@ -27,6 +27,7 @@
typedef struct transaction { typedef struct transaction {
struct transaction *next; /* pointer to next node in list */ struct transaction *next; /* pointer to next node in list */
cnetz_t *cnetz; /* pointer to cnetz instance */ cnetz_t *cnetz; /* pointer to cnetz instance */
int callref; /* callref for transaction */
uint8_t futln_nat; /* current station ID (3 values) */ uint8_t futln_nat; /* current station ID (3 values) */
uint8_t futln_fuvst; uint8_t futln_fuvst;
uint16_t futln_rest; uint16_t futln_rest;
@@ -48,6 +49,7 @@ void link_transaction(transaction_t *trans, cnetz_t *cnetz);
void unlink_transaction(transaction_t *trans); void unlink_transaction(transaction_t *trans);
transaction_t *search_transaction(cnetz_t *cnetz, uint32_t state_mask); transaction_t *search_transaction(cnetz_t *cnetz, uint32_t state_mask);
transaction_t *search_transaction_number(cnetz_t *cnetz, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest); transaction_t *search_transaction_number(cnetz_t *cnetz, uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest);
transaction_t *search_transaction_callref(cnetz_t *cnetz, int callref);
void trans_new_state(transaction_t *trans, int state); void trans_new_state(transaction_t *trans, int state);
void cnetz_flush_other_transactions(cnetz_t *cnetz, transaction_t *trans); void cnetz_flush_other_transactions(cnetz_t *cnetz, transaction_t *trans);
void transaction_timeout(struct timer *timer); void transaction_timeout(struct timer *timer);