diff --git a/cbc/BSC_ConnectionHandler.ttcn b/cbc/BSC_ConnectionHandler.ttcn index ec86f01c0..a8601a66d 100644 --- a/cbc/BSC_ConnectionHandler.ttcn +++ b/cbc/BSC_ConnectionHandler.ttcn @@ -25,15 +25,23 @@ import from CBS_Message all; type function void_fn() runs on BSC_ConnHdlr; +/* Coordinate with test_CT: */ +type port BSC_ConnHdlr_Coord_PT message { + inout charstring; +} with { extension "internal" }; + /* this component represents a single subscriber connection */ type component BSC_ConnHdlr extends CBSP_Adapter_CT { var BSC_ConnHdlrPars g_pars; + port BSC_ConnHdlr_Coord_PT COORD; } type record BSC_ConnHdlrPars { + charstring bsc_host, integer bsc_cbsp_port, charstring cbc_host, integer cbc_cbsp_port, + boolean tcp_is_client, void_fn start_fn, CBS_Message exp_cbs_msg optional, BSSMAP_FIELD_CellIdentificationList cell_list_success optional @@ -41,7 +49,13 @@ type record BSC_ConnHdlrPars { function f_BSC_ConnHdlr_main(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { g_pars := pars; - CBSP_Adapter.f_connect(g_pars.cbc_host, g_pars.cbc_cbsp_port, "", g_pars.bsc_cbsp_port); + if (g_pars.tcp_is_client) { + CBSP_Adapter.f_connect(g_pars.cbc_host, g_pars.cbc_cbsp_port, + g_pars.bsc_host, g_pars.bsc_cbsp_port); + } else { + CBSP_Adapter.f_bind(g_pars.bsc_host, g_pars.bsc_cbsp_port); + CBSP_Adapter.f_wait_client_connect(); + } var BSSMAP_FIELD_CellIdentificationList cell_list := { cIl_allInBSS := ''O @@ -51,6 +65,7 @@ function f_BSC_ConnHdlr_main(charstring id, BSC_ConnHdlrPars pars) runs on BSC_C f_cbsp_send(ts_CBSP_RESTART(cell_list, CBSP_BC_MSGT_CBS, CBSP_RI_DATA_LOST)); f_cbsp_send(ts_CBSP_RESTART(cell_list, CBSP_BC_MSGT_EMERG, CBSP_RI_DATA_LOST)); as_cbsp_reset(0); + COORD.send(COORD_MSG_CONNECTED); g_pars.start_fn.apply(); } diff --git a/cbc/CBC_Tests.ttcn b/cbc/CBC_Tests.ttcn index 64cf5e2a5..406baedf0 100644 --- a/cbc/CBC_Tests.ttcn +++ b/cbc/CBC_Tests.ttcn @@ -33,18 +33,38 @@ import from ECBE_Components all; import from BSC_ConnectionHandler all; import from MME_ConnectionHandler all; +const integer MAX_BSC := 2; +const integer MAX_MME := 2; + +type record BSC_modulepar_cfg { + boolean tcp_is_client +}; +type record of BSC_modulepar_cfg BSC_modulepar_cfgs; + +type record MME_modulepar_cfg { + boolean sctp_is_client +}; +type record of MME_modulepar_cfg MME_modulepar_cfgs; + modulepar { + charstring mp_local_host := "127.0.0.2"; charstring mp_cbc_host := "127.0.0.1"; integer mp_cbc_cbsp_port := 48049; integer mp_cbc_sbcap_port := c_SBC_AP_PORT; integer mp_cbc_ecbe_port := 12345; integer mp_local_cbsp_port := 15000; integer mp_local_sbcap_port := 16000; + /* Must match osmo-cbc.cfg: */ + BSC_modulepar_cfgs mp_bsc_cfg := { + { tcp_is_client := true }, + { tcp_is_client := false } + }; + MME_modulepar_cfgs mp_mme_cfg := { + { sctp_is_client := true }, + { sctp_is_client := false } + }; }; -const integer MAX_BSC := 3; -const integer MAX_MME := 3; - type component test_CT extends CBSP_Adapter_CT, http_CT { timer g_Tguard := 60.0; var integer g_num_bsc; @@ -53,6 +73,8 @@ type component test_CT extends CBSP_Adapter_CT, http_CT { var MME_ConnHdlr g_vc_conn_MME[MAX_MME]; var BSC_ConnHdlrPars g_pars_BSC[MAX_BSC]; var MME_ConnHdlrPars g_pars_MME[MAX_MME]; + port BSC_ConnHdlr_Coord_PT COORD_BSC[MAX_BSC]; + port MME_ConnHdlr_Coord_PT COORD_MME[MAX_BSC]; }; private function f_shutdown_helper() runs on test_CT { @@ -84,12 +106,16 @@ private altstep as_Tguard() runs on test_CT { private function f_BSC_ConnHdlr_start_fn_void() runs on BSC_ConnHdlr { log("Default start_fn() function called!"); } -private function f_init_pars_bsc(integer bsc_cbsp_port, charstring cbc_host, integer cbc_cbsp_port) +private function f_init_pars_bsc(charstring bsc_host, integer bsc_cbsp_port, + charstring cbc_host, integer cbc_cbsp_port, + boolean tcp_is_client) runs on test_CT return BSC_ConnHdlrPars { var BSC_ConnHdlrPars pars := { + bsc_host := bsc_host, bsc_cbsp_port := bsc_cbsp_port, cbc_host := cbc_host, cbc_cbsp_port := cbc_cbsp_port, + tcp_is_client := tcp_is_client, start_fn := refers(f_BSC_ConnHdlr_start_fn_void), exp_cbs_msg := omit, cell_list_success := omit @@ -101,7 +127,10 @@ private function f_init_bsc(integer idx, charstring id) runs on test_CT return B var BSC_ConnHdlr vc_conn; id := id & "-BSC" & int2str(idx); vc_conn := BSC_ConnHdlr.create(id) alive; - g_pars_BSC[idx] := f_init_pars_bsc(mp_local_cbsp_port + idx, mp_cbc_host, mp_cbc_cbsp_port); + g_pars_BSC[idx] := f_init_pars_bsc(mp_local_host, mp_local_cbsp_port + idx, + mp_cbc_host, mp_cbc_cbsp_port, + mp_bsc_cfg[idx].tcp_is_client); + connect(self:COORD_BSC[idx], vc_conn:COORD); return vc_conn; } @@ -118,12 +147,16 @@ private function f_start_bsc(integer idx, charstring id, BSC_ConnHdlrPars pars) private function f_MME_ConnHdlr_start_fn_void() runs on MME_ConnHdlr { log("Default start_fn() function called!"); } -private function f_init_pars_mme(integer mme_sbcap_port, charstring cbc_host, integer cbc_sbcap_port) +private function f_init_pars_mme(charstring mme_host, integer mme_sbcap_port, + charstring cbc_host, integer cbc_sbcap_port, + boolean sctp_is_client) runs on test_CT return MME_ConnHdlrPars { var MME_ConnHdlrPars pars := { + mme_host := mme_host, mme_sbcap_port := mme_sbcap_port, cbc_host := cbc_host, cbc_sbcap_port := cbc_sbcap_port, + sctp_is_client := sctp_is_client, start_fn := refers(f_MME_ConnHdlr_start_fn_void), exp_cbs_msg := omit, write_replace_warning_ind_cause := omit, @@ -136,7 +169,10 @@ private function f_init_mme(integer idx, charstring id) runs on test_CT return M var MME_ConnHdlr vc_conn; id := id & "-MME" & int2str(idx); vc_conn := MME_ConnHdlr.create(id) alive; - g_pars_MME[idx] := f_init_pars_mme(mp_local_sbcap_port + idx, mp_cbc_host, mp_cbc_sbcap_port); + g_pars_MME[idx] := f_init_pars_mme(mp_local_host, mp_local_sbcap_port + idx, + mp_cbc_host, mp_cbc_sbcap_port, + mp_mme_cfg[idx].sctp_is_client); + connect(self:COORD_MME[idx], vc_conn:COORD); return vc_conn; } @@ -172,7 +208,14 @@ function f_start(float t_guard := 60.0) runs on test_CT { for (var integer i := 0; i < g_num_mme; i := i + 1) { f_start_mme(i, testcasename(), g_pars_MME[i]); } - f_sleep(2.0); /* wait all conns connected */ + + /* Now wait for conns to be ready: */ + for (var integer i := 0; i < g_num_bsc; i := i + 1) { + COORD_BSC[i].receive(COORD_MSG_CONNECTED); + } + for (var integer i := 0; i < g_num_mme; i := i + 1) { + COORD_MME[i].receive(COORD_MSG_CONNECTED); + } } /* test whether or not we receive a valid KEEP-ALIVE from the CBC */ @@ -483,6 +526,56 @@ testcase TC_ecbe_create_delete_bsc_and_mme() runs on test_CT { f_shutdown_helper(); } +/* Create and delete message with BSC acting as TCP server */ +testcase TC_ecbe_create_delete_bsc_server() runs on test_CT { + var template (value) BSSMAP_FIELD_CellIdentificationList cell_list_success; + var template (value) CBS_Message msg := t_CBSmsg(46, 16752); + + /* The 2nd BSC is the one configured as server, but we only want to test + * that one, so initialize both but copy over config of the 2nd one to + * the first one, to start only one BSC: */ + f_init(num_bsc := 2); + g_num_bsc := 1; + g_pars_BSC[0] := g_pars_BSC[1]; + + cell_list_success := ts_BSSMAP_CIL_CI({ + ts_BSSMAP_CI_CI(50001), + ts_BSSMAP_CI_CI(50002), + ts_BSSMAP_CI_CI(50003) + }); + g_pars_BSC[0].start_fn := refers(f_bsc_create_and_delete); + g_pars_BSC[0].exp_cbs_msg := valueof(msg); + g_pars_BSC[0].cell_list_success := valueof(cell_list_success); + f_start(); + f_create_and_delete(valueof(msg)); + f_shutdown_helper(); +} + +/* Create and delete message with MME acting as SCTP server */ +testcase TC_ecbe_create_delete_mme_server() runs on test_CT { + var template (value) CellId_Broadcast_List bcast_cell_id_li; + var template (value) CBS_Message msg := t_CBSmsg(48, 16752); + + /* The 2nd MME is the one configured as server, but we only want to test + * that one, so initialize both but copy over config of the 2nd one to + * the first one, to start only one MME: */ + f_init(num_bsc := 0, num_mme := 2); + g_num_mme := 1; + g_pars_MME[0] := g_pars_MME[1]; + + bcast_cell_id_li := { + ts_SBCAP_CellId_Broadcast_List_Item(ts_SBCAP_ECGI(f_enc_mcc_mnc('901'H, '70'H), 1234)), + ts_SBCAP_CellId_Broadcast_List_Item(ts_SBCAP_ECGI(f_enc_mcc_mnc('901'H, '70'H), 5678)) + }; + g_pars_MME[0].start_fn := refers(f_mme_create_and_delete); + g_pars_MME[0].exp_cbs_msg := valueof(msg); + g_pars_MME[0].write_replace_warning_ind_cause := SBC_AP_Cause_message_accepted; + g_pars_MME[0].bcast_cell_id_list := valueof(bcast_cell_id_li); + f_start(); + f_create_and_delete(valueof(msg)); + f_shutdown_helper(); +} + control { execute( TC_rx_keepalive() ); execute( TC_rx_keepalive_timeout() ); @@ -493,6 +586,8 @@ control { execute( TC_ecbe_create_delete_lai() ); execute( TC_ecbe_create_delete_mme_indication() ); execute( TC_ecbe_create_delete_bsc_and_mme() ); + execute( TC_ecbe_create_delete_bsc_server() ); + execute( TC_ecbe_create_delete_mme_server() ); } } diff --git a/cbc/CBS_Message.ttcn b/cbc/CBS_Message.ttcn index 6f77a1b47..1ce693545 100644 --- a/cbc/CBS_Message.ttcn +++ b/cbc/CBS_Message.ttcn @@ -17,6 +17,10 @@ import from BSSMAP_Templates all; import from CBSP_Types all; +/* Messages used for coordination between handlers and test_CT: */ +const charstring COORD_MSG_CONNECTED := "COORD_MSG_CONNECTED"; + + type record CBS_Message { uint16_t msg_id, uint16_t ser_nr, diff --git a/cbc/MME_ConnectionHandler.ttcn b/cbc/MME_ConnectionHandler.ttcn index fec358c9a..ed0502e42 100644 --- a/cbc/MME_ConnectionHandler.ttcn +++ b/cbc/MME_ConnectionHandler.ttcn @@ -25,15 +25,23 @@ import from CBS_Message all; type function void_fn() runs on MME_ConnHdlr; +/* Coordinate with test_CT: */ +type port MME_ConnHdlr_Coord_PT message { + inout charstring; +} with { extension "internal" }; + /* this component represents a single subscriber connection */ type component MME_ConnHdlr extends SBC_AP_Adapter_CT { var MME_ConnHdlrPars g_pars; + port MME_ConnHdlr_Coord_PT COORD; } type record MME_ConnHdlrPars { + charstring mme_host, integer mme_sbcap_port, charstring cbc_host, integer cbc_sbcap_port, + boolean sctp_is_client, void_fn start_fn, CBS_Message exp_cbs_msg optional, SBC_AP_Cause write_replace_warning_ind_cause optional, @@ -42,7 +50,14 @@ type record MME_ConnHdlrPars { function f_MME_ConnHdlr_main(charstring id, MME_ConnHdlrPars pars) runs on MME_ConnHdlr { g_pars := pars; - SBC_AP_Adapter.f_connect(g_pars.cbc_host, g_pars.cbc_sbcap_port, "", g_pars.mme_sbcap_port); + if (g_pars.sctp_is_client) { + SBC_AP_Adapter.f_connect(g_pars.cbc_host, g_pars.cbc_sbcap_port, + g_pars.mme_host, g_pars.mme_sbcap_port); + } else { + SBC_AP_Adapter.f_bind(g_pars.mme_host, g_pars.mme_sbcap_port); + SBC_AP_Adapter.f_wait_client_connect(); + } + COORD.send(COORD_MSG_CONNECTED); g_pars.start_fn.apply(); } diff --git a/library/CBSP_Adapter.ttcn b/library/CBSP_Adapter.ttcn index de89d58bc..278a2f241 100644 --- a/library/CBSP_Adapter.ttcn +++ b/library/CBSP_Adapter.ttcn @@ -77,6 +77,16 @@ runs on CBSP_Adapter_CT { f_set_tcp_segmentation(idx); } +function f_wait_client_connect(integer idx := 0) runs on CBSP_Adapter_CT { + var IPL4asp_Types.PortEvent rx_event; + CBSP[idx].receive(IPL4asp_Types.PortEvent:{connOpened:=?}) -> value rx_event { + log("Connection from ", rx_event.connOpened.remName, ":", rx_event.connOpened.remPort); + /* we want to store the client's connId, not the 'bind socket' one */ + g_cbsp_conn_id[idx] := rx_event.connOpened.connId; + } + f_set_tcp_segmentation(idx); +} + function f_cbsp_send(template (value) CBSP_PDU pdu, integer idx := 0) runs on CBSP_Adapter_CT { CBSP[idx].send(ts_CBSP_Send(g_cbsp_conn_id[idx], pdu)); } diff --git a/library/sbcap/SBC_AP_Adapter.ttcn b/library/sbcap/SBC_AP_Adapter.ttcn index 3217c5e2d..515a723e6 100644 --- a/library/sbcap/SBC_AP_Adapter.ttcn +++ b/library/sbcap/SBC_AP_Adapter.ttcn @@ -77,6 +77,23 @@ runs on SBC_AP_Adapter_CT { g_SBC_AP_conn_id[idx] := res.connId; } +function f_wait_client_connect(integer idx := 0) runs on SBC_AP_Adapter_CT { + var IPL4asp_Types.PortEvent rx_event; + SBC_AP[idx].receive(IPL4asp_Types.PortEvent:{connOpened:=?}) -> value rx_event { + log("Connection from ", rx_event.connOpened.remName, ":", rx_event.connOpened.remPort); + /* we want to store the client's connId, not the 'bind socket' one */ + g_SBC_AP_conn_id[idx] := rx_event.connOpened.connId; + } + timer Tcommup := 10.0; + Tcommup.start; + alt { + [] SBC_AP[idx].receive(tr_SctpAssocChange_COMM_UP(g_SBC_AP_conn_id[idx])) {} + [] Tcommup.timeout { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Timeout waiting SCTP_COMM_UP"); + } + } +} + function f_SBC_AP_send(template (value) SBC_AP_PDU pdu, integer idx := 0) runs on SBC_AP_Adapter_CT { SBC_AP[idx].send(ts_SBC_AP_Send(g_SBC_AP_conn_id[idx], pdu)); }