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
This commit is contained in:
Dennis Grunert 2024-01-18 01:41:15 +01:00
parent b79127209c
commit bd72569a0e
2 changed files with 52 additions and 21 deletions

View File

@ -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 */

View File

@ -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