From bd72569a0ea01e84818243e28dbc29f654c6345d Mon Sep 17 00:00:00 2001 From: Dennis Grunert Date: Thu, 18 Jan 2024 01:41:15 +0100 Subject: [PATCH] Send AOC-E facility on call termination; fixed AOC-E encoding function - Some ISDN terminals require AOC-E information to increment their internal unit counter. Tested with Siemens Profiset 51 - Fixed encodeAOCEChargingUnitOperation() producing incorrect AOC-E IE. Tested with K1297 protocol analyser, protocol ETSI-SupplementalServices --- src/isdn/dss1.c | 50 +++++++++++++++++++++++++-------- src/libmisdnuser/suppserv/fac.c | 23 ++++++++------- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/isdn/dss1.c b/src/isdn/dss1.c index d9b5a8c..42b54b3 100644 --- a/src/isdn/dss1.c +++ b/src/isdn/dss1.c @@ -184,7 +184,7 @@ static void split_3pty(call_t *call) } } -/* Generate AOC-S facility IE from metering information */ +/* Generate AOC-S facility msg from metering information */ #define AOCS_CURRENCY_AMOUNT_PER_UNIT 5 static void generate_aocs_fac(call_t *call) { @@ -216,7 +216,7 @@ static void generate_aocs_fac(call_t *call) fac.u.inv.o.AOCcuril.currencyInfoCount = 2; fac.u.inv.o.AOCcuril.currencyInfo[0].chargedItem = 0x00; // BasicComm fac.u.inv.o.AOCcuril.currencyInfo[0].currencyType = 0xA2; // FlatRate - strncpy(fac.u.inv.o.AOCcuril.currencyInfo[0].FlatRateCurrency.currency, "EUR", 10); // Currency value + strncpy((char *)fac.u.inv.o.AOCcuril.currencyInfo[0].FlatRateCurrency.currency, "EUR", 10); // Currency value fac.u.inv.o.AOCcuril.currencyInfo[0].FlatRateCurrency.currencyAmount = AOCS_CURRENCY_AMOUNT_PER_UNIT * call->metering_connect_units; fac.u.inv.o.AOCcuril.currencyInfo[0].FlatRateCurrency.multiplier = 1; // 1/100 EUR fac.u.inv.o.AOCcuril.currencyInfo[1].chargedItem = 0x02; // CallSetup @@ -227,7 +227,7 @@ static void generate_aocs_fac(call_t *call) fac.u.inv.o.AOCcuril.currencyInfoCount = 2; fac.u.inv.o.AOCcuril.currencyInfo[0].chargedItem = 0x00; // BasicComm fac.u.inv.o.AOCcuril.currencyInfo[0].currencyType = 0xA1; // DurationCurrency - strncpy(fac.u.inv.o.AOCcuril.currencyInfo[0].durationCurrency.currency, "EUR", 10); // Currency value + strncpy((char *)fac.u.inv.o.AOCcuril.currencyInfo[0].durationCurrency.currency, "EUR", 10); // Currency value fac.u.inv.o.AOCcuril.currencyInfo[0].durationCurrency.currencyAmount = AOCS_CURRENCY_AMOUNT_PER_UNIT; fac.u.inv.o.AOCcuril.currencyInfo[0].durationCurrency.multiplier = 1; // 1/100 EUR fac.u.inv.o.AOCcuril.currencyInfo[0].durationCurrency.typeOfCharging = 1; // StepFunction @@ -240,7 +240,7 @@ static void generate_aocs_fac(call_t *call) /* Additional CallSetup charge */ PDEBUG(DISDN, DEBUG_DEBUG, "AOC-S currencyInfoList: BasicComm DurationCurrency %d/100 EUR per %d/100 seconds; CallSetup FlatRate %d/100 EUR\n", AOCS_CURRENCY_AMOUNT_PER_UNIT, call->metering_unit_period_decisecs * 10, AOCS_CURRENCY_AMOUNT_PER_UNIT * (call->metering_connect_units - 1)); fac.u.inv.o.AOCcuril.currencyInfo[1].currencyType = 0xA2; // FlatRate - strncpy(fac.u.inv.o.AOCcuril.currencyInfo[1].FlatRateCurrency.currency, "EUR", 10); // Currency value + strncpy((char *)fac.u.inv.o.AOCcuril.currencyInfo[1].FlatRateCurrency.currency, "EUR", 10); // Currency value fac.u.inv.o.AOCcuril.currencyInfo[1].FlatRateCurrency.currencyAmount = AOCS_CURRENCY_AMOUNT_PER_UNIT * (call->metering_connect_units - 1); fac.u.inv.o.AOCcuril.currencyInfo[1].FlatRateCurrency.multiplier = 1; // 1/100 EUR } @@ -260,6 +260,32 @@ static void generate_aocs_fac(call_t *call) } } +/* Generate AOC-E facility msg */ +static void generate_aoce_fac(call_t *call) +{ + uint8_t fac_ie[256]; + struct asn1_parm fac; + struct l3_msg *l3m; + + PDEBUG(DISDN, DEBUG_DEBUG, "Sending AOC-E facility, total_units=%d\n", call->metering_total_units); + + timer_start(&call->aocd_unit_timer, (double)call->metering_unit_period_decisecs / (double)10); + + memset(&fac, 0, sizeof(fac)); + fac.Valid = 1; + fac.comp = CompInvoke; + fac.u.inv.invokeId = 2; /* doesn't matter since no response is expected */ + fac.u.inv.operationValue = Fac_AOCEChargingUnit; + fac.u.inv.o.AOCchu.recordedUnits = call->metering_total_units; + + encodeFac(fac_ie, &fac); + + // sending facility + l3m = create_l3msg(); + enc_ie_facility(l3m, fac_ie + 2, fac_ie[1]); + call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_FACILITY, call->l3_pid, l3m); +} + /* AOC-D timer callback */ static void aocd_timer_cb(void *data) { @@ -876,12 +902,13 @@ void disconnect_ind(call_t *call, uint32_t pid, struct l3_msg *l3m) /* send message to osmo-cc */ osmo_cc_ll_msg(&call->isdn_ep->cc_ep, call->cc_callref, msg); - /* stop AOC-D timer */ + /* stop AOC-D timer and send AOC-E facility */ if(call->aocd_unit_timer_started) { timer_stop(&call->aocd_unit_timer); timer_exit(&call->aocd_unit_timer); call->aocd_unit_timer_started = 0; + generate_aoce_fac(call); } } @@ -2508,18 +2535,19 @@ void disc_req(call_t *call, uint32_t pid, osmo_cc_msg_t *msg) enc_ie_display(l3m, display); } - /* stop AOC-D timer */ + new_state(call, ISDN_STATE_OUT_DISCONNECT); + + /* send message to ISDN */ + call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_DISCONNECT, call->l3_pid, l3m); + + /* stop AOC-D timer and send AOC-E facility */ if(call->aocd_unit_timer_started) { timer_stop(&call->aocd_unit_timer); timer_exit(&call->aocd_unit_timer); call->aocd_unit_timer_started = 0; + generate_aoce_fac(call); } - - new_state(call, ISDN_STATE_OUT_DISCONNECT); - - /* send message to ISDN */ - call->isdn_ep->ml3->to_layer3(call->isdn_ep->ml3, MT_DISCONNECT, call->l3_pid, l3m); } /* CC-RELEASE REQUEST */ diff --git a/src/libmisdnuser/suppserv/fac.c b/src/libmisdnuser/suppserv/fac.c index f4ea7d7..c528f44 100644 --- a/src/libmisdnuser/suppserv/fac.c +++ b/src/libmisdnuser/suppserv/fac.c @@ -239,7 +239,7 @@ static int encodeAOCSChargingUnitOperation(__u8 * dest, const struct asn1_parm * ci_len++; p[i++] = 0x81; // CurrencySpec ci_len++; c_len++; - cval_len = strlen(currinfolist->currencyInfo[ci].durationCurrency.currency); + cval_len = strlen((char *)currinfolist->currencyInfo[ci].durationCurrency.currency); if(cval_len > 10) cval_len = 10; p[i++] = cval_len; @@ -341,7 +341,7 @@ static int encodeAOCSChargingUnitOperation(__u8 * dest, const struct asn1_parm * ci_len++; p[i++] = 0x81; // CurrencySpec ci_len++; c_len++; - cval_len = strlen(currinfolist->currencyInfo[ci].FlatRateCurrency.currency); + cval_len = strlen((char *)currinfolist->currencyInfo[ci].FlatRateCurrency.currency); if(cval_len > 10) cval_len = 10; p[i++] = cval_len; @@ -481,15 +481,14 @@ static int encodeAOCEChargingUnitOperation(__u8 * dest, const struct asn1_parm * p[i++] = 0x02; // Operation Tag p[i++] = 0x01; // Tag Length p[i++] = Fac_AOCEChargingUnit; // Operation Value - p[i++] = 0xa1; // APDU - p[i++] = 0x30; + p[i++] = 0x30; // ChargingUnitInfo + p[i++] = (0x0b + len); // Length + p[i++] = 0x30; // specificChargingUnits p[i++] = (0x09 + len); // Length - p[i++] = 0xa1; // APDU - p[i++] = (0x04 + len); // Length - p[i++] = 0x30; + p[i++] = 0x30; // recordedUnits p[i++] = (0x02 + len); - p[i++] = 0x02; - p[i++] = 0x02; // AOC-E so Total + p[i++] = 0x02; // recordedNumberOfUnits + p[i++] = len; // Recorded units could take up as much as 3 bytes (0xFFFFFF) p[i] = numberOfUnits & 0xFF; @@ -499,7 +498,11 @@ static int encodeAOCEChargingUnitOperation(__u8 * dest, const struct asn1_parm * p[i+2] = (numberOfUnits >> 16) & 0xFF; i += len; - p[1] = (AOCE_CHARGE_UNIT_IE_LENGTH + len); // IE Payload Length + p[i++] = 0x82; // AOCEBillingId + p[i++] = 0x01; // Length + p[i++] = 0x00; // normalCharging + + p[1] = i - 2; // IE Payload Length p[4] = p[1] - 3; // Invoke Component Length result = p[1] + 2; // Total Length of IE