| module HNBGW_ConnectionHandler { |
| |
| /* HNBGW Connection Handler of HNB_Tests in TTCN-3 |
| * (C) 2021 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de> |
| * All rights reserved. |
| * |
| * Released under the terms of GNU General Public License, Version 2 or |
| * (at your option) any later version. |
| * |
| * SPDX-License-Identifier: GPL-2.0-or-later |
| */ |
| |
| 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 SDP_Types all; |
| |
| import from StatsD_Checker all; |
| |
| import from TELNETasp_PortType all; |
| import from Osmocom_VTY_Functions all; |
| |
| 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; |
| |
| import from GTP_Emulation all; |
| import from GTP_Templates all; |
| import from GTP_CodecPort all; |
| import from GTPU_Types all; |
| |
| /* this component represents a single Iuh connection at the HNBGW. */ |
| type component HNBGW_ConnHdlr extends Iuh_ConnHdlr, GTP_ConnHdlr, StatsD_ConnHdlr { |
| port TELNETasp_PT HNBVTY; |
| /* HNBLLIF Interface of HNodeB */ |
| 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 GTP_Emulation_CT vc_GTP; |
| |
| |
| var TestHdlrParams g_pars; |
| |
| var boolean g_vty_initialized := false; |
| } |
| |
| function f_HNBGW_ConnHdlr_init_vty() runs on HNBGW_ConnHdlr { |
| if (not g_vty_initialized) { |
| map(self:HNBVTY, system:HNBVTY); |
| f_vty_set_prompts(HNBVTY); |
| f_vty_transceive(HNBVTY, "enable"); |
| g_vty_initialized := true; |
| } |
| } |
| |
| private function f_HNBGW_ConnHdlr_init_iuh(charstring id) runs on HNBGW_ConnHdlr { |
| var Iuh_Emulation_CT vc_Iuh; |
| vc_Iuh := Iuh_Emulation_CT.create(id & "-HNBGW") alive; |
| connect(self:HNBAP, vc_Iuh:HNBAP); |
| connect(self:RUA, vc_Iuh:RUA); |
| |
| var Iuh_conn_parameters iuh_pars; |
| iuh_pars.remote_ip := g_pars.hnodeb_addr; |
| iuh_pars.remote_sctp_port := -1; |
| iuh_pars.local_ip := g_pars.hnbgw_addr; |
| iuh_pars.local_sctp_port := g_pars.hnbgw_port; |
| vc_Iuh.start(Iuh_Emulation.main(iuh_pars, id & "-Iuh")); |
| } |
| |
| private function f_HNBGW_ConnHdlr_init_gtp(charstring id) runs on HNBGW_ConnHdlr { |
| id := id & "-GTP"; |
| |
| var GtpEmulationCfg gtp_cfg := { |
| gtpc_bind_ip := g_pars.hnbgw_addr, |
| gtpc_bind_port := GTP1C_PORT, |
| gtpu_bind_ip := g_pars.hnbgw_addr, |
| gtpu_bind_port := GTP1U_PORT, |
| sgsn_role := false |
| }; |
| |
| vc_GTP := GTP_Emulation_CT.create(id) alive; |
| connect(self:GTP, vc_GTP:CLIENT); |
| connect(self:GTP_PROC, vc_GTP:CLIENT_PROC); |
| vc_GTP.start(GTP_Emulation.main(gtp_cfg)); |
| } |
| |
| /* initialize all parameters */ |
| function f_HNBGW_ConnHdlr_init(charstring id, TestHdlrParams pars) runs on HNBGW_ConnHdlr { |
| g_pars := valueof(pars); |
| f_HNBGW_ConnHdlr_init_iuh(id); |
| f_HNBGW_ConnHdlr_init_gtp(id); |
| f_HNBGW_ConnHdlr_init_vty(); |
| |
| /* Connect to HNB on LLSK and do HELLO ping-pong */ |
| f_start_hnbllif(LLSK, id & "-LLSK", g_pars.hnbllif_sk_path, g_llsk_conn_id); |
| } |
| |
| |
| function f_start_hnbllif(HNBLLIF_CODEC_PT pt, charstring id, charstring hnbllif_sk_path, out integer hnbllif_conn_id) { |
| timer T := 2.0; |
| var HNBLLIF_send_data sd; |
| var HNBLLIF_Message last_hello_cnf; |
| if (hnbllif_sk_path == "") { |
| hnbllif_conn_id := -1; |
| return; |
| } |
| hnbllif_conn_id := f_hnbllif_connect(pt, hnbllif_sk_path); |
| |
| T.start; |
| pt.send(t_SD_HNBLLIF(hnbllif_conn_id, ts_HNBLLIF_CTL_HELLO_REQ(HNBLL_IF_SAPI_CTL, HNBLLIF_Types.mp_hnbllif_version))); |
| alt { |
| [] as_hnbllif_hello_cnf(pt, hnbllif_conn_id, last_hello_cnf, HNBLL_IF_SAPI_CTL, HNBLLIF_Types.mp_hnbllif_version); |
| [] T.timeout { |
| Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for HNBLLIF HELLO.REQ SAPI=CTL"); |
| } |
| } |
| pt.send(t_SD_HNBLLIF(hnbllif_conn_id, ts_HNBLLIF_CTL_HELLO_REQ(HNBLL_IF_SAPI_IUH, 0))); |
| alt { |
| [] as_hnbllif_hello_cnf(pt, hnbllif_conn_id, last_hello_cnf, HNBLL_IF_SAPI_IUH, 0); |
| [] T.timeout { |
| 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"); |
| } |
| } |
| pt.send(t_SD_HNBLLIF(hnbllif_conn_id, ts_HNBLLIF_CTL_HELLO_REQ(HNBLL_IF_SAPI_GTP, 0))); |
| alt { |
| [] as_hnbllif_hello_cnf(pt, hnbllif_conn_id, last_hello_cnf, HNBLL_IF_SAPI_GTP, 0); |
| [] T.timeout { |
| Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting for HNBLLIF HELLO.REQ SAPI=GTP"); |
| } |
| } |
| } |
| |
| type record TestHdlrParams { |
| charstring hnbllif_sk_path, /* "" means don't connect */ |
| charstring hnbgw_addr, |
| charstring hnodeb_addr, |
| integer hnbgw_port, |
| integer hnbgw_rtp_port, |
| uint16_t rnc_id, |
| charstring hNB_Identity_Info, |
| uint16_t mcc, |
| uint16_t mnc, |
| uint32_t cell_identity, |
| uint16_t lac, |
| uint8_t rac, |
| uint8_t sac |
| }; |
| |
| /* Note: Do not use valueof() to get a value of this template, use |
| * f_gen_test_hdlr_pars() instead in order to get a configuration. */ |
| template (value) TestHdlrParams t_def_TestHdlrPars := { |
| hnbllif_sk_path := HNBLL_SOCK_DEFAULT, |
| 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, |
| mnc := 1, |
| cell_identity := 1, |
| lac := 2, |
| rac := 3, |
| sac := 4 |
| } |
| |
| template (value) GtpPeer ts_GtpPeerU(charstring ip) := { |
| connId := 1, |
| remName := ip, |
| remPort := GTP1U_PORT |
| } |
| |
| function f_gtpu_send(uint32_t tei, octetstring payload) runs on HNBGW_ConnHdlr { |
| var GtpPeer peer := valueof(ts_GtpPeerU(g_pars.hnodeb_addr)); |
| GTP.send(ts_GTP1U_GPDU(peer, 0 /*seq*/, int2oct(tei, 4), payload)); |
| } |
| |
| /* HNBLLIF socket may at any time receive a new INFO.ind */ |
| altstep as_hnbllif_hello_cnf(HNBLLIF_CODEC_PT pt, integer hnbllif_conn_id, |
| out HNBLLIF_Message last_hello_cnf, |
| template (present) HNBLLIF_Sapi exp_sapi := ?, |
| template (present) uint16_t exp_version := ?) { |
| var HNBLLIF_send_data sd; |
| [] pt.receive(t_SD_HNBLLIF(hnbllif_conn_id, tr_HNBLLIF_CTL_HELLO_CNF(exp_sapi, exp_version))) -> value sd { |
| last_hello_cnf := sd.data; |
| } |
| [] pt.receive(t_SD_HNBLLIF(hnbllif_conn_id, tr_HNBLLIF_CTL_HELLO_CNF(?))) -> value sd { |
| Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Invalid API_VERSION received"); |
| } |
| } |
| |
| function f_llsk_rx(template (present) HNBLLIF_Message exp_tmpl) runs on HNBGW_ConnHdlr |
| return template (present) HNBLLIF_send_data { |
| return t_SD_HNBLLIF(g_llsk_conn_id, exp_tmpl); |
| } |
| |
| function f_llsk_tx(template (value) HNBLLIF_Message tx_msg) runs on HNBGW_ConnHdlr |
| return template (value) HNBLLIF_send_data { |
| return ts_SD_HNBLLIF(g_llsk_conn_id, tx_msg); |
| } |
| |
| function f_enc_mcc_mnc(uint16_t mcc_uint, uint16_t mnc_uint) return OCT3 { |
| var hexstring mnc; |
| var hexstring mcc := int2hex(mcc_uint, 3); |
| |
| if (mnc_uint < 100) { |
| mnc := int2hex(mnc_uint, 2); |
| return hex2oct(mcc[1] & mcc[0] & 'F'H & mcc[2] & mnc[1] & mnc[0]); |
| } else { |
| mnc := int2hex(mnc_uint, 3); |
| return hex2oct(mcc[1] & mcc[0] & mnc[2] & mcc[2] & mnc[1] & mnc[0]); |
| } |
| } |
| |
| function f_handle_hnbap_hnb_register_req() |
| runs on HNBGW_ConnHdlr { |
| HNBAP.receive(tr_HNBAP_HNBRegisterRequest(char2oct(g_pars.hNB_Identity_Info), |
| f_enc_mcc_mnc(g_pars.mcc, g_pars.mnc), |
| int2bit(g_pars.cell_identity, 28), |
| int2oct(g_pars.lac, 2), |
| int2oct(g_pars.rac, 1), |
| int2oct(g_pars.sac, 2) |
| )); |
| 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) |
| runs on HNBGW_ConnHdlr { |
| /* Initialize, connect and start the emulation component */ |
| var RtpemConfig cfg := c_RtpemDefaultCfg; |
| cfg.iuup_mode := true; |
| cfg.iuup_tx_init := false; |
| cfg.tx_payload_type := 96; |
| |
| vc_RTPEM := RTP_Emulation_CT.create(testcasename() & "-RTPEM") alive; |
| 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); |
| |
| /* Set the given RTP emulation mode */ |
| f_rtpem_mode(RTPEM_CTRL, RTPEM_MODE_RXONLY); |
| } |
| |
| function f_HNBGW_rtpem_connect(HostName remote_host, PortNumber remote_port) |
| runs on HNBGW_ConnHdlr { |
| f_rtpem_connect(RTPEM_CTRL, remote_host, remote_port); |
| /* Set the given RTP emulation mode */ |
| f_rtpem_mode(RTPEM_CTRL, RTPEM_MODE_BIDIR); |
| } |
| |
| } |