Harald Welte | f9d449e | 2018-06-24 22:27:47 +0200 | [diff] [blame] | 1 | /* Simple / General implementation of an External USSD Entity using OsmoHLR's GSUP Protocol |
| 2 | * |
| 3 | * The idea is that a test case can simply start an instance of this component in parallel to its |
| 4 | * normal test components. HLR_EUSE_CT will then connect via GSUP to the HLR as the specified EUSE |
| 5 | * name. Any USSD related GSUP message received will be passed to a user-provided call-back |
| 6 | * function, which will return whatever PDU to send in response back to the HLR. |
| 7 | */ |
| 8 | |
| 9 | /* (C) 2018 by Harald Welte <laforge@gnumonks.org> */ |
| 10 | |
| 11 | module HLR_EUSE { |
| 12 | |
| 13 | import from GSUP_Types all; |
| 14 | import from IPA_Emulation all; |
| 15 | |
| 16 | import from General_Types all; |
| 17 | import from Osmocom_Types all; |
| 18 | import from SS_Types all; |
| 19 | import from SS_Templates all; |
| 20 | |
| 21 | /* emulating an external USSD Entity towards OsmoHLR */ |
| 22 | type component HLR_EUSE_CT { |
| 23 | /* Component reference + config of underlying IPA emulation */ |
| 24 | var IPA_Emulation_CT vc_IPA_EUSE; |
| 25 | var IPA_CCM_Parameters ccm_pars; |
| 26 | /* port towards the underlying IPA emulation */ |
| 27 | port IPA_GSUP_PT EUSE; |
| 28 | } |
| 29 | |
| 30 | private function f_init(charstring hlr_ip, uint16_t hlr_gsup_port, charstring name) runs on HLR_EUSE_CT { |
| 31 | var charstring id := "EUSE-" & name; |
| 32 | ccm_pars := c_IPA_default_ccm_pars; |
| 33 | ccm_pars.name := "Osmocom TTCN-3 EUSE Simulator"; |
| 34 | ccm_pars.ser_nr := id; |
| 35 | |
| 36 | vc_IPA_EUSE := IPA_Emulation_CT.create("IPA-" & id); |
| 37 | map(vc_IPA_EUSE:IPA_PORT, system:IPA_CODEC_PT); |
| 38 | connect(vc_IPA_EUSE:IPA_GSUP_PORT, self:EUSE); |
| 39 | vc_IPA_EUSE.start(IPA_Emulation.main_client(hlr_ip, hlr_gsup_port, "", 0, ccm_pars)); |
| 40 | |
| 41 | timer T := 10.0; |
| 42 | T.start; |
| 43 | alt { |
| 44 | [] EUSE.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_UP}) { repeat; } |
| 45 | [] EUSE.receive(ASP_IPA_Event:{up_down := ASP_IPA_EVENT_ID_ACK}) { } |
| 46 | [] T.timeout { |
| 47 | setverdict(fail, "EUSE: Timeout waiting for GSUP IPA Link to come up"); |
| 48 | self.stop; |
| 49 | } |
| 50 | } |
| 51 | } |
| 52 | |
Vadim Yanitskiy | d686a8a | 2018-11-02 02:42:32 +0700 | [diff] [blame] | 53 | type function f_euse_cb(GSUP_PDU rx_pdu) return GSUP_PDU; |
Harald Welte | f9d449e | 2018-06-24 22:27:47 +0200 | [diff] [blame] | 54 | |
Vadim Yanitskiy | d686a8a | 2018-11-02 02:42:32 +0700 | [diff] [blame] | 55 | function f_ss_echo_continue(GSUP_PDU rx_pdu) return GSUP_PDU { |
Harald Welte | f9d449e | 2018-06-24 22:27:47 +0200 | [diff] [blame] | 56 | var GSUP_SessionState ss_next_state; |
Vadim Yanitskiy | d686a8a | 2018-11-02 02:42:32 +0700 | [diff] [blame] | 57 | var GSUP_IeValue ss_ie, state_ie; |
Harald Welte | f9d449e | 2018-06-24 22:27:47 +0200 | [diff] [blame] | 58 | var SS_FacilityInformation dec_fac, rsp_fac; |
| 59 | var octetstring ss_rsp; |
| 60 | |
Daniel Willmann | e2bd04a | 2018-11-06 16:31:27 +0100 | [diff] [blame] | 61 | f_gsup_find_ie(rx_pdu, OSMO_GSUP_SESSION_STATE_IE, state_ie); |
Vadim Yanitskiy | d686a8a | 2018-11-02 02:42:32 +0700 | [diff] [blame] | 62 | var GSUP_SessionState ss_state := state_ie.session_state; |
| 63 | |
Harald Welte | f9d449e | 2018-06-24 22:27:47 +0200 | [diff] [blame] | 64 | f_gsup_find_ie(rx_pdu, OSMO_GSUP_SS_INFO_IE, ss_ie); |
| 65 | dec_fac := dec_SS_FacilityInformation(ss_ie.ss_info); |
| 66 | log("dec_fac: ", dec_fac); |
| 67 | rsp_fac := valueof(ts_SS_USSD_FACILITY_RETURN_RESULT(dec_fac[0].invoke.invokeId.present_, |
| 68 | SS_OP_CODE_PROCESS_USS_REQ, |
| 69 | dec_fac[0].invoke.argument.uSSD_Arg.ussd_DataCodingScheme, |
| 70 | dec_fac[0].invoke.argument.uSSD_Arg.ussd_String)); |
| 71 | ss_rsp := enc_SS_FacilityInformation(rsp_fac); |
| 72 | select (ss_state) { |
| 73 | case (OSMO_GSUP_SESSION_STATE_BEGIN) { ss_next_state := OSMO_GSUP_SESSION_STATE_CONTINUE; } |
| 74 | case (OSMO_GSUP_SESSION_STATE_CONTINUE) { ss_next_state := OSMO_GSUP_SESSION_STATE_END; } |
| 75 | } |
| 76 | return valueof(ts_GSUP_PROC_SS_RES(rx_pdu.ies[0].val.imsi, rx_pdu.ies[1].val.session_id, |
| 77 | ss_next_state, ss_rsp)); |
| 78 | } |
| 79 | |
Vadim Yanitskiy | d686a8a | 2018-11-02 02:42:32 +0700 | [diff] [blame] | 80 | function f_ss_echo(GSUP_PDU rx_pdu) return GSUP_PDU { |
Harald Welte | f9d449e | 2018-06-24 22:27:47 +0200 | [diff] [blame] | 81 | var GSUP_IeValue ss_ie; |
| 82 | var SS_FacilityInformation dec_fac, rsp_fac; |
| 83 | var octetstring ss_rsp; |
| 84 | |
| 85 | f_gsup_find_ie(rx_pdu, OSMO_GSUP_SS_INFO_IE, ss_ie); |
| 86 | dec_fac := dec_SS_FacilityInformation(ss_ie.ss_info); |
| 87 | log("dec_fac: ", dec_fac); |
| 88 | rsp_fac := valueof(ts_SS_USSD_FACILITY_RETURN_RESULT(dec_fac[0].invoke.invokeId.present_, |
| 89 | SS_OP_CODE_PROCESS_USS_REQ, |
| 90 | dec_fac[0].invoke.argument.uSSD_Arg.ussd_DataCodingScheme, |
| 91 | dec_fac[0].invoke.argument.uSSD_Arg.ussd_String)); |
| 92 | ss_rsp := enc_SS_FacilityInformation(rsp_fac); |
| 93 | return valueof(ts_GSUP_PROC_SS_RES(rx_pdu.ies[0].val.imsi, rx_pdu.ies[1].val.session_id, |
| 94 | OSMO_GSUP_SESSION_STATE_END, ss_rsp)); |
| 95 | } |
| 96 | |
| 97 | /* main function for handling mobile-originated USSD via GSUP */ |
| 98 | function f_main_mo(charstring hlr_ip, uint16_t hlr_gsup_port, charstring name, f_euse_cb cb_fn) |
| 99 | runs on HLR_EUSE_CT { |
| 100 | var GSUP_PDU rx_pdu, tx_pdu; |
| 101 | |
| 102 | f_init(hlr_ip, hlr_gsup_port, name); |
| 103 | |
| 104 | while (true) { |
| 105 | alt { |
Vadim Yanitskiy | d686a8a | 2018-11-02 02:42:32 +0700 | [diff] [blame] | 106 | [] EUSE.receive(tr_GSUP_PROC_SS_REQ(?, ?, ?)) -> value rx_pdu { |
| 107 | EUSE.send(cb_fn.apply(rx_pdu)); |
Harald Welte | f9d449e | 2018-06-24 22:27:47 +0200 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | |
| 111 | [] EUSE.receive { |
| 112 | setverdict(fail, "EUSE: Unexpected Rx from HLR"); |
| 113 | self.stop; |
| 114 | } |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | |
| 120 | } |