HLR: Add HLR_EUSE.ttcn to implement minimal external USSD Entity

As OsmoHLR is getting support for external USSD Entities (EUSEs),
we have to implement this function in the test logic in order to
test it.

Change-Id: Ibab210b06abfd5a21e81c7f7fbe574c4f67414a0
This commit is contained in:
Harald Welte 2018-06-24 22:27:47 +02:00
parent e490438672
commit f9d449edd6
2 changed files with 135 additions and 0 deletions

124
hlr/HLR_EUSE.ttcn Normal file
View File

@ -0,0 +1,124 @@
/* Simple / General implementation of an External USSD Entity using OsmoHLR's GSUP Protocol
*
* The idea is that a test case can simply start an instance of this component in parallel to its
* normal test components. HLR_EUSE_CT will then connect via GSUP to the HLR as the specified EUSE
* name. Any USSD related GSUP message received will be passed to a user-provided call-back
* function, which will return whatever PDU to send in response back to the HLR.
*/
/* (C) 2018 by Harald Welte <laforge@gnumonks.org> */
module HLR_EUSE {
import from GSUP_Types all;
import from IPA_Emulation all;
import from General_Types all;
import from Osmocom_Types all;
import from SS_Types all;
import from SS_Templates all;
/* emulating an external USSD Entity towards OsmoHLR */
type component HLR_EUSE_CT {
/* Component reference + config of underlying IPA emulation */
var IPA_Emulation_CT vc_IPA_EUSE;
var IPA_CCM_Parameters ccm_pars;
/* port towards the underlying IPA emulation */
port IPA_GSUP_PT EUSE;
}
private function f_init(charstring hlr_ip, uint16_t hlr_gsup_port, charstring name) runs on HLR_EUSE_CT {
var charstring id := "EUSE-" & name;
ccm_pars := c_IPA_default_ccm_pars;
ccm_pars.name := "Osmocom TTCN-3 EUSE Simulator";
ccm_pars.ser_nr := id;
vc_IPA_EUSE := IPA_Emulation_CT.create("IPA-" & id);
map(vc_IPA_EUSE:IPA_PORT, system:IPA_CODEC_PT);
connect(vc_IPA_EUSE:IPA_GSUP_PORT, self:EUSE);
vc_IPA_EUSE.start(IPA_Emulation.main_client(hlr_ip, hlr_gsup_port, "", 0, ccm_pars));
timer T := 10.0;
T.start;
alt {
[] EUSE.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) { repeat; }
[] EUSE.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) { }
[] T.timeout {
setverdict(fail, "EUSE: Timeout waiting for GSUP IPA Link to come up");
self.stop;
}
}
}
type function f_euse_cb(GSUP_SessionState ss_state, GSUP_PDU rx_pdu) return GSUP_PDU;
function f_ss_echo_continue(GSUP_SessionState ss_state, GSUP_PDU rx_pdu) return GSUP_PDU {
var GSUP_SessionState ss_next_state;
var GSUP_IeValue ss_ie;
var SS_FacilityInformation dec_fac, rsp_fac;
var octetstring ss_rsp;
f_gsup_find_ie(rx_pdu, OSMO_GSUP_SS_INFO_IE, ss_ie);
dec_fac := dec_SS_FacilityInformation(ss_ie.ss_info);
log("dec_fac: ", dec_fac);
rsp_fac := valueof(ts_SS_USSD_FACILITY_RETURN_RESULT(dec_fac[0].invoke.invokeId.present_,
SS_OP_CODE_PROCESS_USS_REQ,
dec_fac[0].invoke.argument.uSSD_Arg.ussd_DataCodingScheme,
dec_fac[0].invoke.argument.uSSD_Arg.ussd_String));
ss_rsp := enc_SS_FacilityInformation(rsp_fac);
select (ss_state) {
case (OSMO_GSUP_SESSION_STATE_BEGIN) { ss_next_state := OSMO_GSUP_SESSION_STATE_CONTINUE; }
case (OSMO_GSUP_SESSION_STATE_CONTINUE) { ss_next_state := OSMO_GSUP_SESSION_STATE_END; }
}
return valueof(ts_GSUP_PROC_SS_RES(rx_pdu.ies[0].val.imsi, rx_pdu.ies[1].val.session_id,
ss_next_state, ss_rsp));
}
function f_ss_echo(GSUP_SessionState ss_state, GSUP_PDU rx_pdu) return GSUP_PDU {
var GSUP_IeValue ss_ie;
var SS_FacilityInformation dec_fac, rsp_fac;
var octetstring ss_rsp;
f_gsup_find_ie(rx_pdu, OSMO_GSUP_SS_INFO_IE, ss_ie);
dec_fac := dec_SS_FacilityInformation(ss_ie.ss_info);
log("dec_fac: ", dec_fac);
rsp_fac := valueof(ts_SS_USSD_FACILITY_RETURN_RESULT(dec_fac[0].invoke.invokeId.present_,
SS_OP_CODE_PROCESS_USS_REQ,
dec_fac[0].invoke.argument.uSSD_Arg.ussd_DataCodingScheme,
dec_fac[0].invoke.argument.uSSD_Arg.ussd_String));
ss_rsp := enc_SS_FacilityInformation(rsp_fac);
return valueof(ts_GSUP_PROC_SS_RES(rx_pdu.ies[0].val.imsi, rx_pdu.ies[1].val.session_id,
OSMO_GSUP_SESSION_STATE_END, ss_rsp));
}
/* main function for handling mobile-originated USSD via GSUP */
function f_main_mo(charstring hlr_ip, uint16_t hlr_gsup_port, charstring name, f_euse_cb cb_fn)
runs on HLR_EUSE_CT {
var GSUP_PDU rx_pdu, tx_pdu;
f_init(hlr_ip, hlr_gsup_port, name);
while (true) {
alt {
[] EUSE.receive(tr_GSUP_PROC_SS_REQ(?, ?, OSMO_GSUP_SESSION_STATE_BEGIN)) -> value rx_pdu {
EUSE.send(cb_fn.apply(OSMO_GSUP_SESSION_STATE_BEGIN, rx_pdu));
}
[] EUSE.receive(tr_GSUP_PROC_SS_REQ(?, ?, OSMO_GSUP_SESSION_STATE_CONTINUE)) -> value rx_pdu {
EUSE.send(cb_fn.apply(OSMO_GSUP_SESSION_STATE_CONTINUE, rx_pdu));
}
[] EUSE.receive(tr_GSUP_PROC_SS_REQ(?, ?, OSMO_GSUP_SESSION_STATE_END)) -> value rx_pdu {
EUSE.send(cb_fn.apply(OSMO_GSUP_SESSION_STATE_END, rx_pdu));
}
[] EUSE.receive {
setverdict(fail, "EUSE: Unexpected Rx from HLR");
self.stop;
}
}
}
}
}

View File

@ -687,4 +687,15 @@ template GSUP_PDU tr_GSUP_PROC_SS_ERR(
}
);
function f_gsup_find_ie(GSUP_PDU msg, GSUP_IEI iei, out GSUP_IeValue ret) return boolean {
for (var integer i := 0; i < sizeof(msg.ies); i := i+1) {
if (msg.ies[i].tag == iei) {
ret := msg.ies[i].val;
return true;
}
}
return false;
}
} with { encode "RAW"; variant "FIELDORDER(msb)" }