diff options
Diffstat (limited to 'src/cnetz/cnetz.c')
-rw-r--r-- | src/cnetz/cnetz.c | 647 |
1 files changed, 352 insertions, 295 deletions
diff --git a/src/cnetz/cnetz.c b/src/cnetz/cnetz.c index 08cb668..b3771d7 100644 --- a/src/cnetz/cnetz.c +++ b/src/cnetz/cnetz.c @@ -143,10 +143,12 @@ #include <math.h> #include <inttypes.h> #include "../libsample/sample.h" -#include "../libdebug/debug.h" +#include "../liblogging/logging.h" #include "../libmobile/call.h" #include "../libmobile/cause.h" -#include "../libosmocc/message.h" +#include "../libmobile/get_time.h" +#include "../libmobile/console.h" +#include <osmocom/cc/message.h> #include "cnetz.h" #include "database.h" #include "sysinfo.h" @@ -157,8 +159,16 @@ /* uncomment this to do echo debugging (-l) on Speech Channel */ //#define DEBUG_SPK +#define FLOAT_TO_TIMEOUT(f) floor(f), ((f) - floor(f)) * 1000000 + #define CUT_OFF_EMPHASIS_CNETZ 796.0 /* 200 uS time constant */ +/* OgK list of alternative channels, NOT including 131 */ +cnetz_t *ogk_list[16]; +int ogk_list_count = 0; +int ogk_list_index = 0; + + /* Convert channel number to frequency number of base station. Set 'unterband' to 1 to get frequency of mobile station. */ double cnetz_kanal2freq(int kanal, int unterband) @@ -178,6 +188,28 @@ double cnetz_kanal2freq(int kanal, int unterband) return freq * 1e6; } +/* check if number is a valid station ID */ +const char *cnetz_number_valid(const char *number) +{ + /* assume that the number has valid length(s) and digits */ + + if (number[0] > '7') + return "Digit 1 (mobile country code) exceeds 7."; + if (number[7]) { + if ((number[1] - '0') == 0) + return "Digit 2 and 3 (mobile network code) of 8-digit number must be at least 10."; + if ((number[1] - '0') * 10 + (number[2] - '0') > 31) + return "Digit 2 and 3 (mobile network code) of 8-digit number exceed 31."; + if (atoi(number + 3) > 65535) + return "Digit 4 to 8 (mobile subscriber suffix) of 8-digit number exceed 65535."; + } else { + if (atoi(number + 2) > 65535) + return "Digit 3 to 7 (mobile subscriber suffix) of 7-digit number exceed 65535."; + } + + return NULL; +} + /* convert power level to P-bits by selecting next higher level */ static uint8_t cnetz_power2bits(int power) { @@ -198,7 +230,7 @@ static uint8_t cnetz_power2bits(int power) } } -const char *cnetz_state_name(enum cnetz_state state) +static const char *cnetz_state_name(enum cnetz_state state) { static char invalid[16]; @@ -235,13 +267,13 @@ static void cnetz_new_state(cnetz_t *cnetz, enum cnetz_state new_state) { if (cnetz->state == new_state) return; - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "State change: %s -> %s\n", cnetz_state_name(cnetz->state), cnetz_state_name(new_state)); + LOGP_CHAN(DCNETZ, LOGL_INFO, "State change: %s -> %s\n", cnetz_state_name(cnetz->state), cnetz_state_name(new_state)); cnetz->state = new_state; cnetz_display_status(); } /* Convert ISDN cause to 'Ausloesegrund' of C-Netz mobile station */ -uint8_t cnetz_cause_isdn2cnetz(int cause) +static uint8_t cnetz_cause_isdn2cnetz(int cause) { switch (cause) { case CAUSE_NORMAL: @@ -264,65 +296,71 @@ int cnetz_init(void) } /* Create transceiver instance and link to a list. */ -int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char *audiodev, int use_sdr, enum demod_type demod, int samplerate, double rx_gain, double tx_gain, int challenge_valid, uint64_t challenge, int response_valid, uint64_t response, int warteschlange, int metering, double speech_deviation, int ms_power, int measure_speed, double clock_speed[2], int polarity, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback) +int cnetz_create(const char *kanal_name, enum cnetz_chan_type chan_type, const char *device, int use_sdr, enum demod_type demod, int samplerate, double rx_gain, double tx_gain, int challenge_valid, uint64_t challenge, int response_valid, uint64_t response, int warteschlange, int metering, double speech_deviation, int ms_power, int measure_speed, double clock_speed[2], int polarity, int pre_emphasis, int de_emphasis, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback) { sender_t *sender; cnetz_t *cnetz; + int kanal; int rc; - if ((atoi(kanal) & 1) && (atoi(kanal) < 3 || atoi(kanal) > 1147)) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Channel ('Kanal') number %s invalid. For odd channel numbers, use channel 3 ... 1147.\n", kanal); + kanal = atoi(kanal_name); + if ((kanal & 1) && (kanal < 3 || kanal > 1147)) { + LOGP(DCNETZ, LOGL_ERROR, "Channel ('Kanal') number %d invalid. For odd channel numbers, use channel 3 ... 1147.\n", kanal); return -EINVAL; } - if ((atoi(kanal) & 1) && atoi(kanal) > 947) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You defined an extended frequency channel %s, only newer phones support this!\n", kanal); + if ((kanal & 1) && kanal > 947) { + LOGP(DCNETZ, LOGL_NOTICE, "You defined an extended frequency channel %d, only newer phones support this!\n", kanal); } - if (!(atoi(kanal) & 1) && (atoi(kanal) < 4 || atoi(kanal) > 918)) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Channel ('Kanal') number %s invalid. For even channel numbers, use channel 4 ... 918.\n", kanal); + if (!(kanal & 1) && (kanal < 4 || kanal > 918)) { + LOGP(DCNETZ, LOGL_ERROR, "Channel ('Kanal') number %d invalid. For even channel numbers, use channel 4 ... 918.\n", kanal); return -EINVAL; } - if (!(atoi(kanal) & 1) && atoi(kanal) > 758) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You defined an extended frequency %s, only newer phones support this!\n", kanal); - } - - /* OgK must be on channel 131 */ - if ((chan_type == CHAN_TYPE_OGK || chan_type == CHAN_TYPE_OGK_SPK) && atoi(kanal) != CNETZ_OGK_KANAL) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You must use channel %d for calling channel ('Orga-Kanal') or for combined calling + traffic channel!\n", CNETZ_OGK_KANAL); - return -EINVAL; + if (!(kanal & 1) && kanal > 758) { + LOGP(DCNETZ, LOGL_NOTICE, "You defined an extended frequency channel %d, only newer phones support this!\n", kanal); } /* SpK must be on channel other than 131 */ - if (chan_type == CHAN_TYPE_SPK && atoi(kanal) == CNETZ_OGK_KANAL) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You must not use channel %d for traffic channel!\n", CNETZ_OGK_KANAL); + if (chan_type == CHAN_TYPE_SPK && kanal == CNETZ_STD_OGK_KANAL) { + LOGP(DCNETZ, LOGL_NOTICE, "You must not use channel %d for traffic channel!\n", CNETZ_STD_OGK_KANAL); return -EINVAL; } /* warn if we combine SpK and OgK, this is not supported by standard */ if (chan_type == CHAN_TYPE_OGK_SPK) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "You selected channel %d ('Orga-Kanal') for combined calling + traffic channel. Some phones will reject this.\n", CNETZ_OGK_KANAL); + LOGP(DCNETZ, LOGL_NOTICE, "You selected channel %d ('Orga-Kanal') for combined control + traffic channel. Some phones will reject this.\n", kanal); } for (sender = sender_head; sender; sender = sender->next) { cnetz = (cnetz_t *)sender; - if (!!strcmp(sender->audiodev, audiodev)) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "To be able to sync multiple channels, all channels must be on the same sound device!\n"); + if (!!strcmp(sender->device, device)) { + LOGP(DCNETZ, LOGL_NOTICE, "To be able to sync multiple channels, all channels must be on the same sound device!\n"); return -EINVAL; } } cnetz = calloc(1, sizeof(cnetz_t)); if (!cnetz) { - PDEBUG(DCNETZ, DEBUG_ERROR, "No memory!\n"); + LOGP(DCNETZ, LOGL_ERROR, "No memory!\n"); return -ENOMEM; } - PDEBUG(DCNETZ, DEBUG_DEBUG, "Creating 'C-Netz' instance for 'Kanal' = %s (sample rate %d).\n", kanal, samplerate); + LOGP(DCNETZ, LOGL_DEBUG, "Creating 'C-Netz' instance for 'Kanal' = %d (sample rate %d).\n", kanal, samplerate); + + cnetz->kanal = kanal; + if ((chan_type == CHAN_TYPE_OGK || chan_type == CHAN_TYPE_OGK_SPK) && kanal != CNETZ_STD_OGK_KANAL) { + if (ogk_list_count == 16) { + LOGP(DCNETZ, LOGL_ERROR, "No more than 16 non-standard OGK are allowed!\n"); + rc = -EINVAL; + goto error; + } + ogk_list[ogk_list_count++] = cnetz; + } /* init general part of transceiver */ /* do not enable emphasis, since it is done by cnetz code, not by common sender code */ - rc = sender_create(&cnetz->sender, kanal, cnetz_kanal2freq(atoi(kanal), 0), cnetz_kanal2freq(atoi(kanal), 1), audiodev, use_sdr, samplerate, rx_gain, tx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, PAGING_SIGNAL_NONE); + rc = sender_create(&cnetz->sender, kanal_name, cnetz_kanal2freq(kanal, 0), cnetz_kanal2freq(kanal, 1), device, use_sdr, samplerate, rx_gain, tx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, PAGING_SIGNAL_NONE); if (rc < 0) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to init transceiver process!\n"); + LOGP(DCNETZ, LOGL_ERROR, "Failed to init transceiver process!\n"); goto error; } @@ -337,7 +375,7 @@ int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char * /* init audio processing */ rc = dsp_init_sender(cnetz, measure_speed, clock_speed, demod, speech_deviation); if (rc < 0) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to init signal processing!\n"); + LOGP(DCNETZ, LOGL_ERROR, "Failed to init signal processing!\n"); goto error; } @@ -381,13 +419,13 @@ int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char * cnetz_go_idle(cnetz); #ifdef DEBUG_SPK - transaction_t *trans = create_transaction(cnetz, TRANS_DS, 2, 2, 22002, -1, -1); + transaction_t *trans = create_transaction(cnetz, TRANS_DS, 2, 2, 22002, -1, -1, NAN); trans->mo_call = 1; cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_K, (cnetz->sched_ts + 2) & 31); #else /* create transaction for speech channel loopback */ if (loopback && chan_type == CHAN_TYPE_SPK) { - transaction_t *trans = create_transaction(cnetz, TRANS_VHQ_K, 2, 2, 22002, -1, -1); + transaction_t *trans = create_transaction(cnetz, TRANS_VHQ_K, 2, 2, 22002, -1, -1, NAN); trans->mo_call = 1; cnetz_set_dsp_mode(cnetz, DSP_MODE_SPK_K); cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_K, (cnetz->sched_ts + 1) & 31); @@ -397,21 +435,23 @@ int cnetz_create(const char *kanal, enum cnetz_chan_type chan_type, const char * #if 0 /* debug flushing transactions */ transaction_t *trans1, *trans2; - trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1); + trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1, NAN); destroy_transaction(trans1); - trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1); + trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1, NAN); destroy_transaction(trans1); - trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1); - trans2 = create_transaction(cnetz, 99, 2, 2, 22002, -1, -1); + trans1 = create_transaction(cnetz, 99, 6, 2, 15784, -1, -1, NAN); + trans2 = create_transaction(cnetz, 99, 2, 2, 22002, -1, -1, NAN); unlink_transaction(trans1); link_transaction(trans1, cnetz); cnetz_flush_other_transactions(cnetz, trans1); - trans2 = create_transaction(cnetz, 99, 2, 2, 22002, -1, -1); + trans2 = create_transaction(cnetz, 99, 2, 2, 22002, -1, -1, NAN); cnetz_flush_other_transactions(cnetz, trans2); #endif - PDEBUG(DCNETZ, DEBUG_NOTICE, "Created 'Kanal' #%s of type '%s' = %s\n", kanal, chan_type_short_name(chan_type), chan_type_long_name(chan_type)); - PDEBUG(DNMT, DEBUG_NOTICE, " -> Using cell ID: Nat=%d FuVst=%d Rest=%d Name='%s'\n", si.fuz_nat, si.fuz_fuvst, si.fuz_rest, get_station_name(si.fuz_nat, si.fuz_fuvst, si.fuz_rest)); + LOGP(DCNETZ, LOGL_NOTICE, "Created 'Kanal' #%d of type '%s' = %s\n", kanal, chan_type_short_name(chan_type), chan_type_long_name(chan_type)); + const char *name, *long_name; + name = get_station_name(si.fuz_nat, si.fuz_fuvst, si.fuz_rest, &long_name); + LOGP(DCNETZ, LOGL_NOTICE, " -> Using cell ID: Nat=%d FuVst=%d Rest=%d Name='%s' Long Name='%s'\n", si.fuz_nat, si.fuz_fuvst, si.fuz_rest, name, long_name); return 0; @@ -427,11 +467,11 @@ void cnetz_destroy(sender_t *sender) cnetz_t *cnetz = (cnetz_t *) sender; transaction_t *trans; - PDEBUG(DCNETZ, DEBUG_DEBUG, "Destroying 'C-Netz' instance for 'Kanal' = %s.\n", sender->kanal); + LOGP(DCNETZ, LOGL_DEBUG, "Destroying 'C-Netz' instance for 'Kanal' = %s.\n", sender->kanal); while ((trans = search_transaction(cnetz, ~0))) { const char *rufnummer = transaction2rufnummer(trans); - PDEBUG(DCNETZ, DEBUG_NOTICE, "Removing pending transaction for subscriber '%s'\n", rufnummer); + LOGP(DCNETZ, LOGL_NOTICE, "Removing pending transaction for subscriber '%s'\n", rufnummer); destroy_transaction(trans); } @@ -449,9 +489,9 @@ static cnetz_t *search_free_spk(int extended) cnetz = (cnetz_t *) sender; /* ignore extended frequency, if not supported */ if (!extended) { - if ((atoi(sender->kanal) & 1) && atoi(sender->kanal) > 947) + if ((cnetz->kanal & 1) && cnetz->kanal > 947) continue; - if (!(atoi(sender->kanal) & 1) && atoi(sender->kanal) > 758) + if (!(cnetz->kanal & 1) && cnetz->kanal > 758) continue; } /* ignore busy channel */ @@ -468,7 +508,7 @@ static cnetz_t *search_free_spk(int extended) return ogk_spk; } -static cnetz_t *search_ogk(void) +static cnetz_t *search_ogk(int kanal) { sender_t *sender; cnetz_t *cnetz; @@ -478,6 +518,8 @@ static cnetz_t *search_ogk(void) /* ignore busy channel */ if (cnetz->state != CNETZ_IDLE) continue; + if (cnetz->kanal != kanal) + continue; if (cnetz->chan_type == CHAN_TYPE_OGK) return cnetz; if (cnetz->chan_type == CHAN_TYPE_OGK_SPK) @@ -490,40 +532,40 @@ static cnetz_t *search_ogk(void) /* Abort connection, if any and send idle broadcast */ void cnetz_go_idle(cnetz_t *cnetz) { - cnetz_t *ogk; transaction_t *trans; if (cnetz->state == CNETZ_IDLE) return; if (cnetz->trans_list) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Releasing but still having transaction, please fix!\n"); + LOGP(DCNETZ, LOGL_ERROR, "Releasing but still having transaction, please fix!\n"); if (cnetz->trans_list->callref) call_up_release(cnetz->trans_list->callref, CAUSE_NORMAL); destroy_transaction(cnetz->trans_list); } - PDEBUG(DCNETZ, DEBUG_INFO, "Entering IDLE state on channel %s.\n", cnetz->sender.kanal); + LOGP(DCNETZ, LOGL_INFO, "Entering IDLE state on channel %s.\n", cnetz->sender.kanal); cnetz_new_state(cnetz, CNETZ_IDLE); + cnetz->sched_lr_debugged = 0; + cnetz->sched_mlr_debugged = 0; /* set scheduler to OgK or turn off SpK */ if (cnetz->dsp_mode == DSP_MODE_SPK_K || cnetz->dsp_mode == DSP_MODE_SPK_V) { /* switch next frame after distributed signaling boundary (multiple of 8 slots) */ - cnetz_set_sched_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, (cnetz->sched_ts + 8) & 24); + cnetz_set_sched_dsp_mode(cnetz, (cnetz->chan_type == CHAN_TYPE_OGK || cnetz->chan_type == CHAN_TYPE_OGK_SPK) ? DSP_MODE_OGK : DSP_MODE_OFF, (cnetz->sched_ts + 8) & 24); } else { /* switch next frame */ - cnetz_set_sched_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF, (cnetz->sched_ts + 1) & 31); - cnetz_set_dsp_mode(cnetz, (atoi(cnetz->sender.kanal) == CNETZ_OGK_KANAL) ? DSP_MODE_OGK : DSP_MODE_OFF); + cnetz_set_sched_dsp_mode(cnetz, (cnetz->chan_type == CHAN_TYPE_OGK || cnetz->chan_type == CHAN_TYPE_OGK_SPK) ? DSP_MODE_OGK : DSP_MODE_OFF, (cnetz->sched_ts + 1) & 31); + cnetz_set_dsp_mode(cnetz, (cnetz->chan_type == CHAN_TYPE_OGK || cnetz->chan_type == CHAN_TYPE_OGK_SPK) ? DSP_MODE_OGK : DSP_MODE_OFF); } /* check for first phone in queue and trigger completion of call (becoming idle means that SpK is now available) */ - ogk = search_ogk(); - trans = search_transaction(ogk, TRANS_MT_QUEUE | TRANS_MO_QUEUE); + trans = search_transaction_queue(); if (trans) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Now channel available for queued subscriber '%s'.\n", transaction2rufnummer(trans)); + LOGP(DCNETZ, LOGL_NOTICE, "Now channel is available for queued subscriber '%s'.\n", transaction2rufnummer(trans)); trans_new_state(trans, (trans->state == TRANS_MT_QUEUE) ? TRANS_MT_DELAY : TRANS_MO_DELAY); - timer_stop(&trans->timer); - timer_start(&trans->timer, 2.0); + osmo_timer_del(&trans->timer); + osmo_timer_schedule(&trans->timer, 3,0); /* Wait at least one frame cycles (2.4s) until timeout */ } } @@ -534,119 +576,67 @@ static void cnetz_release(transaction_t *trans, uint8_t cause) trans->repeat = 0; trans->release_cause = cause; trans->cnetz->sched_dsp_mode_ts = -1; - timer_stop(&trans->timer); + osmo_timer_del(&trans->timer); } -/* Receive audio from call instance. */ -void call_down_audio(int callref, sample_t *samples, int count) -{ - sender_t *sender; - cnetz_t *cnetz; - - for (sender = sender_head; sender; sender = sender->next) { - cnetz = (cnetz_t *) sender; - if (cnetz->trans_list && cnetz->trans_list->callref == callref) - break; - } - if (!sender) - return; - - if (cnetz->dsp_mode == DSP_MODE_SPK_V) { - /* store as is, since we convert rate when processing FSK frames */ - jitter_save(&cnetz->sender.dejitter, samples, count); - } -} - -void call_down_clock(void) {} - int call_down_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) { - sender_t *sender; - cnetz_t *cnetz, *spk; + cnetz_t *ogk, *spk; int rc; int extended; transaction_t *trans; uint8_t futln_nat; uint8_t futln_fuvst; int futln_rest; /* use int for checking size > 65535 */ - int len; - int i; - - /* 1. check if number is invalid, return INVALNUMBER */ - len = strlen(dialing); - if (len >= 11 && !strncmp(dialing, "0161", 4)) { - dialing += 4; - len -= 4; - } - if (len < 7 || len > 8) { -inval: - PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call to invalid number '%s', rejecting!\n", dialing); - return -CAUSE_INVALNUMBER; - } - for (i = 0; i < len; i++) { - if (dialing[i] < '0' || dialing[i] > '9') - goto inval; - } + int ogk_kanal; + /* 1. split number into elements */ futln_nat = dialing[0] - '0'; - if (len == 7) - futln_fuvst = dialing[1] - '0'; - else { + if (dialing[7]) { futln_fuvst = (dialing[1] - '0') * 10 + (dialing[2] - '0'); - if (futln_fuvst > 31) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Digit 2 and 3 '%02d' must not exceed '31', but they do!\n", futln_fuvst); - goto inval; - } - } - futln_rest = atoi(dialing + len - 5); - if (futln_rest > 65535) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Last 5 digits '%05d' must not exceed '65535', but they do!\n", futln_rest); - goto inval; + futln_rest = atoi(dialing + 3); + } else { + futln_fuvst = dialing[1] - '0'; + futln_rest = atoi(dialing + 2); } /* 2. check if the subscriber is attached */ - rc = find_db(futln_nat, futln_fuvst, futln_rest, NULL, &extended); + rc = find_db(futln_nat, futln_fuvst, futln_rest, &ogk_kanal, NULL, &extended); if (rc < 0) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call to not attached subscriber, rejecting!\n"); + LOGP(DCNETZ, LOGL_NOTICE, "Outgoing call to not attached subscriber, rejecting!\n"); return -CAUSE_OUTOFORDER; } /* 3. check if given number is already in a call, return BUSY */ - for (sender = sender_head; sender; sender = sender->next) { - cnetz = (cnetz_t *) sender; - /* search transaction for this number */ - trans = search_transaction_number(cnetz, futln_nat, futln_fuvst, futln_rest); - if (trans) - break; - } - if (sender) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call to busy number, rejecting!\n"); + trans = search_transaction_number_global(futln_nat, futln_fuvst, futln_rest); + if (trans) { + LOGP(DCNETZ, LOGL_NOTICE, "Outgoing call to busy number, rejecting!\n"); return -CAUSE_BUSY; } /* 4. check if we have no OgK, return NOCHANNEL */ - cnetz = search_ogk(); - if (!cnetz) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call, but OgK is currently busy, rejecting!\n"); + ogk = search_ogk(ogk_kanal); + if (!ogk) { + LOGP(DCNETZ, LOGL_NOTICE, "Outgoing call, but OgK is currently busy, rejecting!\n"); return -CAUSE_NOCHANNEL; } /* 5. check if all senders are busy, return NOCHANNEL */ spk = search_free_spk(extended); if (!spk) { - if (!cnetz->warteschlange) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call, but no free channel, rejecting!\n"); + if (!ogk->warteschlange) { + LOGP(DCNETZ, LOGL_NOTICE, "Outgoing call, but no free channel, rejecting!\n"); return -CAUSE_NOCHANNEL; } else - PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing call, but no free channel, queuing call!\n"); + LOGP(DCNETZ, LOGL_NOTICE, "Outgoing call, but no free channel, queuing call!\n"); } - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Call to mobile station, paging station id '%s'\n", dialing); + LOGP(DCNETZ, LOGL_INFO, "Call to mobile station, paging station id '%s'\n", dialing); /* 6. trying to page mobile station */ - trans = create_transaction(cnetz, (spk) ? TRANS_VAK : TRANS_WSK, dialing[0] - '0', dialing[1] - '0', atoi(dialing + 2), -1, -1); + trans = create_transaction(ogk, (spk) ? TRANS_VAK : TRANS_WSK, futln_nat, futln_fuvst, futln_rest, -1, -1, NAN); if (!trans) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); + LOGP(DCNETZ, LOGL_ERROR, "Failed to create transaction\n"); return -CAUSE_TEMPFAIL; } trans->callref = callref; @@ -655,8 +645,35 @@ inval: return 0; } -void call_down_answer(int __attribute__((unused)) callref) +void call_down_answer(int callref, struct timeval *tv_meter) { + sender_t *sender; + cnetz_t *cnetz; + transaction_t *trans; + + LOGP(DCNETZ, LOGL_INFO, "Call has been answered by network.\n"); + + for (sender = sender_head; sender; sender = sender->next) { + cnetz = (cnetz_t *) sender; + trans = search_transaction_callref(cnetz, callref); + if (trans) + break; + } + if (!sender) { + LOGP(DCNETZ, LOGL_NOTICE, "Incoming answer, but no callref!\n"); + return; + } + + /* At least tone second! */ + if (tv_meter->tv_sec) { + LOGP(DCNETZ, LOGL_INFO, "Network starts metering pulses every %lu.%03lu seconds.\n", tv_meter->tv_sec, tv_meter->tv_usec / 1000); + trans->meter_start = get_time(); + trans->metering_time = (double)tv_meter->tv_sec + (double)tv_meter->tv_usec / 1000000.0; + } else if (cnetz->metering) { + LOGP(DCNETZ, LOGL_INFO, "Command line options starts metering pulses every %d seconds.\n", cnetz->metering); + trans->meter_start = get_time(); + trans->metering_time = (double)cnetz->metering; + } } /* Call control sends disconnect (with tones). @@ -669,7 +686,7 @@ void call_down_disconnect(int callref, int cause) cnetz_t *cnetz; transaction_t *trans; - PDEBUG(DCNETZ, DEBUG_INFO, "Call has been disconnected by network.\n"); + LOGP(DCNETZ, LOGL_INFO, "Call has been disconnected by network.\n"); for (sender = sender_head; sender; sender = sender->next) { cnetz = (cnetz_t *) sender; @@ -679,7 +696,7 @@ void call_down_disconnect(int callref, int cause) break; } if (!sender) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n"); + LOGP(DCNETZ, LOGL_NOTICE, "Outgoing disconnect, but no callref!\n"); call_up_release(callref, CAUSE_INVALCALLREF); return; } @@ -688,15 +705,17 @@ void call_down_disconnect(int callref, int cause) switch (cnetz->dsp_mode) { case DSP_MODE_SPK_V: + /* stop metering */ + trans->meter_end = get_time(); return; case DSP_MODE_SPK_K: - PDEBUG(DCNETZ, DEBUG_INFO, "Call control disconnects on speech channel, releasing towards mobile station.\n"); + LOGP(DCNETZ, LOGL_INFO, "Call control disconnects on speech channel, releasing towards mobile station.\n"); cnetz_release(trans, cnetz_cause_isdn2cnetz(cause)); call_up_release(callref, cause); trans->callref = 0; break; default: - PDEBUG(DCNETZ, DEBUG_INFO, "Call control disconnects on organisation channel, removing transaction.\n"); + LOGP(DCNETZ, LOGL_INFO, "Call control disconnects on organisation channel, removing transaction.\n"); call_up_release(callref, cause); trans->callref = 0; if (trans->state == TRANS_MT_QUEUE || trans->state == TRANS_MT_DELAY) { @@ -716,7 +735,7 @@ void call_down_release(int callref, int cause) cnetz_t *cnetz; transaction_t *trans; - PDEBUG(DCNETZ, DEBUG_INFO, "Call has been released by network, releasing call.\n"); + LOGP(DCNETZ, LOGL_INFO, "Call has been released by network, releasing call.\n"); for (sender = sender_head; sender; sender = sender->next) { cnetz = (cnetz_t *) sender; @@ -726,7 +745,7 @@ void call_down_release(int callref, int cause) break; } if (!sender) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing release, but no callref!\n"); + LOGP(DCNETZ, LOGL_NOTICE, "Outgoing release, but no callref!\n"); /* don't send release, because caller already released */ return; } @@ -736,11 +755,11 @@ void call_down_release(int callref, int cause) switch (cnetz->dsp_mode) { case DSP_MODE_SPK_K: case DSP_MODE_SPK_V: - PDEBUG(DCNETZ, DEBUG_INFO, "Call control releases on speech channel, releasing towards mobile station.\n"); + LOGP(DCNETZ, LOGL_INFO, "Call control releases on speech channel, releasing towards mobile station.\n"); cnetz_release(trans, cnetz_cause_isdn2cnetz(cause)); break; default: - PDEBUG(DCNETZ, DEBUG_INFO, "Call control releases on organisation channel, removing transaction.\n"); + LOGP(DCNETZ, LOGL_INFO, "Call control releases on organisation channel, removing transaction.\n"); if (trans->state == TRANS_MT_QUEUE) { cnetz_release(trans, cnetz_cause_isdn2cnetz(cause)); } else { @@ -750,19 +769,19 @@ void call_down_release(int callref, int cause) } } -int cnetz_meldeaufruf(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest) +int cnetz_meldeaufruf(uint8_t futln_nat, uint8_t futln_fuvst, uint16_t futln_rest, int ogk_kanal) { cnetz_t *cnetz; transaction_t *trans; - cnetz = search_ogk(); + cnetz = search_ogk(ogk_kanal); if (!cnetz) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "'Meldeaufruf', but OgK is currently busy!\n"); + LOGP(DCNETZ, LOGL_NOTICE, "'Meldeaufruf', but OgK is currently busy!\n"); return -CAUSE_NOCHANNEL; } - trans = create_transaction(cnetz, TRANS_MA, futln_nat, futln_fuvst, futln_rest, -1, -1); + trans = create_transaction(cnetz, TRANS_MA, futln_nat, futln_fuvst, futln_rest, -1, -1, NAN); if (!trans) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); + LOGP(DCNETZ, LOGL_ERROR, "Failed to create transaction\n"); return -CAUSE_TEMPFAIL; } @@ -827,29 +846,20 @@ const char *chan_type_long_name(enum cnetz_chan_type chan_type) } /* Timeout handling */ -void transaction_timeout(struct timer *timer) +void transaction_timeout(void *data) { - transaction_t *trans = (transaction_t *)timer->priv; + transaction_t *trans = data; cnetz_t *cnetz = trans->cnetz; switch (trans->state) { - case TRANS_WAF: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after dialing request 'Wahlaufforderung'\n"); - if (trans->try == N) { - trans_new_state(trans, TRANS_WBN); - break; - } - trans->try++; - trans_new_state(trans, TRANS_VWG); - break; case TRANS_MT_QUEUE: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Phone in queue, but still no channel available, releasing call!\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Phone in queue, but still no channel available, releasing call!\n"); call_up_release(trans->callref, CAUSE_NOCHANNEL); trans->callref = 0; cnetz_release(trans, CNETZ_CAUSE_GASSENBESETZT); break; case TRANS_MO_QUEUE: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Phone in queue, but still no channel available, releasing!\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Phone in queue, but still no channel available, releasing!\n"); cnetz_release(trans, CNETZ_CAUSE_GASSENBESETZT); break; case TRANS_MT_DELAY: @@ -859,12 +869,12 @@ void transaction_timeout(struct timer *timer) trans_new_state(trans, TRANS_VAG); break; case TRANS_BQ: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after channel allocation 'Belegung Quittung'\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "No response after channel allocation 'Belegung Quittung'\n"); trans_new_state(trans, TRANS_AF); trans->repeat = 0; break; case TRANS_ZFZ: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after sending random number 'Zufallszahl'\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "No response after sending random number 'Zufallszahl'\n"); if (trans->callref) { call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; @@ -872,7 +882,7 @@ void transaction_timeout(struct timer *timer) cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); break; case TRANS_AP: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after waiting for challenge response 'Autorisierungsparameter'\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "No response after waiting for challenge response 'Autorisierungsparameter'\n"); if (trans->callref) { call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; @@ -882,9 +892,9 @@ void transaction_timeout(struct timer *timer) case TRANS_VHQ_K: case TRANS_VHQ_V: if (cnetz->dsp_mode != DSP_MODE_SPK_V) - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response while holding call 'Quittung Verbindung halten'\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "No response while holding call 'Quittung Verbindung halten'\n"); else - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Lost signal from 'FuTln' (mobile station)\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Lost signal from 'FuTln' (mobile station)\n"); if (trans->callref) { call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; @@ -892,31 +902,25 @@ void transaction_timeout(struct timer *timer) cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); break; case TRANS_DS: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after connect 'Durchschalten'\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "No response after connect 'Durchschalten'\n"); call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); break; case TRANS_RTA: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after ringing order 'Rufton anschalten'\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "No response after ringing order 'Rufton anschalten'\n"); call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); break; case TRANS_AHQ: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after answer 'Abhebequittung'\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "No response after answer 'Abhebequittung'\n"); call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); break; - case TRANS_MFT: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after keepalive order 'Meldeaufruf'\n"); - /* no response to availability check */ - trans->page_failed = 1; - destroy_transaction(trans); - break; default: - PDEBUG_CHAN(DCNETZ, DEBUG_ERROR, "Timeout unhandled in state %" PRIu64 "\n", trans->state); + LOGP_CHAN(DCNETZ, LOGL_ERROR, "Timeout unhandled in state %" PRIu64 "\n", trans->state); } } @@ -948,13 +952,13 @@ void cnetz_sync_frame(cnetz_t *cnetz, double sync, int block) } /* if more than +- one bit out of sync */ if (offset < -0.5 || offset > 0.5) { - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Frame sync offset = %.2f, correcting!\n", offset); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Frame sync offset = %.2f, correcting!\n", offset); fsk_correct_sync(&cnetz->fsk_demod, offset); return; } /* resync by some fraction of received sync error */ - PDEBUG_CHAN(DCNETZ, DEBUG_DEBUG, "Frame sync offset = %.2f, correcting.\n", offset); + LOGP_CHAN(DCNETZ, LOGL_DEBUG, "Frame sync offset = %.2f, correcting.\n", offset); fsk_correct_sync(&cnetz->fsk_demod, offset / 2.0); } @@ -984,6 +988,7 @@ const telegramm_t *cnetz_transmit_telegramm_rufblock(cnetz_t *cnetz) telegramm.fuz_fuvst_nr = si.fuz_fuvst; telegramm.fuz_rest_nr = si.fuz_rest; telegramm.kennung_fufst = si.kennung_fufst; + telegramm.bahn_bs = si.bahn_bs; telegramm.nachbarschafts_prioritaets_bit = si.nachbar_prio; telegramm.bewertung_nach_pegel_und_entfernung = si.bewertung; telegramm.entfernungsangabe_der_fufst = si.entfernung; @@ -992,7 +997,7 @@ const telegramm_t *cnetz_transmit_telegramm_rufblock(cnetz_t *cnetz) telegramm.grenzwert_fuer_umschalten = si.grenz_umschalten; telegramm.grenze_fuer_ausloesen = si.grenz_ausloesen; - trans = search_transaction(cnetz, TRANS_EM | TRANS_UM | TRANS_WBN | TRANS_WBP | TRANS_VAG | TRANS_VAK | TRANS_ATQ | TRANS_VA | TRANS_WSK); + trans = search_transaction(cnetz, TRANS_EM | TRANS_UM | TRANS_WBN | TRANS_WBP | TRANS_VAG | TRANS_VAK | TRANS_ATQ | TRANS_ATQ_IDLE | TRANS_VA | TRANS_WSK); if (trans) { telegramm.futln_nationalitaet = trans->futln_nat; telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst; @@ -1000,18 +1005,18 @@ const telegramm_t *cnetz_transmit_telegramm_rufblock(cnetz_t *cnetz) telegramm.ausloesegrund = trans->release_cause; switch (trans->state) { case TRANS_EM: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending acknowledgment 'Einbuchquittung' to Attachment request.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending acknowledgment 'Einbuchquittung' to Attachment request.\n"); telegramm.opcode = OPCODE_EBQ_R; destroy_transaction(trans); break; case TRANS_UM: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending acknowledgment 'Umbuchquittung' to Roaming requuest.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending acknowledgment 'Umbuchquittung' to Roaming requuest.\n"); telegramm.opcode = OPCODE_UBQ_R; destroy_transaction(trans); break; case TRANS_WBN: wbn: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending call reject 'Wahlbestaetigung negativ'.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending call reject 'Wahlbestaetigung negativ'.\n"); telegramm.opcode = OPCODE_WBN_R; destroy_transaction(trans); cnetz_go_idle(cnetz); @@ -1020,17 +1025,17 @@ wbn: spk = search_free_spk(trans->extended); /* Accept call if channel available, otherwise reject or queue call */ if (spk) { - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending call accept 'Wahlbestaetigung positiv'.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending call accept 'Wahlbestaetigung positiv'.\n"); telegramm.opcode = OPCODE_WBP_R; trans_new_state(trans, TRANS_VAG); } else if (cnetz->warteschlange) { /* queue call if no channel is available, but queue allowed */ - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "No free channel, sending call accept in queue 'Wahlbestaetigung positiv in Warteschlage'.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "No free channel, sending call accept in queue 'Wahlbestaetigung positiv in Warteschlage'.\n"); telegramm.opcode = OPCODE_WWBP_R; trans_new_state(trans, TRANS_MO_QUEUE); - timer_start(&trans->timer, T_VAG2); /* Maximum time to hold queue */ + osmo_timer_schedule(&trans->timer, T_VAG2); /* Maximum time to hold queue */ } else { - PDEBUG(DCNETZ, DEBUG_NOTICE, "No free channel anymore, rejecting call!\n"); + LOGP(DCNETZ, LOGL_NOTICE, "No free channel anymore, rejecting call!\n"); trans_new_state(trans, TRANS_WBN); goto wbn; } @@ -1039,32 +1044,32 @@ wbn: case TRANS_VAK: vak: if (trans->state == TRANS_VAG) { - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending channel assignment 'Verbindungsaufbau gehend'.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending channel assignment 'Verbindungsaufbau gehend'.\n"); telegramm.opcode = OPCODE_VAG_R; } else { - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending channel assignment 'Verbindungsaufbau kommend'.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending channel assignment 'Verbindungsaufbau kommend'.\n"); telegramm.opcode = OPCODE_VAK_R; } trans_new_state(trans, TRANS_BQ); trans->repeat = 0; - timer_start(&trans->timer, 0.150 + 0.0375 * F_BQ); /* two slots + F_BQ frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.150 + 0.0375 * F_BQ)); /* two slots + F_BQ frames */ /* select channel */ spk = search_free_spk(trans->extended); if (!spk) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "No free channel anymore, rejecting call!\n"); + LOGP(DCNETZ, LOGL_NOTICE, "No free channel anymore, rejecting call!\n"); destroy_transaction(trans); cnetz_go_idle(cnetz); break; } if (spk == cnetz) { - PDEBUG(DCNETZ, DEBUG_INFO, "Staying on combined calling + traffic channel %s\n", spk->sender.kanal); + LOGP(DCNETZ, LOGL_INFO, "Staying on combined control + traffic channel %s\n", spk->sender.kanal); } else { - PDEBUG(DCNETZ, DEBUG_INFO, "Assigning phone to traffic channel %s\n", spk->sender.kanal); + LOGP(DCNETZ, LOGL_INFO, "Assigning phone to traffic channel %s\n", spk->sender.kanal); /* sync RX time to current OgK time */ fsk_copy_sync(&spk->fsk_demod, &cnetz->fsk_demod); } /* set channel */ - telegramm.frequenz_nr = atoi(spk->sender.kanal); + telegramm.frequenz_nr = spk->kanal; /* change state to busy */ cnetz_new_state(spk, CNETZ_BUSY); /* schedule switching two slots ahead */ @@ -1076,12 +1081,13 @@ vak: cnetz_flush_other_transactions(spk, trans); break; case TRANS_ATQ: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending acknowledgment 'Quittung fuer Ausloesen des FuTelG im OgK-Betrieb' to release request.\n"); + case TRANS_ATQ_IDLE: + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending acknowledgment 'Quittung fuer Ausloesen des FuTelG im OgK-Betrieb' to release request.\n"); telegramm.opcode = OPCODE_ATQ_R; destroy_transaction(trans); break; case TRANS_VA: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Vorzeitiges Ausloesen' to queued mobile station\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Vorzeitiges Ausloesen' to queued mobile station\n"); telegramm.opcode = OPCODE_VA_R; destroy_transaction(trans); break; @@ -1092,10 +1098,10 @@ vak: trans_new_state(trans, TRANS_VAK); goto vak; } - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "No free channel, sending incoming call in queue 'Warteschglange kommend'.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "No free channel, sending incoming call in queue 'Warteschglange kommend'.\n"); telegramm.opcode = OPCODE_WSK_R; trans_new_state(trans, TRANS_MT_QUEUE); - timer_start(&trans->timer, T_VAK); /* Maximum time to hold queue */ + osmo_timer_schedule(&trans->timer, T_VAK); /* Maximum time to hold queue */ call_up_alerting(trans->callref); default: ; /* LR */ @@ -1114,33 +1120,54 @@ const telegramm_t *cnetz_transmit_telegramm_meldeblock(cnetz_t *cnetz) memset(&telegramm, 0, sizeof(telegramm)); telegramm.opcode = OPCODE_MLR_M; telegramm.max_sendeleistung = cnetz_power2bits(cnetz->ms_power); - telegramm.ogk_verkehrsanteil = 0; /* must be 0 or phone might not respond to messages in different slot */ + telegramm.ogk_verkehrsanteil = 0; /* must be 0 or some phone might not respond to messages in different slots */ telegramm.teilnehmergruppensperre = si.teilnehmergruppensperre; telegramm.anzahl_gesperrter_teilnehmergruppen = si.anzahl_gesperrter_teilnehmergruppen; - telegramm.ogk_vorschlag = CNETZ_OGK_KANAL; + if (ogk_list_count) { + /* if we have alternative OGKs, we cycle through the list and indicate their channels */ + telegramm.ogk_vorschlag = ogk_list[ogk_list_index]->kanal; + if (++ogk_list_index == ogk_list_count) + ogk_list_index = 0; + } else + telegramm.ogk_vorschlag = CNETZ_STD_OGK_KANAL; telegramm.fuz_rest_nr = si.fuz_rest; - trans = search_transaction(cnetz, TRANS_VWG | TRANS_MA); +next_candidate: + trans = search_transaction(cnetz, TRANS_VWG | TRANS_WAF | TRANS_MA | TRANS_MFT); if (trans) { switch (trans->state) { + case TRANS_WAF: + /* no response to dial request (try again or drop connection) */ + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "No response after dialing request 'Wahlaufforderung'\n"); + if (trans->try == N) { + trans_new_state(trans, TRANS_WBN); + goto next_candidate; + } + trans->try++; + trans_new_state(trans, TRANS_VWG); + /* FALLTHRU */ case TRANS_VWG: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending acknowledgment 'Wahlaufforderung' to outging call\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending acknowledgment 'Wahlaufforderung' to outging call\n"); telegramm.opcode = OPCODE_WAF_M; telegramm.futln_nationalitaet = trans->futln_nat; telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst; telegramm.futln_rest_nr = trans->futln_rest; trans_new_state(trans, TRANS_WAF); - timer_start(&trans->timer, 1.0); /* Wait two slot cycles until resending */ break; case TRANS_MA: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending keepalive request 'Meldeaufruf'\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending keepalive request 'Meldeaufruf'\n"); telegramm.opcode = OPCODE_MA_M; telegramm.futln_nationalitaet = trans->futln_nat; telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst; telegramm.futln_rest_nr = trans->futln_rest; trans_new_state(trans, TRANS_MFT); - timer_start(&trans->timer, 1.0); /* Wait two slot cycles until timeout */ break; + case TRANS_MFT: + /* no response to availability check */ + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "No response after keepalive order 'Meldeaufruf'\n"); + trans->page_failed = 1; + destroy_transaction(trans); + goto next_candidate; default: ; /* MLR */ } @@ -1162,20 +1189,22 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo break; rufnummer = telegramm2rufnummer(telegramm); if (si.authentifikationsbit && telegramm->chipkarten_futelg_bit) - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received Attachment 'Einbuchen' message from Subscriber '%s' with chip card's ID %d (vendor id %d, hardware version %d, software version %d)\n", rufnummer, telegramm->kartenkennung, telegramm->herstellerkennung, telegramm->hardware_des_futelg, telegramm->software_des_futelg); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received Attachment 'Einbuchen' message from Subscriber '%s' with chip card's ID %d (vendor id %d, hardware version %d, software version %d)\n", rufnummer, telegramm->kartenkennung, telegramm->herstellerkennung, telegramm->hardware_des_futelg, telegramm->software_des_futelg); else - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received Attachment 'Einbuchen' message from Subscriber '%s' with %s card's security code %d\n", rufnummer, (telegramm->chipkarten_futelg_bit) ? "chip":"magnet", telegramm->sicherungs_code); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received Attachment 'Einbuchen' message from Subscriber '%s' with %s card's security code %d\n", rufnummer, (telegramm->chipkarten_futelg_bit) ? "chip":"magnet", telegramm->sicherungs_code); if (telegramm->erweitertes_frequenzbandbit) - PDEBUG(DCNETZ, DEBUG_INFO, " -> Phone supports extended frequency band\n"); + LOGP(DCNETZ, LOGL_INFO, " -> Phone supports extended frequency band\n"); if (cnetz->state != CNETZ_IDLE) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Ignoring Attachment from subscriber '%s', because we are busy becoming SpK.\n", rufnummer); + LOGP(DCNETZ, LOGL_NOTICE, "Ignoring Attachment from subscriber '%s', because we are busy becoming SpK.\n", rufnummer); break; } - trans = create_transaction(cnetz, TRANS_EM, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, telegramm->chipkarten_futelg_bit, telegramm->erweitertes_frequenzbandbit); + console_inscription(rufnummer); + trans = create_transaction(cnetz, TRANS_EM, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, telegramm->chipkarten_futelg_bit, telegramm->erweitertes_frequenzbandbit, cnetz->rf_level_db); if (!trans) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); + LOGP(DCNETZ, LOGL_ERROR, "Failed to create transaction\n"); break; } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ valid_frame = 1; break; case OPCODE_UM_R: @@ -1183,20 +1212,22 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo break; rufnummer = telegramm2rufnummer(telegramm); if (si.authentifikationsbit && telegramm->chipkarten_futelg_bit) - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received Roaming 'Umbuchen' message from Subscriber '%s' with chip card's ID %d (vendor id %d, hardware version %d, software version %d)\n", rufnummer, telegramm->kartenkennung, telegramm->herstellerkennung, telegramm->hardware_des_futelg, telegramm->software_des_futelg); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received Roaming 'Umbuchen' message from Subscriber '%s' with chip card's ID %d (vendor id %d, hardware version %d, software version %d)\n", rufnummer, telegramm->kartenkennung, telegramm->herstellerkennung, telegramm->hardware_des_futelg, telegramm->software_des_futelg); else - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received Roaming 'Umbuchen' message from Subscriber '%s' with %s card's security code %d\n", rufnummer, (telegramm->chipkarten_futelg_bit) ? "chip":"magnet", telegramm->sicherungs_code); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received Roaming 'Umbuchen' message from Subscriber '%s' with %s card's security code %d\n", rufnummer, (telegramm->chipkarten_futelg_bit) ? "chip":"magnet", telegramm->sicherungs_code); if (telegramm->erweitertes_frequenzbandbit) - PDEBUG(DCNETZ, DEBUG_INFO, " -> Phone supports extended frequency band\n"); + LOGP(DCNETZ, LOGL_INFO, " -> Phone supports extended frequency band\n"); if (cnetz->state != CNETZ_IDLE) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Ignoring Roaming from subscriber '%s', because we are busy becoming SpK.\n", rufnummer); + LOGP(DCNETZ, LOGL_NOTICE, "Ignoring Roaming from subscriber '%s', because we are busy becoming SpK.\n", rufnummer); break; } - trans = create_transaction(cnetz, TRANS_UM, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, telegramm->chipkarten_futelg_bit, telegramm->erweitertes_frequenzbandbit); + console_inscription(rufnummer); + trans = create_transaction(cnetz, TRANS_UM, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, telegramm->chipkarten_futelg_bit, telegramm->erweitertes_frequenzbandbit, cnetz->rf_level_db); if (!trans) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); + LOGP(DCNETZ, LOGL_ERROR, "Failed to create transaction\n"); break; } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ valid_frame = 1; break; case OPCODE_UWG_R: @@ -1204,39 +1235,43 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo if (!match_fuz(telegramm)) break; rufnummer = telegramm2rufnummer(telegramm); - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received Roaming request 'Umbuchantrag' message from Subscriber '%s' on queue\n", rufnummer); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received Roaming request 'Umbuchantrag' message from Subscriber '%s' on queue\n", rufnummer); break; case OPCODE_VWG_R: case OPCODE_SRG_R: + case OPCODE_NUG_R: if (!match_fuz(telegramm)) break; rufnummer = telegramm2rufnummer(telegramm); if (opcode == OPCODE_VWG_R) - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received outgoing Call 'Verbindungswunsch gehend' message from Subscriber '%s'\n", rufnummer); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received outgoing Call 'Verbindungswunsch gehend' message from Subscriber '%s'\n", rufnummer); + else if (opcode == OPCODE_SRG_R) + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received outgoing emergency Call 'Sonderruf gehend' message from Subscriber '%s'\n", rufnummer); else - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received outgoing emergency Call 'Sonderruf gehend' message from Subscriber '%s'\n", rufnummer); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received outgoing Call 'Verbindungswunsch gehend bei Nachbarschaftsunterstuetzung' message from Subscriber '%s'\n", rufnummer); if (cnetz->state != CNETZ_IDLE) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Ignoring Call from subscriber '%s', because we are busy becoming SpK.\n", rufnummer); + LOGP(DCNETZ, LOGL_NOTICE, "Ignoring Call from subscriber '%s', because we are busy becoming SpK.\n", rufnummer); break; } - trans = create_transaction(cnetz, TRANS_VWG, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, -1, telegramm->erweitertes_frequenzbandbit); + trans = create_transaction(cnetz, TRANS_VWG, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, -1, telegramm->erweitertes_frequenzbandbit, cnetz->rf_level_db); if (!trans) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); + LOGP(DCNETZ, LOGL_ERROR, "Failed to create transaction\n"); break; } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ trans->try = 1; valid_frame = 1; break; case OPCODE_WUE_M: trans = search_transaction(cnetz, TRANS_WAF | TRANS_WBP | TRANS_VAG | TRANS_MO_QUEUE); if (!trans) { - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received dialing digits 'Wahluebertragung' message without transaction, ignoring!\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Received dialing digits 'Wahluebertragung' message without transaction (on this OgK), ignoring!\n"); break; } rufnummer = transaction2rufnummer(trans); strncpy(trans->dialing, telegramm->wahlziffern, sizeof(trans->dialing) - 1); - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received dialing digits 'Wahluebertragung' message from Subscriber '%s' to Number '%s'\n", rufnummer, trans->dialing); - timer_stop(&trans->timer); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received dialing digits 'Wahluebertragung' message from Subscriber '%s' to Number '%s'\n", rufnummer, trans->dialing); + osmo_timer_del(&trans->timer); trans_new_state(trans, TRANS_WBP); trans->try = 1; /* try */ valid_frame = 1; @@ -1245,18 +1280,31 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo if (!match_fuz(telegramm)) break; rufnummer = telegramm2rufnummer(telegramm); - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received release 'Ausloesen des FuTelG im OgK-Betrieb bei WS' message from Subscriber '%s'\n", rufnummer); - trans = search_transaction_number(cnetz, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received release 'Ausloesen des FuTelG im OgK-Betrieb bei WS' message from Subscriber '%s'\n", rufnummer); + trans = search_transaction_number_global(telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr); if (!trans) { + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "There is no transaction, so we assume that the phone did not receive previous release.\n"); /* create transaction, in case the phone repeats the release after we have acked it */ - trans = create_transaction(cnetz, TRANS_ATQ, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, -1, -1); + trans = create_transaction(cnetz, TRANS_ATQ_IDLE, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, -1, -1, cnetz->rf_level_db); if (!trans) { - PDEBUG(DCNETZ, DEBUG_ERROR, "Failed to create transaction\n"); + LOGP(DCNETZ, LOGL_ERROR, "Failed to create transaction\n"); break; } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ } else { - timer_stop(&trans->timer); - trans_new_state(trans, TRANS_ATQ); + if (cnetz == trans->cnetz) { + osmo_timer_del(&trans->timer); + trans_new_state(trans, TRANS_ATQ); + } else + if (trans->state == TRANS_ATQ_IDLE) { + trans = create_transaction(cnetz, TRANS_ATQ_IDLE, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr, -1, -1, cnetz->rf_level_db); + if (!trans) { + LOGP(DCNETZ, LOGL_ERROR, "Failed to create transaction\n"); + break; + } + cnetz = trans->cnetz; /* cnetz may change, due to stronger reception on different OgK */ + } else + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Received release 'Ausloesen des FuTelG im OgK-Betrieb bei WS' message without transaction (on this OgK), ignoring!\n"); } valid_frame = 1; break; @@ -1265,16 +1313,16 @@ void cnetz_receive_telegramm_ogk(cnetz_t *cnetz, telegramm_t *telegramm, int blo break; trans = search_transaction_number(cnetz, telegramm->futln_nationalitaet, telegramm->futln_heimat_fuvst_nr, telegramm->futln_rest_nr); if (!trans) { - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received acknowledge 'Meldung Funktelefonteilnehmer' message without transaction, ignoring!\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Received acknowledge 'Meldung Funktelefonteilnehmer' message without transaction (on this OgK), ignoring!\n"); break; } rufnummer = transaction2rufnummer(trans); - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received acknowledge 'Meldung Funktelefonteilnehmer' message from Subscriber '%s'\n", rufnummer); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received acknowledge 'Meldung Funktelefonteilnehmer' message from Subscriber '%s'\n", rufnummer); destroy_transaction(trans); valid_frame = 1; break; default: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received unexpected Telegramm (opcode %d = %s)\n", opcode, telegramm_name(opcode)); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Received unexpected Telegramm (opcode %d = %s)\n", opcode, telegramm_name(opcode)); } if (cnetz->sender.loopback) { @@ -1295,7 +1343,9 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz) { static telegramm_t telegramm; transaction_t *trans = cnetz->trans_list; + int ogk_kanal; cnetz_t *ogk; + int rc; if (!trans) return NULL; @@ -1311,95 +1361,96 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz) telegramm.futln_nationalitaet = trans->futln_nat; telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst; telegramm.futln_rest_nr = trans->futln_rest; - telegramm.frequenz_nr = atoi(cnetz->sender.kanal); + telegramm.frequenz_nr = cnetz->kanal; telegramm.bedingte_genauigkeit_der_fufst = si.genauigkeit; telegramm.zufallszahl = cnetz->challenge; + telegramm.bahn_bs = si.bahn_bs; switch (trans->state) { case TRANS_BQ: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Belegungsquittung' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Belegungsquittung' on traffic channel\n"); telegramm.opcode = OPCODE_BQ_K; - if (++trans->repeat >= 8 && !timer_running(&trans->timer)) { + if (++trans->repeat >= 8 && !osmo_timer_pending(&trans->timer)) { if (cnetz->challenge_valid) { if (si.authentifikationsbit == 0) { - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Cannot authenticate, because base station does not support it. (Authentication disabled in sysinfo.)\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Cannot authenticate, because base station does not support it. (Authentication disabled in sysinfo.)\n"); goto no_auth; } if (trans->futelg_bit == 0) { - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Cannot authenticate, because mobile station does not support it. (Mobile station has magnetic card.)\n"); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Cannot authenticate, because mobile station does not support it. (Mobile station has magnetic card.)\n"); goto no_auth; } - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Perform authentication with subscriber's card, use challenge: 0x%016" PRIx64 "\n", telegramm.zufallszahl); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Perform authentication with subscriber's card, use challenge: 0x%016" PRIx64 "\n", telegramm.zufallszahl); trans_new_state(trans, TRANS_ZFZ); - timer_start(&trans->timer, 0.0375 * F_ZFZ); /* F_ZFZ frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.0375 * F_ZFZ)); /* F_ZFZ frames */ } else { no_auth: trans_new_state(trans, TRANS_VHQ_K); - timer_start(&trans->timer, 0.0375 * F_VHQK); /* F_VHQK frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.0375 * F_VHQK)); /* F_VHQK frames */ } trans->repeat = 0; } break; case TRANS_ZFZ: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Zufallszahl' on traffic channel (0x%016" PRIx64 ").\n", telegramm.zufallszahl); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Zufallszahl' on traffic channel (0x%016" PRIx64 ").\n", telegramm.zufallszahl); telegramm.opcode = OPCODE_ZFZ_K; break; case TRANS_AP: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Quittung Verbindung halten' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Quittung Verbindung halten' on traffic channel\n"); telegramm.opcode = OPCODE_VHQ_K; break; case TRANS_VHQ_K: if (!cnetz->sender.loopback) - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Quittung Verbindung halten' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Quittung Verbindung halten' on traffic channel\n"); telegramm.opcode = OPCODE_VHQ_K; /* continue until next sub frame, so we send DS from first block of next sub frame. */ - 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 && !osmo_timer_pending(&trans->timer)) { /* next sub frame */ if (trans->mo_call) { trans->callref = call_up_setup(transaction2rufnummer(trans), trans->dialing, OSMO_CC_NETWORK_CNETZ_NONE, ""); trans_new_state(trans, TRANS_DS); trans->repeat = 0; - timer_start(&trans->timer, 0.0375 * F_DS); /* F_DS frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.0375 * F_DS)); /* F_DS frames */ } if (trans->mt_call) { trans_new_state(trans, TRANS_RTA); - timer_start(&trans->timer, 0.0375 * F_RTA); /* F_RTA frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.0375 * F_RTA)); /* F_RTA frames */ trans->repeat = 0; call_up_alerting(trans->callref); } } break; case TRANS_DS: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Durchschalten' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Durchschalten' on traffic channel\n"); telegramm.opcode = OPCODE_DSB_K; /* send exactly a sub frame (8 time slots) */ - if ((cnetz->sched_ts & 7) == 7 && cnetz->sched_r_m && !timer_running(&trans->timer)) { + if ((cnetz->sched_ts & 7) == 7 && cnetz->sched_r_m && !osmo_timer_pending(&trans->timer)) { /* next sub frame */ trans_new_state(trans, TRANS_VHQ_V); trans->repeat = 0; cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_V, (cnetz->sched_ts + 1) & 31); #ifndef DEBUG_SPK - timer_start(&trans->timer, 0.075 + 0.6 * F_VHQ); /* one slot + F_VHQ frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.075 + 0.6 * F_VHQ)); /* one slot + F_VHQ frames */ #endif } break; case TRANS_RTA: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Rufton anschalten' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Rufton anschalten' on traffic channel\n"); telegramm.opcode = OPCODE_RTA_K; break; case TRANS_AHQ: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Abhebe Quittung' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Abhebe Quittung' on traffic channel\n"); telegramm.opcode = OPCODE_AHQ_K; if ((cnetz->sched_ts & 7) == 7 && cnetz->sched_r_m) { /* next sub frame */ trans_new_state(trans, TRANS_VHQ_V); trans->repeat = 0; cnetz_set_sched_dsp_mode(cnetz, DSP_MODE_SPK_V, (cnetz->sched_ts + 1) & 31); - timer_start(&trans->timer, 0.075 + 0.6 * F_VHQ); /* one slot + F_VHQ frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.075 + 0.6 * F_VHQ)); /* one slot + F_VHQ frames */ } break; case TRANS_AF: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Ausloesen durch FuFSt' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Ausloesen durch FuFSt' on traffic channel\n"); telegramm.opcode = OPCODE_AF_K; if (++trans->repeat < N_AFKT) break; @@ -1410,7 +1461,7 @@ no_auth: break; } if (trans->try == N) { - PDEBUG(DCNETZ, DEBUG_INFO, "Maximum retries, removing transaction\n"); + LOGP(DCNETZ, LOGL_INFO, "Maximum retries, removing transaction\n"); /* no response to incomming call */ trans->page_failed = 1; cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); @@ -1426,9 +1477,15 @@ no_auth: /* idle channel */ cnetz_go_idle(cnetz); /* alloc ogk again */ - ogk = search_ogk(); + rc = find_db(trans->futln_nat, trans->futln_fuvst, trans->futln_rest, &ogk_kanal, NULL, NULL); + if (rc < 0) { + LOGP(DCNETZ, LOGL_NOTICE, "Cannot find subscriber in database anymore, releasing!\n"); + goto no_ogk; + } + ogk = search_ogk(ogk_kanal); if (!ogk) { - PDEBUG(DCNETZ, DEBUG_NOTICE, "Cannot retry, because currently no OgK available (busy)\n"); + LOGP(DCNETZ, LOGL_NOTICE, "Cannot retry, because currently no OgK available (busy)\n"); +no_ogk: cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); if (trans->callref) call_up_release(trans->callref, CAUSE_NOCHANNEL); @@ -1436,7 +1493,7 @@ no_auth: destroy_transaction(trans); break; } - PDEBUG(DCNETZ, DEBUG_INFO, "Retry to assign channel.\n"); + LOGP(DCNETZ, LOGL_INFO, "Retry to assign channel.\n"); /* attach call to OgK */ link_transaction(trans, ogk); /* change state */ @@ -1447,7 +1504,7 @@ no_auth: trans->try++; break; case TRANS_AT: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Auslosen durch FuFst' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Auslosen durch FuFst' on traffic channel\n"); telegramm.opcode = OPCODE_AF_K; if (++trans->repeat == 1) { destroy_transaction(trans); @@ -1477,11 +1534,11 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) if (!match_futln(telegramm, trans->futln_nat, trans->futln_fuvst, trans->futln_rest)) { break; } - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received allocation 'Belegung' message.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received allocation 'Belegung' message.\n"); valid_frame = 1; if (trans->state != TRANS_BQ) break; - timer_stop(&trans->timer); + osmo_timer_del(&trans->timer); trans->try = 0; break; case OPCODE_DSQ_K: @@ -1491,35 +1548,35 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) if (!match_futln(telegramm, trans->futln_nat, trans->futln_fuvst, trans->futln_rest)) { break; } - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received assignment confirm 'Durchschaltung Quittung' message.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received assignment confirm 'Durchschaltung Quittung' message.\n"); valid_frame = 1; if (trans->state != TRANS_DS) break; cnetz->scrambler = telegramm->betriebs_art; cnetz->scrambler_switch = 0; - timer_stop(&trans->timer); + osmo_timer_del(&trans->timer); break; case OPCODE_ZFZQ_K: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received random number acknowledge 'Zufallszahlquittung' message.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received random number acknowledge 'Zufallszahlquittung' message.\n"); valid_frame = 1; if (trans->state != TRANS_ZFZ) break; if (cnetz->challenge != telegramm->zufallszahl) { - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received random number acknowledge (0x%016" PRIx64 ") does not match the transmitted one (0x%016" PRIx64 "), ignoring!\n", telegramm->zufallszahl, cnetz->challenge); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Received random number acknowledge (0x%016" PRIx64 ") does not match the transmitted one (0x%016" PRIx64 "), ignoring!\n", telegramm->zufallszahl, cnetz->challenge); break; } - timer_stop(&trans->timer); + osmo_timer_del(&trans->timer); trans_new_state(trans, TRANS_AP); - timer_start(&trans->timer, T_AP); /* 750 milliseconds */ + osmo_timer_schedule(&trans->timer, T_AP); /* 750 milliseconds */ break; case OPCODE_AP_K: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received challenge response 'Autorisierungsparameter' message (0x%016" PRIx64 ").\n", telegramm->authorisierungsparameter); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received challenge response 'Autorisierungsparameter' message (0x%016" PRIx64 ").\n", telegramm->authorisierungsparameter); valid_frame = 1; if (trans->state != TRANS_AP) break; /* if authentication response from card does not match */ if (cnetz->response_valid && telegramm->authorisierungsparameter != cnetz->response) { - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received challenge response (0x%016" PRIx64 ") does not match the expected one (0x%016" PRIx64 "), releasing!\n", telegramm->authorisierungsparameter, cnetz->response); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Received challenge response (0x%016" PRIx64 ") does not match the expected one (0x%016" PRIx64 "), releasing!\n", telegramm->authorisierungsparameter, cnetz->response); if (trans->callref) { call_up_release(trans->callref, CAUSE_TEMPFAIL); /* jolly guesses that */ trans->callref = 0; @@ -1527,10 +1584,10 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) cnetz_release(trans, CNETZ_CAUSE_GASSENBESETZT); /* when authentication is not valid */ break; } - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Completed authentication with subscriber's card, challenge response: 0x%016" PRIx64 "\n", telegramm->authorisierungsparameter); - timer_stop(&trans->timer); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Completed authentication with subscriber's card, challenge response: 0x%016" PRIx64 "\n", telegramm->authorisierungsparameter); + osmo_timer_del(&trans->timer); trans_new_state(trans, TRANS_VHQ_K); - timer_start(&trans->timer, 0.0375 * F_VHQK); /* F_VHQK frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.0375 * F_VHQK)); /* F_VHQK frames */ break; case OPCODE_VH_K: if (!match_fuz(telegramm)) { @@ -1539,11 +1596,11 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) if (!match_futln(telegramm, trans->futln_nat, trans->futln_fuvst, trans->futln_rest)) { break; } - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received connection hold 'Verbindung halten' message.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received connection hold 'Verbindung halten' message.\n"); valid_frame = 1; if (trans->state != TRANS_VHQ_K) break; - timer_stop(&trans->timer); + osmo_timer_del(&trans->timer); break; case OPCODE_RTAQ_K: if (!match_fuz(telegramm)) { @@ -1553,10 +1610,10 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) break; } valid_frame = 1; - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received ringback 'Rufton anschalten Quittung' message.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received ringback 'Rufton anschalten Quittung' message.\n"); if (trans->state != TRANS_RTA) break; - timer_start(&trans->timer, 0.0375 * F_RTA); /* F_RTA frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.0375 * F_RTA)); /* F_RTA frames */ break; case OPCODE_AH_K: if (!match_fuz(telegramm)) { @@ -1565,7 +1622,7 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) if (!match_futln(telegramm, trans->futln_nat, trans->futln_fuvst, trans->futln_rest)) { break; } - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received answer frame 'Abheben' message.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received answer frame 'Abheben' message.\n"); valid_frame = 1; /* if already received this frame, or if we are already on VHQ or if we are releasing */ if (trans->state == TRANS_AHQ || trans->state == TRANS_VHQ_K || trans->state == TRANS_VHQ_V || trans->state == TRANS_AF) @@ -1574,7 +1631,7 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) cnetz->scrambler_switch = 0; trans_new_state(trans, TRANS_AHQ); trans->repeat = 0; - timer_stop(&trans->timer); + osmo_timer_del(&trans->timer); call_up_answer(trans->callref, transaction2rufnummer(trans)); break; case OPCODE_AT_K: @@ -1584,21 +1641,21 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) if (!match_futln(telegramm, trans->futln_nat, trans->futln_fuvst, trans->futln_rest)) { break; } - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received release frame 'Ausloesen durch FuTln' message.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received release frame 'Ausloesen durch FuTln' message.\n"); valid_frame = 1; /* if already received this frame, if we are releasing */ if (trans->state == TRANS_AT || trans->state == TRANS_AF) break; trans_new_state(trans, TRANS_AT); trans->repeat = 0; - timer_stop(&trans->timer); + osmo_timer_del(&trans->timer); if (trans->callref) { call_up_release(trans->callref, CAUSE_NORMAL); trans->callref = 0; } break; default: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received unexpected Telegramm (opcode %d = %s)\n", opcode, telegramm_name(opcode)); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Received unexpected Telegramm (opcode %d = %s)\n", opcode, telegramm_name(opcode)); } if (valid_frame) @@ -1617,11 +1674,11 @@ const telegramm_t *cnetz_transmit_telegramm_spk_v(cnetz_t *cnetz) memset(&telegramm, 0, sizeof(telegramm)); - if (cnetz->metering) { - double now = get_time(); - if (!trans->call_start) - trans->call_start = now; - meter = (now - trans->call_start) / (double)cnetz->metering + 1; + if (trans->metering_time) { + /* get end time. if not set, use current time. (still running) */ + double end = (trans->meter_end) ? : get_time(); + /* add one unit, because when metering is started, the first unit is counted. */ + meter = (end - trans->meter_start) / (double)trans->metering_time + 1.0; } telegramm.max_sendeleistung = cnetz_power2bits(cnetz->ms_power); @@ -1634,7 +1691,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_v(cnetz_t *cnetz) telegramm.futln_nationalitaet = trans->futln_nat; telegramm.futln_heimat_fuvst_nr = trans->futln_fuvst; telegramm.futln_rest_nr = trans->futln_rest; - telegramm.frequenz_nr = atoi(cnetz->sender.kanal); + telegramm.frequenz_nr = cnetz->kanal; telegramm.entfernung = si.entfernung; telegramm.bedingte_genauigkeit_der_fufst = si.genauigkeit; telegramm.gueltigkeit_des_gebuehrenstandes = 0; @@ -1643,15 +1700,15 @@ const telegramm_t *cnetz_transmit_telegramm_spk_v(cnetz_t *cnetz) switch (trans->state) { case TRANS_VHQ_V: if ((cnetz->sched_ts & 8) == 0) { /* sub frame 1 and 3 */ - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Quittung Verbindung halten 1' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Quittung Verbindung halten 1' on traffic channel\n"); telegramm.opcode = OPCODE_VHQ1_V; } else { /* sub frame 2 and 4 */ - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Quittung Verbindung halten 2' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Quittung Verbindung halten 2' on traffic channel\n"); telegramm.opcode = OPCODE_VHQ2_V; } break; case TRANS_AF: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending 'Ausloesen durch FuFSt' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending 'Ausloesen durch FuFSt' on traffic channel\n"); telegramm.opcode = OPCODE_AF_V; if (++trans->repeat == N_AFV) { destroy_transaction(trans); @@ -1659,7 +1716,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_v(cnetz_t *cnetz) } break; case TRANS_AT: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Sending acknowledge to 'Ausloesen durch FuTln' on traffic channel\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Sending acknowledge to 'Ausloesen durch FuTln' on traffic channel\n"); telegramm.opcode = OPCODE_AF_V; if (++trans->repeat == 1) { destroy_transaction(trans); @@ -1693,16 +1750,16 @@ void cnetz_receive_telegramm_spk_v(cnetz_t *cnetz, telegramm_t *telegramm) } if (trans->state != TRANS_VHQ_V) break; - timer_start(&trans->timer, 0.6 * F_VHQ); /* F_VHQ frames */ + osmo_timer_schedule(&trans->timer, FLOAT_TO_TIMEOUT(0.6 * F_VHQ)); /* F_VHQ frames */ switch (opcode) { case OPCODE_VH_V: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received supervisory frame 'Verbindung halten' message%s.\n", (telegramm->test_telefonteilnehmer_geraet) ? ", phone is a test-phone" : ""); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received supervisory frame 'Verbindung halten' message%s.\n", (telegramm->test_telefonteilnehmer_geraet) ? ", phone is a test-phone" : ""); break; case OPCODE_USAI_V: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received internal handover request frame 'Umschaltantrag intern' message%s.\n", (telegramm->test_telefonteilnehmer_geraet) ? ", phone is a test-phone" : ""); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received internal handover request frame 'Umschaltantrag intern' message%s.\n", (telegramm->test_telefonteilnehmer_geraet) ? ", phone is a test-phone" : ""); break; case OPCODE_USAE_V: - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received external handover request frame 'Umschaltantrag extern' message%s.\n", (telegramm->test_telefonteilnehmer_geraet) ? ", phone is a test-phone" : ""); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received external handover request frame 'Umschaltantrag extern' message%s.\n", (telegramm->test_telefonteilnehmer_geraet) ? ", phone is a test-phone" : ""); break; } valid_frame = 1; @@ -1723,21 +1780,21 @@ void cnetz_receive_telegramm_spk_v(cnetz_t *cnetz, telegramm_t *telegramm) if (!match_futln(telegramm, trans->futln_nat, trans->futln_fuvst, trans->futln_rest)) { break; } - PDEBUG_CHAN(DCNETZ, DEBUG_INFO, "Received release frame 'Ausloesen durch FuTln' message.\n"); + LOGP_CHAN(DCNETZ, LOGL_INFO, "Received release frame 'Ausloesen durch FuTln' message.\n"); valid_frame = 1; /* if already received this frame, if we are releasing */ if (trans->state == TRANS_AT || trans->state == TRANS_AF) break; trans_new_state(trans, TRANS_AT); trans->repeat = 0; - timer_stop(&trans->timer); + osmo_timer_del(&trans->timer); if (trans->callref) { call_up_release(trans->callref, CAUSE_NORMAL); trans->callref = 0; } break; default: - PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Received unexpected Telegramm (opcode %d = %s)\n", opcode, telegramm_name(opcode)); + LOGP_CHAN(DCNETZ, LOGL_NOTICE, "Received unexpected Telegramm (opcode %d = %s)\n", opcode, telegramm_name(opcode)); } if (valid_frame) |