diff options
author | Pau Espin Pedrol <pespin@sysmocom.de> | 2021-11-29 16:21:26 +0100 |
---|---|---|
committer | laforge <laforge@osmocom.org> | 2021-12-15 14:23:23 +0000 |
commit | 32fb54e61059ded6dd1695447e9dee2d7a2f21c4 (patch) | |
tree | 28099425a7e9fb3a7410f073bac35aa45bce34c2 | |
parent | a6bbb8c45d00471e09d8890f6a402280ad7d600f (diff) |
hnodeb: Add audio SAPI
Change-Id: I20544f67c2450bc3cd4bcb3ee638de1958bf5783
-rw-r--r-- | hnodeb/HNBGW_ConnectionHandler.ttcn | 49 | ||||
-rw-r--r-- | hnodeb/HNB_Tests.ttcn | 83 | ||||
-rw-r--r-- | library/HNBLLIF_Templates.ttcn | 119 | ||||
-rw-r--r-- | library/HNBLLIF_Types.ttcn | 136 |
4 files changed, 384 insertions, 3 deletions
diff --git a/hnodeb/HNBGW_ConnectionHandler.ttcn b/hnodeb/HNBGW_ConnectionHandler.ttcn index 554c35fe..3c4bc6f4 100644 --- a/hnodeb/HNBGW_ConnectionHandler.ttcn +++ b/hnodeb/HNBGW_ConnectionHandler.ttcn @@ -27,6 +27,9 @@ import from HNBAP_Templates all; import from Iuh_Emulation all; +import from RTP_Types all; +import from RTP_Emulation all; + import from HNBLLIF_CodecPort all; import from HNBLLIF_Types all; import from HNBLLIF_Templates all; @@ -40,6 +43,9 @@ type component HNBGW_ConnHdlr extends StatsD_ConnHdlr { port HNBLLIF_CODEC_PT LLSK; var integer g_llsk_conn_id; + var RTP_Emulation_CT vc_RTPEM; + port RTPEM_CTRL_PT RTPEM_CTRL; + port RTPEM_DATA_PT RTPEM_DATA; var TestHdlrParams g_pars; var boolean g_vty_initialized := false; @@ -102,6 +108,13 @@ function f_start_hnbllif(HNBLLIF_CODEC_PT pt, charstring id, charstring hnbllif_ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for HNBLLIF HELLO.REQ SAPI=IUH"); } } + pt.send(t_SD_HNBLLIF(hnbllif_conn_id, ts_HNBLLIF_CTL_HELLO_REQ(HNBLL_IF_SAPI_AUDIO, 0))); + alt { + [] as_hnbllif_hello_cnf(pt, hnbllif_conn_id, last_hello_cnf, HNBLL_IF_SAPI_AUDIO, 0); + [] T.timeout { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for HNBLLIF HELLO.REQ SAPI=AUDIO"); + } + } } type record TestHdlrParams { @@ -109,6 +122,7 @@ type record TestHdlrParams { charstring hnbgw_addr, charstring hnodeb_addr, integer hnbgw_port, + integer hnbgw_rtp_port, uint16_t rnc_id, charstring hNB_Identity_Info, uint16_t mcc, @@ -126,6 +140,7 @@ template (value) TestHdlrParams t_def_TestHdlrPars := { hnbgw_addr := "127.0.0.1", hnodeb_addr := "127.0.0.1", hnbgw_port := 29169, + hnbgw_rtp_port := 9000, rnc_id := 23, hNB_Identity_Info := "OsmoHNodeB", mcc := 1, @@ -185,6 +200,38 @@ runs on HNBGW_ConnHdlr { HNBAP.send(ts_HNBAP_HNBRegisterAccept(g_pars.rnc_id)); } - +/* Initialize and start the RTP emulation component for a ConnHdlr */ +function f_HNBGW_rtpem_activate(inout octetstring payload, + HostName remote_host, + PortNumber remote_port, + RtpemConfig cfg := c_RtpemDefaultCfg, + RtpemMode mode := RTPEM_MODE_BIDIR) +runs on HNBGW_ConnHdlr { + /* Step 0: initialize, connect and start the emulation component */ + vc_RTPEM := RTP_Emulation_CT.create(testcasename() & "-RTPEM"); + map(vc_RTPEM:RTP, system:RTP); + map(vc_RTPEM:RTCP, system:RTCP); + connect(vc_RTPEM:CTRL, self:RTPEM_CTRL); + connect(vc_RTPEM:DATA, self:RTPEM_DATA); + vc_RTPEM.start(RTP_Emulation.f_main()); + + /* Configure the RTP parameters (TCH/FS). TODO: IuUP */ + var integer payload_len := 33; + var octetstring hdr := 'D0'O; + + /* Pad the payload to conform the expected length */ + payload := f_pad_oct(hdr & payload, payload_len, '00'O); + cfg.tx_fixed_payload := payload; + f_rtpem_configure(RTPEM_CTRL, cfg); + + /* Bind the RTP emulation to the configured address */ + f_rtpem_bind(RTPEM_CTRL, g_pars.hnbgw_addr, g_pars.hnbgw_rtp_port); + + /* Connect to the IUT's address/port parsed from CRCX ACK */ + f_rtpem_connect(RTPEM_CTRL, remote_host, remote_port); + + /* Set the given RTP emulation mode */ + f_rtpem_mode(RTPEM_CTRL, mode); +} } diff --git a/hnodeb/HNB_Tests.ttcn b/hnodeb/HNB_Tests.ttcn index 59dd1ee2..05cd2bf5 100644 --- a/hnodeb/HNB_Tests.ttcn +++ b/hnodeb/HNB_Tests.ttcn @@ -24,6 +24,7 @@ import from Misc_Helpers all; import from General_Types all; import from Osmocom_Types all; import from IPL4asp_Types all; +import from Native_Functions all; import from Osmocom_CTRL_Functions all; import from Osmocom_CTRL_Types all; @@ -44,6 +45,9 @@ import from RUA_Templates all; import from HNBGW_ConnectionHandler all; import from Iuh_Emulation all; +import from RTP_Types all; +import from RTP_Emulation all; + import from HNBLLIF_CodecPort all; import from HNBLLIF_Types all; import from HNBLLIF_Templates all; @@ -63,6 +67,7 @@ const hexstring ranap_cm_service_req := '001340400000060003400100000f40060000f11 const hexstring ranap_auth_req := '00144032000002001040262505120217dc146aeac56cb5ff6d5fb51f47f19220108ca5a6d0c8110000b9e9272498872764003b400100'H; const hexstring ranap_auth_resp := '001440140000010010400d0c0554ccbdd0302104002f3ae4'H; const hexstring ranap_paging := '000e401e0000030003400100001740095000010100000000f10040400500b6cf4773'H; +const hexstring ranap_rab_ass_req := '0000005900000100364052000001003500487824cd80102fa7201a2c0000f44c080a028000514000272028140067400000222814003c40000000503d02000227c03500010a0901a200000000000000000000000000401f4a0000400100'H; const hexstring iu_release_compl := '20010003000000'H; type component test_CT extends CTRL_Adapter_CT { @@ -277,11 +282,89 @@ testcase TC_paging() runs on test_CT { f_shutdown_helper(); } +private function f_tc_cs_mo_call(charstring id) runs on HNBGW_ConnHdlr { + const integer context_id := 30; + const bitstring context_id_bstr := '000000000000000000011110'B; /* encoded context_id */ + const Establishment_Cause est_cause := normal_call; + var HNBLLIF_send_data sd; + var PDU_RTP rtp_pdu; + var octetstring rtp_payload; + var HostName hnodeb_rtp_addr; + var PortNumber hnodeb_rtp_port; + timer Tu; + + f_handle_hnbap_hnb_register_req(); + + LLSK.receive(f_llsk_rx(tr_HNBLLIF_IUH_CONFIGURE_IND(g_pars.mcc, g_pars.mnc, g_pars.cell_identity, + g_pars.lac, g_pars.rac, g_pars.sac, g_pars.rnc_id))); + + /* Now an UE attempts CM Service Request: */ + LLSK.send(f_llsk_tx(ts_HNBLLIF_IUH_CONN_ESTABLISH_REQ(context_id, 0, enum2int(est_cause), hex2oct(ranap_cm_service_req)))); + /* The related RUA Connect + RANAP message is received on Iuh: */ + RUA.receive(tr_RUA_Connect(cs_domain, context_id_bstr, est_cause, hex2oct(ranap_cm_service_req))); + + /* Now HNBGW answers with RUA-DirectTransfer(RANAP-RabASsReq) */ + RUA.send(ts_RUA_DirectTransfer(cs_domain, context_id_bstr, hex2oct(ranap_rab_ass_req))); + + /* Now on LLSK first the Conn establishment is confirmed and then we receive data */ + LLSK.receive(f_llsk_rx(tr_HNBLLIF_IUH_CONN_ESTABLISH_CNF(context_id, 0, 0))); + LLSK.receive(f_llsk_rx(tr_HNBLLIF_IUH_CONN_DATA_IND(context_id, 0, hex2oct(ranap_rab_ass_req)))); + + /* Now LLSK provides the remote TransportLayerAddress from RabAssReq and asks SUT to provide a local address: */ + LLSK.send(f_llsk_tx(ts_HNBLLIF_AUDIO_CONN_ESTABLISH_REQ(context_id, g_pars.hnbgw_rtp_port, HNBLL_IF_ADDR_TYPE_IPV4, + f_HNBLLIF_Addr(HNBLL_IF_ADDR_TYPE_IPV4, g_pars.hnbgw_addr)))); + LLSK.receive(f_llsk_rx(tr_HNBLLIF_AUDIO_CONN_ESTABLISH_CNF(context_id, 0, ?, HNBLL_IF_ADDR_TYPE_IPV4, ?))) -> value sd; + + hnodeb_rtp_addr := f_inet_ntoa(sd.data.u.audio.u.conn_establish.u.cnf.local_addr); + if (not match(g_pars.hnodeb_addr, hnodeb_rtp_addr)) { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "hnodeb RTP local address doesn't match expectations"); + } + hnodeb_rtp_port := sd.data.u.audio.u.conn_establish.u.cnf.local_rtp_port; + rtp_payload := f_rnd_octstring(6); + f_HNBGW_rtpem_activate(rtp_payload, hnodeb_rtp_addr, hnodeb_rtp_port); + /* Make sure that Uplink frames are received at the HNBGW */ + RTPEM_DATA.clear; + LLSK.send(f_llsk_tx(ts_HNBLLIF_AUDIO_CONN_DATA_REQ(context_id, rtp_payload))); + Tu.start(2.0); + alt { + [] RTPEM_DATA.receive(PDU_RTP:?) -> value rtp_pdu { + if (rtp_pdu.data != rtp_payload) { + log("Unexpected RTP payload received!"); + repeat; + } + } + [] RTPEM_DATA.receive { repeat; } + [] Tu.timeout { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for Uplink speech frames"); + } + } + Tu.stop; + /* We should also have received some RTP from the HNBGW: */ + LLSK.receive(f_llsk_rx(tr_HNBLLIF_AUDIO_CONN_DATA_IND(context_id, rtp_payload))); + + f_rtpem_mode(RTPEM_CTRL, RTPEM_MODE_NONE); + + LLSK.send(f_llsk_tx(ts_HNBLLIF_AUDIO_CONN_RELEASE_REQ(context_id))); + + /* UE sends Iu Release Complete to release the conn */ + LLSK.send(f_llsk_tx(ts_HNBLLIF_IUH_CONN_RELEASE_REQ(context_id, 0, 0, 0, hex2oct(iu_release_compl)))); + RUA.receive(tr_RUA_Disconnect(cs_domain, context_id_bstr, ts_RUA_Cause(normal), hex2oct(iu_release_compl))); +} +testcase TC_cs_mo_call() runs on test_CT { + var HNBGW_ConnHdlr vc_conn; + + f_init(); + vc_conn := f_start_handler(refers(f_tc_cs_mo_call)); + vc_conn.done; + f_shutdown_helper(); +} + control { execute( TC_hnb_register_request_accept() ); execute( TC_hnb_register_request_reject() ); execute( TC_mo_conn() ); execute( TC_paging() ); + execute( TC_cs_mo_call() ); } } diff --git a/library/HNBLLIF_Templates.ttcn b/library/HNBLLIF_Templates.ttcn index f330fdf8..3fa49b7b 100644 --- a/library/HNBLLIF_Templates.ttcn +++ b/library/HNBLLIF_Templates.ttcn @@ -248,4 +248,123 @@ template (present) HNBLLIF_Message tr_HNBLLIF_IUH_UNITDATA_IND(template (present } } +/********************** + * AUDIO SAPI + **********************/ + +template (value) HNBLLIF_Message ts_HNBLLIF_AUDIO_CONN_ESTABLISH_REQ(template (value) uint32_t context_id, + template (value) uint16_t remote_rtp_port, + template (value) HNBLLIF_AddrType remote_rtp_address_type, + template (value) HNBLLIF_Addr remote_addr) := { + sapi := HNBLL_IF_SAPI_AUDIO, + u := { + audio := { + prim := HNBLL_IF_AUDIO_MSG_CONN_ESTABLISH, + u := { + conn_establish := { + op := HNBLL_IF_OP_REQUEST, + u := { + req := { + context_id := context_id, + remote_rtp_port := remote_rtp_port, + reserved := 0, + remote_rtp_address_type := remote_rtp_address_type, + remote_addr := remote_addr + } + } + } + } + } + } +} + +template (present) HNBLLIF_Message tr_HNBLLIF_AUDIO_CONN_ESTABLISH_CNF(template (present) uint32_t context_id := ?, + template (present) uint8_t error_code := ?, + template (present) uint16_t local_rtp_port:= ?, + template (present) HNBLLIF_AddrType local_rtp_address_type := ?, + template (present) HNBLLIF_Addr local_addr := ?) := { + sapi := HNBLL_IF_SAPI_AUDIO, + u := { + audio := { + prim := HNBLL_IF_AUDIO_MSG_CONN_ESTABLISH, + u := { + conn_establish := { + op := HNBLL_IF_OP_CONFIRM, + u := { + cnf := { + context_id := context_id, + local_rtp_port := local_rtp_port, + error_code := error_code, + local_rtp_address_type := local_rtp_address_type, + local_addr := local_addr + } + } + } + } + } + } +} + +template (value) HNBLLIF_Message ts_HNBLLIF_AUDIO_CONN_RELEASE_REQ(template (value) uint32_t context_id) := { + sapi := HNBLL_IF_SAPI_AUDIO, + u := { + audio := { + prim := HNBLL_IF_AUDIO_MSG_CONN_RELEASE, + u := { + conn_release := { + op := HNBLL_IF_OP_REQUEST, + u := { + req := { + context_id := context_id + } + } + } + } + } + } +} + +template (present) HNBLLIF_Message tr_HNBLLIF_AUDIO_CONN_DATA_IND(template (present) uint32_t context_id := ?, + template (present) octetstring data := ?) := { + sapi := HNBLL_IF_SAPI_AUDIO, + u := { + audio := { + prim := HNBLL_IF_AUDIO_MSG_CONN_DATA, + u := { + conn_data := { + op := HNBLL_IF_OP_INDICATION, + u := { + ind := { + context_id := context_id, + data_len := ?, + data := data + } + } + } + } + } + } +} + +template (value) HNBLLIF_Message ts_HNBLLIF_AUDIO_CONN_DATA_REQ(template (value) uint32_t context_id, + template (value) octetstring data) := { + sapi := HNBLL_IF_SAPI_AUDIO, + u := { + audio := { + prim := HNBLL_IF_AUDIO_MSG_CONN_DATA, + u := { + conn_data := { + op := HNBLL_IF_OP_REQUEST, + u := { + req := { + context_id := context_id, + data_len := lengthof(data), + data := data + } + } + } + } + } + } +} } with { encode "RAW" variant "BYTEORDER(first)" }; diff --git a/library/HNBLLIF_Types.ttcn b/library/HNBLLIF_Types.ttcn index f9c8cc5f..befd7bb7 100644 --- a/library/HNBLLIF_Types.ttcn +++ b/library/HNBLLIF_Types.ttcn @@ -232,15 +232,121 @@ type record HNBLLIF_IUH_PrimHdr { other, OTHERWISE)" }; +/********************** + * AUDIO SAPI + **********************/ +type enumerated HNBLLIF_AUDIO_MsgType { + HNBLL_IF_AUDIO_MSG_CONN_ESTABLISH ('0000'O), + HNBLL_IF_AUDIO_MSG_CONN_RELEASE ('0001'O), + HNBLL_IF_AUDIO_MSG_CONN_DATA ('0002'O) +} with { variant "FIELDLENGTH(16)" }; + +/* CONN_ESTABLISH */ +type record HNBLLIF_AUDIO_conn_establish_req { + uint32_t context_id, + uint16_t remote_rtp_port, + uint8_t reserved, + HNBLLIF_AddrType remote_rtp_address_type, + HNBLLIF_Addr remote_addr +} with { variant "" }; + +type record HNBLLIF_AUDIO_conn_establish_cnf { + uint32_t context_id, + uint16_t local_rtp_port, + uint8_t error_code, + HNBLLIF_AddrType local_rtp_address_type, + HNBLLIF_Addr local_addr +} with { variant "" }; + +type union HNBLLIF_AUDIO_PrimOpUnion_conn_establish { + HNBLLIF_AUDIO_conn_establish_req req, + HNBLLIF_AUDIO_conn_establish_cnf cnf, + octetstring other +} with { variant "" }; +type record HNBLLIF_AUDIO_PrimOp_conn_establish { + HNBLLIF_Operation op, + HNBLLIF_AUDIO_PrimOpUnion_conn_establish u +} with { variant (u) "CROSSTAG( req, op = HNBLL_IF_OP_REQUEST; + cnf, op = HNBLL_IF_OP_CONFIRM; + other, OTHERWISE)" +}; + +/* CONN_RELEASE */ +type record HNBLLIF_AUDIO_conn_release_req { + uint32_t context_id +} with { variant "" }; + + +type union HNBLLIF_AUDIO_PrimOpUnion_conn_release { + HNBLLIF_AUDIO_conn_release_req req, + octetstring other +} with { variant "" }; +type record HNBLLIF_AUDIO_PrimOp_conn_release { + HNBLLIF_Operation op, + HNBLLIF_AUDIO_PrimOpUnion_conn_release u +} with { variant (u) "CROSSTAG( req, op = HNBLL_IF_OP_REQUEST; + other, OTHERWISE)" +}; + +/* CONN_DATA */ +type record HNBLLIF_AUDIO_conn_data_ind { + uint32_t context_id, + uint32_t data_len, + octetstring data /* RANAP message */ +} with { variant (data_len) "LENGTHTO (data)" }; + +type record HNBLLIF_AUDIO_conn_data_req { + uint32_t context_id, + uint32_t data_len, + octetstring data /* RANAP message */ +} with { variant (data_len) "LENGTHTO (data)" }; + +type union HNBLLIF_AUDIO_PrimOpUnion_conn_data { + HNBLLIF_AUDIO_conn_data_req req, + HNBLLIF_AUDIO_conn_data_ind ind, + octetstring other +} with { variant "" }; +type record HNBLLIF_AUDIO_PrimOp_conn_data { + HNBLLIF_Operation op, + HNBLLIF_AUDIO_PrimOpUnion_conn_data u +} with { variant (u) "CROSSTAG( req, op = HNBLL_IF_OP_REQUEST; + ind, op = HNBLL_IF_OP_INDICATION; + other, OTHERWISE)" +}; + +type union HNBLLIF_AUDIO_PrimUnion { + HNBLLIF_AUDIO_PrimOp_conn_establish conn_establish, + HNBLLIF_AUDIO_PrimOp_conn_release conn_release, + HNBLLIF_AUDIO_PrimOp_conn_data conn_data, + octetstring other +} with { variant "" }; + +type record HNBLLIF_AUDIO_PrimHdr { + HNBLLIF_AUDIO_MsgType prim, + HNBLLIF_AUDIO_PrimUnion u +} with { variant (u) "CROSSTAG( conn_establish, prim = HNBLL_IF_AUDIO_MSG_CONN_ESTABLISH; + conn_release, prim = HNBLL_IF_AUDIO_MSG_CONN_RELEASE; + conn_data, prim = HNBLL_IF_AUDIO_MSG_CONN_DATA; + other, OTHERWISE)" +}; + /********************** * General **********************/ + +type enumerated HNBLLIF_AddrType { + HNBLL_IF_ADDR_TYPE_UNSPEC ('00'O), + HNBLL_IF_ADDR_TYPE_IPV4 ('01'O), + HNBLL_IF_ADDR_TYPE_IPV6 ('02'O) +} with { variant "FIELDLENGTH(8)" }; +type octetstring HNBLLIF_Addr length(16); + type enumerated HNBLLIF_Sapi { HNBLL_IF_SAPI_CTL (-1), - HNBLL_IF_SAPI_IUH ('00000001'O)//, + HNBLL_IF_SAPI_IUH ('00000001'O), //HNBLL_IF_SAPI_GTP ('00000002'O), - //HNBLL_IF_SAPI_AUDIO ('00000003'O), + HNBLL_IF_SAPI_AUDIO ('00000003'O) } with { variant "FIELDLENGTH(32)" variant "COMP(2scompl)" }; @@ -255,6 +361,7 @@ type enumerated HNBLLIF_Operation { type union HNBLLIF_SapiUnion { HNBLLIF_CTL_PrimHdr ctl, HNBLLIF_IUH_PrimHdr iuh, + HNBLLIF_AUDIO_PrimHdr audio, octetstring other } with { variant "" }; @@ -263,6 +370,7 @@ type record HNBLLIF_Message { HNBLLIF_SapiUnion u } with { variant (u) "CROSSTAG( ctl, sapi = HNBLL_IF_SAPI_CTL; iuh, sapi = HNBLL_IF_SAPI_IUH; + audio, sapi = HNBLL_IF_SAPI_AUDIO; other, OTHERWISE)" }; @@ -271,5 +379,29 @@ external function enc_HNBLLIF_Message(in HNBLLIF_Message pdu) return octetstring external function dec_HNBLLIF_Message(in octetstring stream) return HNBLLIF_Message with { extension "prototype(convert) decode(RAW)" }; +function f_HNBLLIF_AF2addr_type(AddressFamily address_family) +return HNBLLIF_AddrType { + if (address_family == AF_INET) { + return HNBLL_IF_ADDR_TYPE_IPV4; + } else if (address_family == AF_INET6) { + return HNBLL_IF_ADDR_TYPE_IPV6; + } else { + return HNBLL_IF_ADDR_TYPE_UNSPEC; + } +} + +function f_HNBLLIF_Addr(HNBLLIF_AddrType addr_type, charstring addr_str) +return HNBLLIF_Addr { + var HNBLLIF_Addr addr; + + if (addr_type == HNBLL_IF_ADDR_TYPE_IPV4) { + addr := f_inet_addr(addr_str); + } else { + addr := f_inet6_addr(addr_str); + } + + return addr; +} + } with { encode "RAW" variant "BYTEORDER(first)" }; |