Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 1 | module BSC_Tests_VAMOS { |
| 2 | |
| 3 | /* Integration Tests for OsmoBSC |
| 4 | * (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * Released under the terms of GNU General Public License, Version 2 or |
| 8 | * (at your option) any later version. |
| 9 | * |
| 10 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 11 | * |
| 12 | * This test suite tests OsmoBSC while emulating both multiple BTS + MS as |
| 13 | * well as the MSC. See README for more details. |
| 14 | * |
| 15 | * There are test cases that run in so-called 'handler mode' and test cases |
| 16 | * that run directly on top of the BSSAP and RSL CodecPorts. The "handler mode" |
| 17 | * tests abstract the multiplexing/demultiplexing of multiple SCCP connections |
| 18 | * and/or RSL channels and are hence suitable for higher-level test cases, while |
| 19 | * the "raw" tests directly on top of the CodecPorts are more suitable for lower- |
| 20 | * level testing. |
| 21 | */ |
| 22 | |
| 23 | import from BSC_Tests all; |
| 24 | |
| 25 | import from Misc_Helpers all; |
| 26 | import from General_Types all; |
| 27 | import from Osmocom_Types all; |
| 28 | import from GSM_Types all; |
| 29 | import from IPL4asp_Types all; |
| 30 | |
| 31 | import from BSSAP_Types all; |
| 32 | import from RAN_Adapter all; |
| 33 | import from BSSAP_LE_Adapter all; |
| 34 | import from BSSAP_LE_CodecPort all; |
| 35 | import from BSSAP_LE_Types all; |
| 36 | import from BSSLAP_Types all; |
| 37 | import from BSSAP_CodecPort all; |
| 38 | import from BSSMAP_Templates all; |
| 39 | import from IPA_Emulation all; |
| 40 | import from IPA_CodecPort all; |
| 41 | import from IPA_Types all; |
| 42 | import from IPA_Testing all; |
| 43 | import from RSL_Types all; |
| 44 | import from RSL_Emulation all; |
| 45 | import from MGCP_Emulation all; |
| 46 | import from MGCP_Templates all; |
| 47 | import from MGCP_Types all; |
| 48 | import from MGCP_CodecPort all; |
| 49 | |
| 50 | import from Osmocom_CTRL_Functions all; |
| 51 | import from Osmocom_CTRL_Types all; |
| 52 | import from Osmocom_CTRL_Adapter all; |
| 53 | |
| 54 | import from StatsD_Types all; |
| 55 | import from StatsD_CodecPort all; |
| 56 | import from StatsD_CodecPort_CtrlFunct all; |
| 57 | import from StatsD_Checker all; |
| 58 | |
| 59 | import from Osmocom_VTY_Functions all; |
| 60 | import from TELNETasp_PortType all; |
| 61 | |
| 62 | import from MobileL3_CommonIE_Types all; |
| 63 | import from MobileL3_Types all; |
| 64 | import from MobileL3_RRM_Types all; |
| 65 | import from L3_Templates all; |
| 66 | import from GSM_RR_Types all; |
| 67 | |
| 68 | import from SCCP_Templates all; |
| 69 | import from BSSMAP_Templates all; |
| 70 | import from BSSMAP_LE_Templates all; |
| 71 | |
| 72 | import from SCCPasp_Types all; |
| 73 | |
| 74 | import from GSM_SystemInformation all; |
| 75 | import from GSM_RestOctets all; |
| 76 | import from TCCConversion_Functions all; |
| 77 | |
| 78 | import from RAN_Emulation all; |
| 79 | import from MSC_ConnectionHandler all; |
| 80 | |
| 81 | import from Native_Functions all; |
| 82 | |
| 83 | const integer NUM_BTS := 3; |
| 84 | const integer NUM_MSC := 3; |
| 85 | |
| 86 | private function f_rsl_chan_nr_to_subslot(RslChannelNr chan_nr) |
| 87 | return integer |
| 88 | { |
| 89 | var integer subslot; |
| 90 | select (chan_nr) { |
| 91 | case (t_RslChanNr_Bm(?)) { |
| 92 | /* TCH/F, always subslot 0 */ |
| 93 | subslot := 0; |
| 94 | } |
| 95 | case (t_RslChanNr_Lm(?, ?)) { |
| 96 | /* TCH/H */ |
| 97 | subslot := chan_nr.u.lm.sub_chan; |
| 98 | } |
| 99 | case (t_RslChanNr_Osmo_VAMOS_Bm(?)) { |
| 100 | /* TCH/F, always subslot 0 */ |
| 101 | subslot := 0; |
| 102 | } |
| 103 | case (t_RslChanNr_Osmo_VAMOS_Lm(?, ?)) { |
| 104 | /* TCH/H */ |
| 105 | subslot := chan_nr.u.lm.sub_chan; |
| 106 | } |
| 107 | case else { |
| 108 | setverdict(fail, "unsupported RslChannelNr type in f_rsl_chan_nr_to_subslot()"); |
| 109 | mtc.stop; |
| 110 | } |
| 111 | } |
| 112 | return subslot; |
| 113 | } |
| 114 | |
| 115 | private function f_rsl_chan_nr_to_rsl_cbits(RslChannelNr chan_nr) |
| 116 | return BIT5 |
| 117 | { |
| 118 | var BIT5 rsl_cbits; |
| 119 | select (chan_nr) { |
| 120 | case (t_RslChanNr_Bm(?)) { |
| 121 | rsl_cbits := '00001'B; |
| 122 | } |
| 123 | case (t_RslChanNr_Lm(?, ?)) { |
| 124 | rsl_cbits := int2bit(2 + chan_nr.u.lm.sub_chan, 5); /* '0001x'B */ |
| 125 | } |
| 126 | case (t_RslChanNr_Osmo_VAMOS_Bm(?)) { |
| 127 | rsl_cbits := '11101'B; |
| 128 | } |
| 129 | case (t_RslChanNr_Osmo_VAMOS_Lm(?, ?)) { |
| 130 | rsl_cbits := int2bit(30 + chan_nr.u.lm.sub_chan, 5); /* '1111x'B */ |
| 131 | } |
| 132 | case else { |
| 133 | setverdict(fail, "unsupported RslChannelNr type in f_rsl_chan_nr_to_rsl_cbits()"); |
| 134 | mtc.stop; |
| 135 | } |
| 136 | } |
| 137 | return rsl_cbits; |
| 138 | } |
| 139 | |
| 140 | private function f_rsl_chan_nr_to_rr_cbits(RslChannelNr chan_nr) |
| 141 | return BIT5 |
| 142 | { |
| 143 | var BIT5 rr_cbits; |
| 144 | select (chan_nr) { |
| 145 | case (t_RslChanNr_Bm(?)) { |
| 146 | rr_cbits := '00001'B; |
| 147 | } |
| 148 | case (t_RslChanNr_Lm(?, ?)) { |
| 149 | rr_cbits := int2bit(2 + chan_nr.u.lm.sub_chan, 5); /* '0001x'B */ |
| 150 | } |
| 151 | case (t_RslChanNr_Osmo_VAMOS_Bm(?)) { |
| 152 | rr_cbits := '00001'B; |
| 153 | /* In RR, there must *not* be Osmocom specific cbits */ |
| 154 | } |
| 155 | case (t_RslChanNr_Osmo_VAMOS_Lm(?, ?)) { |
| 156 | rr_cbits := int2bit(2 + chan_nr.u.lm.sub_chan, 5); /* '0001x'B */ |
| 157 | /* In RR, there must *not* be Osmocom specific cbits */ |
| 158 | } |
| 159 | case else { |
| 160 | setverdict(fail, "unsupported RslChannelNr type in f_rsl_chan_nr_to_rr_cbits()"); |
| 161 | mtc.stop; |
| 162 | } |
| 163 | } |
| 164 | return rr_cbits; |
| 165 | } |
| 166 | |
| 167 | private function f_rsl_chan_nr_to_chrt(RslChannelNr chan_nr, boolean vamos) |
| 168 | return RSL_ChanRateType |
| 169 | { |
| 170 | var boolean fr; |
| 171 | select (chan_nr) { |
| 172 | case (t_RslChanNr_Bm(?)) { |
| 173 | fr := true; |
| 174 | } |
| 175 | case (t_RslChanNr_Lm(?, ?)) { |
| 176 | fr := false; |
| 177 | } |
| 178 | case (t_RslChanNr_Osmo_VAMOS_Bm(?)) { |
| 179 | fr := true; |
| 180 | } |
| 181 | case (t_RslChanNr_Osmo_VAMOS_Lm(?, ?)) { |
| 182 | fr := false; |
| 183 | } |
| 184 | case else { |
| 185 | setverdict(fail, "unsupported RslChannelNr type in f_rsl_chan_nr_to_chrt()"); |
| 186 | mtc.stop; |
| 187 | } |
| 188 | } |
| 189 | if (fr) { |
| 190 | if (vamos) { |
| 191 | return RSL_CHRT_OSMO_TCH_F_VAMOS; |
| 192 | } else { |
| 193 | return RSL_CHRT_TCH_F; |
| 194 | } |
| 195 | } else { |
| 196 | if (vamos) { |
| 197 | return RSL_CHRT_OSMO_TCH_H_VAMOS; |
| 198 | } else { |
| 199 | return RSL_CHRT_TCH_H; |
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | private function f_lchan_str(integer bts_nr, integer trx_nr, RslChannelNr chan_nr) |
| 205 | return charstring |
| 206 | { |
| 207 | var integer subslot := f_rsl_chan_nr_to_subslot(chan_nr); |
| 208 | return "lchan " & int2str(bts_nr) & " " & int2str(trx_nr) & " " & int2str(chan_nr.tn) & " " & int2str(subslot); |
| 209 | } |
| 210 | |
| 211 | private function f_long_lchan_str(integer bts_nr, integer trx_nr, RslChannelNr chan_nr) |
| 212 | return charstring |
| 213 | { |
| 214 | var integer subslot := f_rsl_chan_nr_to_subslot(chan_nr); |
| 215 | return "bts " & int2str(bts_nr) & " trx " & int2str(trx_nr) & " timeslot " & int2str(chan_nr.tn) & " sub-slot " & int2str(subslot); |
| 216 | } |
| 217 | |
| 218 | private function f_lchan_ensure_established(TELNETasp_PT vty, integer bts_nr, integer trx_nr, RslChannelNr chan_nr) |
| 219 | { |
| 220 | var charstring lchan_str := f_lchan_str(bts_nr, trx_nr, chan_nr); |
| 221 | var charstring lchan_info := f_vty_transceive_ret(vty, "show " & lchan_str); |
| 222 | if (f_strstr(lchan_info, "State: ESTABLISHED") < 0) { |
| 223 | log("'show lchan' replied: ", lchan_info); |
| 224 | setverdict(fail, "lchan " & lchan_str & " is not in state ESTABLISHED"); |
| 225 | mtc.stop; |
| 226 | } |
| 227 | setverdict(pass); |
| 228 | } |
| 229 | |
| 230 | /* Activate a primary lchan in VAMOS speech mode */ |
| 231 | testcase TC_chan_act_to_vamos() runs on test_CT { |
| 232 | f_init_vty(); |
| 233 | |
| 234 | f_logp(BSCVTY, "TC_chan_act_to_vamos"); |
| 235 | |
| 236 | f_init(1, false); |
| 237 | f_sleep(1.0); |
| 238 | |
| 239 | f_vty_transceive(BSCVTY, "bts 0 trx 0 timeslot 1 sub-slot 0 activate-vamos fr"); |
| 240 | |
| 241 | var RSL_Message rsl; |
| 242 | |
| 243 | rsl := f_exp_ipa_rx(0, tr_RSL_MsgTypeD(RSL_MT_CHAN_ACTIV)); |
| 244 | |
| 245 | var RSL_IE_Body chan_mode_ie; |
| 246 | if (f_rsl_find_ie(rsl, RSL_IE_CHAN_MODE, chan_mode_ie) == false) { |
| 247 | setverdict(fail, "Cannot find RSL_IE_CHAN_MODE"); |
| 248 | mtc.stop; |
| 249 | } |
| 250 | if (chan_mode_ie.chan_mode.ch_rate_type != RSL_CHRT_OSMO_TCH_F_VAMOS) { |
| 251 | setverdict(fail, "expected chan_mode.ch_rate_type == RSL_CHRT_OSMO_TCH_F_VAMOS"); |
| 252 | mtc.stop; |
| 253 | } |
| 254 | |
| 255 | var RSL_IE_Body osmo_tsc_ie; |
| 256 | if (f_rsl_find_ie(rsl, RSL_IE_OSMO_TRAINING_SEQUENCE, osmo_tsc_ie) == false) { |
| 257 | setverdict(fail, "Cannot find RSL_IE_OSMO_TRAINING_SEQUENCE"); |
| 258 | mtc.stop; |
| 259 | } |
| 260 | |
| 261 | var RslChannelNr chan_nr := rsl.ies[0].body.chan_nr; |
| 262 | f_ipa_tx(0, ts_RSL_CHAN_ACT_ACK(chan_nr, 23+10)); |
| 263 | |
| 264 | f_sleep(1.0); |
| 265 | f_lchan_ensure_established(BSCVTY, 0, 0, chan_nr); |
| 266 | |
Vadim Yanitskiy | ce8eb85 | 2022-02-07 14:15:10 +0600 | [diff] [blame] | 267 | f_vty_transceive(BSCVTY, "bts 0 trx 0 timeslot 1 sub-slot 0 deactivate"); |
| 268 | |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 269 | f_shutdown_helper(); |
| 270 | } |
| 271 | |
| 272 | /* verify that DTAP passes through both ways with the right cbits */ |
| 273 | private function f_verify_dtap() runs on MSC_ConnHdlr |
| 274 | { |
| 275 | var octetstring l3_data := '00010203040506'O; |
| 276 | var PDU_BSSAP rx_bssap_dtap; |
| 277 | |
| 278 | /* MS to NW */ |
| 279 | RSL.send(ts_RSL_DATA_IND(g_chan_nr, valueof(ts_RslLinkID_DCCH(0)), l3_data)); |
| 280 | BSSAP.receive(tr_BSSAP_DTAP) -> value rx_bssap_dtap; |
| 281 | if (not match(rx_bssap_dtap.pdu.dtap, l3_data)) { |
| 282 | setverdict(fail, "unexpected L3 data"); |
| 283 | mtc.stop; |
| 284 | } |
| 285 | |
| 286 | /* NW to MS */ |
| 287 | l3_data := '0800dcba9876543210'O; |
| 288 | BSSAP.send(ts_BSSAP_DTAP(l3_data, '00'O)); |
| 289 | RSL.receive(tr_RSL_DATA_REQ(g_chan_nr, tr_RslLinkID_DCCH(0), l3_data)); |
| 290 | } |
| 291 | |
| 292 | |
| 293 | private function f_est_lchan_and_mode_modify_to_vamos() runs on MSC_ConnHdlr { |
| 294 | var PDU_BSSAP ass_cmd := f_gen_ass_req(g_pars.use_osmux); |
| 295 | var template PDU_BSSAP exp_compl := f_gen_exp_compl(g_pars.use_osmux); |
| 296 | |
| 297 | /* puzzle together the ASSIGNMENT REQ for given codec[s] */ |
| 298 | if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_AoIP) { |
| 299 | ass_cmd.pdu.bssmap.assignmentRequest.codecList := g_pars.ass_codec_list; |
| 300 | exp_compl.pdu.bssmap.assignmentComplete.speechCodec.codecElements[0] := |
| 301 | g_pars.ass_codec_list.codecElements[0]; |
| 302 | if (isvalue(g_pars.expect_mr_s0_s7)) { |
| 303 | exp_compl.pdu.bssmap.assignmentComplete.speechCodec.codecElements[0].s0_7 := |
| 304 | g_pars.expect_mr_s0_s7; |
| 305 | } |
| 306 | } |
| 307 | ass_cmd.pdu.bssmap.assignmentRequest.channelType := |
| 308 | f_BSSMAP_chtype_from_codec(g_pars.ass_codec_list.codecElements[0]); |
| 309 | log("expecting ASS COMPL like this: ", exp_compl); |
| 310 | |
| 311 | f_establish_fully(ass_cmd, exp_compl); |
| 312 | |
| 313 | f_lchan_ensure_established(BSCVTY, 0, 0, g_chan_nr); |
| 314 | |
| 315 | var charstring current_long_lchan_str := f_long_lchan_str(0, 0, g_chan_nr); |
| 316 | f_vty_transceive(BSCVTY, current_long_lchan_str & " modify vamos tsc 2 3"); |
| 317 | |
| 318 | var RSL_Message rsl_rr; |
| 319 | RSL.receive(tr_RSL_DATA_REQ(g_chan_nr)) -> value rsl_rr; |
| 320 | |
| 321 | var PDU_ML3_NW_MS l3 := dec_PDU_ML3_NW_MS(rsl_rr.ies[2].body.l3_info.payload); |
| 322 | |
| 323 | var integer current_subslot := f_rsl_chan_nr_to_subslot(g_chan_nr); |
| 324 | |
| 325 | template PDU_ML3_NW_MS expect_rr_modify := tr_RRM_ModeModify( |
| 326 | tr_ChannelDescription2_V(timeslotNumber := int2bit(g_chan_nr.tn, 3)), |
| 327 | tr_ChannelMode_V(mode := 'C1'O /* 1 1 0 0 0 0 0 1 speech full rate or half rate version 1 in VAMOS mode (3GPP TS 44.018) */), |
| 328 | extendedTSCSet := tr_ExtendedTSCSet_TV(cSDomainTSCSet := '01'B)); |
| 329 | |
| 330 | if (not match(l3, expect_rr_modify)) { |
| 331 | log("expected: ", expect_rr_modify); |
| 332 | log("got: ", l3); |
| 333 | setverdict(fail, "RR channelModeModify message is not as expected"); |
| 334 | mtc.stop; |
| 335 | } |
| 336 | f_rsl_reply(ts_RRM_ModeModifyAck(l3.msgs.rrm.channelModeModify.channelDescription, |
| 337 | l3.msgs.rrm.channelModeModify.channelMode, |
| 338 | l3.msgs.rrm.channelModeModify.extendedTSCSet), rsl_rr); |
| 339 | |
| 340 | var RSL_Message rsl; |
| 341 | RSL.receive(tr_RSL_MODE_MODIFY_REQ_with_OSMO_TSC(g_chan_nr, tr_RSL_ChanMode(f_rsl_chan_nr_to_chrt(g_chan_nr, true), RSL_CMOD_SP_GSM1), |
| 342 | tsc_set := 1, /* 1 means TSC Set 2 (range 1-4 in spec tables and naming, 0-3 on the wire) */ |
| 343 | tsc := 3)); |
| 344 | RSL.send(ts_RSL_MODE_MODIFY_ACK(g_chan_nr)); |
| 345 | f_sleep(1.0); |
| 346 | |
| 347 | f_lchan_ensure_established(BSCVTY, 0, 0, g_chan_nr); |
| 348 | f_verify_dtap(); |
| 349 | } |
| 350 | |
| 351 | private function f_TC_mode_modify_to_vamos(charstring id) runs on MSC_ConnHdlr { |
| 352 | f_est_lchan_and_mode_modify_to_vamos(); |
Vadim Yanitskiy | 41b702f | 2022-02-07 14:16:14 +0600 | [diff] [blame] | 353 | f_perform_clear(RSL); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 354 | } |
| 355 | |
| 356 | /* Modify a primary lchan into VAMOS speech mode */ |
| 357 | testcase TC_mode_modify_to_vamos_fr() runs on test_CT { |
| 358 | var TestHdlrParams pars := f_gen_test_hdlr_pars(); |
| 359 | var MSC_ConnHdlr vc_conn; |
| 360 | |
| 361 | f_init(1, true); |
| 362 | f_sleep(1.0); |
| 363 | |
| 364 | pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR})); |
| 365 | vc_conn := f_start_handler(refers(f_TC_mode_modify_to_vamos), pars); |
| 366 | vc_conn.done; |
| 367 | f_shutdown_helper(); |
| 368 | } |
| 369 | |
| 370 | /* Modify a primary lchan into VAMOS speech mode */ |
| 371 | testcase TC_mode_modify_to_vamos_hr() runs on test_CT { |
| 372 | var TestHdlrParams pars := f_gen_test_hdlr_pars(); |
| 373 | var MSC_ConnHdlr vc_conn; |
| 374 | |
| 375 | f_init(1, true); |
| 376 | f_sleep(1.0); |
| 377 | |
| 378 | pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR})); |
| 379 | vc_conn := f_start_handler(refers(f_TC_mode_modify_to_vamos), pars); |
| 380 | vc_conn.done; |
| 381 | f_shutdown_helper(); |
| 382 | } |
| 383 | |
| 384 | /* Establish a primary lchan, and then do a re-assignment to a VAMOS shadow lchan. */ |
| 385 | private function f_reassign_secondary_to_primary_lchan(RslChannelNr new_chan_nr) runs on MSC_ConnHdlr |
| 386 | { |
| 387 | var integer current_subslot := f_rsl_chan_nr_to_subslot(g_chan_nr); |
| 388 | |
| 389 | var integer new_subslot := f_rsl_chan_nr_to_subslot(new_chan_nr); |
| 390 | var BIT5 new_rr_cbits := f_rsl_chan_nr_to_rr_cbits(new_chan_nr); |
| 391 | |
| 392 | activate(as_Media_mgw()); |
| 393 | |
| 394 | f_rslem_register(0, new_chan_nr, RSL_PROC); |
| 395 | log("f_rslem_register(0, new_chan_nr = ", new_chan_nr, ")"); |
| 396 | |
| 397 | f_vty_transceive(BSCVTY, "bts 0 trx 0 timeslot " & int2str(g_chan_nr.tn) & " vamos-sub-slot " & int2str(current_subslot) |
| 398 | & " reassign-to trx 0 timeslot " & int2str(new_chan_nr.tn) & " sub-slot " & int2str(new_subslot)); |
| 399 | /* RSL CHAN ACT is ACKed by RSL emulation */ |
| 400 | |
| 401 | var RSL_Message rsl; |
| 402 | var RSL_IE_Body ie; |
| 403 | var boolean b_unused; |
| 404 | interleave { |
| 405 | [] RSL.receive(tr_RSL_DATA_REQ(g_chan_nr)) -> value rsl { |
| 406 | var PDU_ML3_NW_MS l3 := dec_PDU_ML3_NW_MS(rsl.ies[2].body.l3_info.payload); |
| 407 | var template PDU_ML3_NW_MS expect_rr_assignment := tr_RR_AssignmentCommand( |
| 408 | desc := tr_ChannelDescription2_V(timeslotNumber := int2bit(new_chan_nr.tn, 3), |
| 409 | channelTypeandTDMAOffset := new_rr_cbits), |
| 410 | mode := tr_ChannelMode_TV(mode := '01'O |
| 411 | /* 0 0 0 0 0 0 0 1 speech full rate or half rate version 1 (3GPP TS 44.018) */), |
| 412 | extendedTSCSet := omit); |
| 413 | if (not match(l3, expect_rr_assignment)) { |
| 414 | log("expected: ", expect_rr_assignment); |
| 415 | log("got: ", l3); |
| 416 | setverdict(fail, "RR assignmentCommand message is not as expected"); |
| 417 | mtc.stop; |
| 418 | } |
| 419 | |
| 420 | var PDU_ML3_MS_NW l3_tx := valueof(ts_RRM_AssignmentComplete('00'O)); |
| 421 | RSL.send(ts_RSL_EST_IND(new_chan_nr, valueof(ts_RslLinkID_DCCH(0)), |
| 422 | enc_PDU_ML3_MS_NW(l3_tx))); |
| 423 | |
| 424 | } |
| 425 | [] RSL.receive(tr_RSL_IPA_CRCX(new_chan_nr)) -> value rsl { |
| 426 | var uint7_t rtp_pt := 0; |
| 427 | if (f_rsl_find_ie(rsl, RSL_IE_IPAC_RTP_PAYLOAD, ie)) { |
| 428 | rtp_pt := ie.ipa_rtp_pt; |
| 429 | } |
| 430 | RSL.send(ts_RSL_IPA_CRCX_ACK(new_chan_nr, 123, |
Vadim Yanitskiy | fc63164 | 2021-07-03 02:42:45 +0200 | [diff] [blame] | 431 | f_inet_addr("1.2.3.4"), |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 432 | 4321, |
| 433 | rtp_pt)); |
| 434 | } |
| 435 | [] RSL.receive(tr_RSL_IPA_MDCX(new_chan_nr, ?)) -> value rsl{ |
| 436 | /* Extract conn_id, ip, port, rtp_pt2 from request + use in response */ |
| 437 | b_unused := f_rsl_find_ie(rsl, RSL_IE_IPAC_CONN_ID, ie); |
| 438 | var uint16_t conn_id := ie.ipa_conn_id; |
| 439 | /* mandatory */ |
| 440 | b_unused := f_rsl_find_ie(rsl, RSL_IE_IPAC_REMOTE_IP, ie); |
| 441 | var HostPort peer; |
Vadim Yanitskiy | fc63164 | 2021-07-03 02:42:45 +0200 | [diff] [blame] | 442 | peer.host := f_inet_ntoa(ie.ipa_remote_ip); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 443 | b_unused := f_rsl_find_ie(rsl, RSL_IE_IPAC_REMOTE_PORT, ie); |
| 444 | peer.port_nr := ie.ipa_remote_port; |
| 445 | var uint7_t rtp_pt := 0; |
| 446 | /* optional */ |
| 447 | if (f_rsl_find_ie(rsl, RSL_IE_IPAC_RTP_PAYLOAD, ie)) { |
| 448 | rtp_pt := ie.ipa_rtp_pt; |
| 449 | } |
| 450 | RSL.send(ts_RSL_IPA_MDCX_ACK(new_chan_nr, conn_id, |
Vadim Yanitskiy | fc63164 | 2021-07-03 02:42:45 +0200 | [diff] [blame] | 451 | f_inet_addr(peer.host), |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 452 | peer.port_nr, |
| 453 | rtp_pt)); |
| 454 | } |
| 455 | [] RSL.receive(tr_RSL_DEACT_SACCH(g_chan_nr)) {} |
| 456 | [] RSL.receive(tr_RSL_RF_CHAN_REL(g_chan_nr)) { |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 457 | RSL.send(ts_ASP_RSL_UD(ts_RSL_RF_CHAN_REL_ACK(g_chan_nr), |
| 458 | IPAC_PROTO_RSL_TRX0)); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 459 | f_rslem_unregister(0, g_chan_nr, RSL_PROC); |
| 460 | g_chan_nr := new_chan_nr; |
| 461 | } |
| 462 | /* (There must be no RSL_MT_REL_REQ on the old lchan.) */ |
| 463 | } |
| 464 | |
| 465 | setverdict(pass); |
| 466 | |
| 467 | f_sleep(1.0); |
| 468 | f_vty_transceive(BSCVTY, "show lchan summary"); |
| 469 | |
| 470 | f_verify_dtap(); |
| 471 | } |
| 472 | |
| 473 | private function f_est_and_reassign_to_secondary_lchan(RslChannelNr new_chan_nr) runs on MSC_ConnHdlr |
| 474 | { |
| 475 | var integer new_subslot := f_rsl_chan_nr_to_subslot(new_chan_nr); |
| 476 | var BIT5 new_rr_cbits := f_rsl_chan_nr_to_rr_cbits(new_chan_nr); |
| 477 | |
| 478 | var PDU_BSSAP ass_cmd := f_gen_ass_req(); |
| 479 | var template PDU_BSSAP exp_compl := f_gen_exp_compl(); |
| 480 | |
| 481 | /* puzzle together the ASSIGNMENT REQ for given codec[s] */ |
| 482 | if (mp_bssap_cfg[0].transport == BSSAP_TRANSPORT_AoIP) { |
| 483 | ass_cmd.pdu.bssmap.assignmentRequest.codecList := g_pars.ass_codec_list; |
| 484 | exp_compl.pdu.bssmap.assignmentComplete.speechCodec.codecElements[0] := |
| 485 | g_pars.ass_codec_list.codecElements[0]; |
| 486 | if (isvalue(g_pars.expect_mr_s0_s7)) { |
| 487 | exp_compl.pdu.bssmap.assignmentComplete.speechCodec.codecElements[0].s0_7 := |
| 488 | g_pars.expect_mr_s0_s7; |
| 489 | } |
| 490 | } |
| 491 | ass_cmd.pdu.bssmap.assignmentRequest.channelType := |
| 492 | f_BSSMAP_chtype_from_codec(g_pars.ass_codec_list.codecElements[0]); |
| 493 | log("expecting ASS COMPL like this: ", exp_compl); |
| 494 | |
| 495 | f_establish_fully(ass_cmd, exp_compl); |
| 496 | |
| 497 | var integer current_subslot := f_rsl_chan_nr_to_subslot(g_chan_nr); |
| 498 | |
| 499 | f_sleep(1.0); |
| 500 | |
| 501 | activate(as_Media_mgw()); |
| 502 | |
| 503 | f_rslem_register(0, new_chan_nr, RSL_PROC); |
| 504 | log("f_rslem_register(0, new_chan_nr = ", new_chan_nr, ")"); |
| 505 | |
| 506 | f_vty_transceive(BSCVTY, "bts 0 trx 0 timeslot " & int2str(g_chan_nr.tn) & " sub-slot " & int2str(current_subslot) |
| 507 | & " reassign-to trx 0 timeslot " & int2str(new_chan_nr.tn) & " vamos-sub-slot " & int2str(new_subslot) & " tsc 4 2"); |
| 508 | /* RSL CHAN ACT is ACKed by RSL emulation */ |
| 509 | |
| 510 | var RSL_Message rsl; |
| 511 | var RSL_IE_Body ie; |
| 512 | var boolean b_unused; |
| 513 | interleave { |
| 514 | [] RSL.receive(tr_RSL_DATA_REQ(g_chan_nr)) -> value rsl { |
| 515 | var PDU_ML3_NW_MS l3 := dec_PDU_ML3_NW_MS(rsl.ies[2].body.l3_info.payload); |
| 516 | var template PDU_ML3_NW_MS expect_rr_assignment := tr_RR_AssignmentCommand( |
| 517 | desc := tr_ChannelDescription2_V(timeslotNumber := int2bit(new_chan_nr.tn, 3), |
| 518 | channelTypeandTDMAOffset := new_rr_cbits), |
| 519 | mode := tr_ChannelMode_TV(mode := 'C1'O |
| 520 | /* 1 1 0 0 0 0 0 1 speech full rate or half rate version 1 in VAMOS mode (3GPP TS 44.018) */), |
| 521 | extendedTSCSet := tr_ExtendedTSCSet_TV(cSDomainTSCSet := '11'B |
| 522 | /* 3 means TSC Set 4 (range 1-4 in spec tables and naming, 0-3 on the wire) */)); |
| 523 | if (not match(l3, expect_rr_assignment)) { |
| 524 | log("expected: ", expect_rr_assignment); |
| 525 | log("got: ", l3); |
| 526 | setverdict(fail, "RR assignmentCommand message is not as expected"); |
| 527 | mtc.stop; |
| 528 | } |
| 529 | |
| 530 | var PDU_ML3_MS_NW l3_tx := valueof(ts_RRM_AssignmentComplete('00'O)); |
| 531 | RSL.send(ts_RSL_EST_IND(new_chan_nr, valueof(ts_RslLinkID_DCCH(0)), |
| 532 | enc_PDU_ML3_MS_NW(l3_tx))); |
| 533 | |
| 534 | } |
| 535 | [] RSL.receive(tr_RSL_IPA_CRCX(new_chan_nr)) -> value rsl { |
| 536 | var uint7_t rtp_pt := 0; |
| 537 | if (f_rsl_find_ie(rsl, RSL_IE_IPAC_RTP_PAYLOAD, ie)) { |
| 538 | rtp_pt := ie.ipa_rtp_pt; |
| 539 | } |
| 540 | RSL.send(ts_RSL_IPA_CRCX_ACK(new_chan_nr, 123, |
Vadim Yanitskiy | fc63164 | 2021-07-03 02:42:45 +0200 | [diff] [blame] | 541 | f_inet_addr("1.2.3.4"), |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 542 | 4321, |
| 543 | rtp_pt)); |
| 544 | } |
| 545 | [] RSL.receive(tr_RSL_IPA_MDCX(new_chan_nr, ?)) -> value rsl{ |
| 546 | /* Extract conn_id, ip, port, rtp_pt2 from request + use in response */ |
| 547 | b_unused := f_rsl_find_ie(rsl, RSL_IE_IPAC_CONN_ID, ie); |
| 548 | var uint16_t conn_id := ie.ipa_conn_id; |
| 549 | /* mandatory */ |
| 550 | b_unused := f_rsl_find_ie(rsl, RSL_IE_IPAC_REMOTE_IP, ie); |
| 551 | var HostPort peer; |
Vadim Yanitskiy | fc63164 | 2021-07-03 02:42:45 +0200 | [diff] [blame] | 552 | peer.host := f_inet_ntoa(ie.ipa_remote_ip); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 553 | b_unused := f_rsl_find_ie(rsl, RSL_IE_IPAC_REMOTE_PORT, ie); |
| 554 | peer.port_nr := ie.ipa_remote_port; |
| 555 | var uint7_t rtp_pt := 0; |
| 556 | /* optional */ |
| 557 | if (f_rsl_find_ie(rsl, RSL_IE_IPAC_RTP_PAYLOAD, ie)) { |
| 558 | rtp_pt := ie.ipa_rtp_pt; |
| 559 | } |
| 560 | RSL.send(ts_RSL_IPA_MDCX_ACK(new_chan_nr, conn_id, |
Vadim Yanitskiy | fc63164 | 2021-07-03 02:42:45 +0200 | [diff] [blame] | 561 | f_inet_addr(peer.host), |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 562 | peer.port_nr, |
| 563 | rtp_pt)); |
| 564 | } |
| 565 | [] RSL.receive(tr_RSL_DEACT_SACCH(g_chan_nr)) {} |
| 566 | [] RSL.receive(tr_RSL_RF_CHAN_REL(g_chan_nr)) { |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 567 | RSL.send(ts_ASP_RSL_UD(ts_RSL_RF_CHAN_REL_ACK(g_chan_nr), |
| 568 | IPAC_PROTO_RSL_TRX0)); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 569 | f_rslem_unregister(0, g_chan_nr, RSL_PROC); |
| 570 | g_chan_nr := new_chan_nr; |
| 571 | } |
| 572 | /* (There must be no RSL_MT_REL_REQ on the old lchan.) */ |
| 573 | } |
| 574 | |
| 575 | setverdict(pass); |
| 576 | |
| 577 | f_sleep(1.0); |
| 578 | f_vty_transceive(BSCVTY, "show lchan summary"); |
| 579 | |
| 580 | f_verify_dtap(); |
| 581 | } |
| 582 | |
| 583 | /* Establish a primary lchan, and then do a re-assignment to a VAMOS shadow lchan. |
| 584 | * Also re-assign back to a primary lchan. */ |
| 585 | private function f_TC_assign_to_secondary_lchan_fr(charstring id) runs on MSC_ConnHdlr { |
| 586 | f_est_and_reassign_to_secondary_lchan(valueof(t_RslChanNr_Osmo_VAMOS_Bm(2))); |
| 587 | f_reassign_secondary_to_primary_lchan(valueof(t_RslChanNr_Bm(3))); |
| 588 | f_perform_clear(RSL); |
| 589 | f_sleep(1.0); |
| 590 | } |
| 591 | |
| 592 | /* Establish a primary lchan, and then do a re-assignment to a VAMOS shadow lchan. */ |
| 593 | testcase TC_assign_to_secondary_lchan_fr() runs on test_CT { |
| 594 | var TestHdlrParams pars := f_gen_test_hdlr_pars(); |
| 595 | var MSC_ConnHdlr vc_conn; |
| 596 | |
| 597 | f_init(1, true); |
| 598 | f_sleep(1.0); |
| 599 | |
| 600 | pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR})); |
| 601 | vc_conn := f_start_handler(refers(f_TC_assign_to_secondary_lchan_fr), pars); |
| 602 | vc_conn.done; |
| 603 | f_shutdown_helper(); |
| 604 | } |
| 605 | |
| 606 | /* Establish a primary lchan, and then do a re-assignment to a VAMOS shadow lchan. |
| 607 | * Also re-assign back to a primary lchan. */ |
| 608 | private function f_TC_assign_to_secondary_lchan_hr(charstring id) runs on MSC_ConnHdlr { |
| 609 | f_est_and_reassign_to_secondary_lchan(valueof(t_RslChanNr_Osmo_VAMOS_Lm(6, 0))); |
| 610 | f_reassign_secondary_to_primary_lchan(valueof(t_RslChanNr_Lm(6, 1))); |
| 611 | f_perform_clear(RSL); |
| 612 | f_sleep(1.0); |
| 613 | } |
| 614 | |
| 615 | /* Establish a primary lchan, and then do a re-assignment to a VAMOS shadow lchan. */ |
| 616 | testcase TC_assign_to_secondary_lchan_hr() runs on test_CT { |
| 617 | var TestHdlrParams pars := f_gen_test_hdlr_pars(); |
| 618 | var MSC_ConnHdlr vc_conn; |
| 619 | |
| 620 | f_init(1, true); |
| 621 | f_sleep(1.0); |
| 622 | |
| 623 | pars.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR})); |
| 624 | vc_conn := f_start_handler(refers(f_TC_assign_to_secondary_lchan_hr), pars); |
| 625 | vc_conn.done; |
| 626 | f_shutdown_helper(); |
| 627 | } |
| 628 | |
Vadim Yanitskiy | 7bd04e4 | 2022-02-07 14:18:38 +0600 | [diff] [blame^] | 629 | const charstring PRIMARY_LCHAN_DONE := "PRIMARY_LCHAN_DONE"; |
| 630 | const charstring MULTIPLEX_DONE := "MULTIPLEX_DONE"; |
| 631 | |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 632 | /* First, primary lchan of TC_vamos_multiplex_tch_f_tch_f() */ |
| 633 | private function f_TC_vamos_multiplex_tch_f_tch_f1(charstring id) runs on MSC_ConnHdlr { |
| 634 | f_est_lchan_and_mode_modify_to_vamos(); |
Vadim Yanitskiy | 7bd04e4 | 2022-02-07 14:18:38 +0600 | [diff] [blame^] | 635 | f_sleep(1.0); |
| 636 | COORD.send(PRIMARY_LCHAN_DONE); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 637 | f_logp(BSCVTY, "f_est_lchan_and_mode_modify_to_vamos done"); |
Vadim Yanitskiy | 7bd04e4 | 2022-02-07 14:18:38 +0600 | [diff] [blame^] | 638 | COORD.receive(MULTIPLEX_DONE); |
| 639 | f_perform_clear(RSL); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 640 | } |
| 641 | |
| 642 | /* Second, VAMOS shadow lchan of TC_vamos_multiplex_tch_f_tch_f() */ |
| 643 | private function f_TC_vamos_multiplex_tch_f_tch_f2(charstring id) runs on MSC_ConnHdlr { |
Vadim Yanitskiy | 7bd04e4 | 2022-02-07 14:18:38 +0600 | [diff] [blame^] | 644 | f_sleep(1.0); |
| 645 | COORD.receive(PRIMARY_LCHAN_DONE); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 646 | f_est_and_reassign_to_secondary_lchan(valueof(t_RslChanNr_Osmo_VAMOS_Bm(1))); |
Vadim Yanitskiy | 7bd04e4 | 2022-02-07 14:18:38 +0600 | [diff] [blame^] | 647 | f_sleep(1.0); |
| 648 | COORD.send(MULTIPLEX_DONE); |
| 649 | f_perform_clear(RSL); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 650 | } |
| 651 | |
| 652 | /* Establish a primary lchan and modify it to VAMOS speech mode. Then establish |
| 653 | * another primary lchan, and re-assign it to the VAMOS secondary lchan of the |
| 654 | * first primary lchan. */ |
| 655 | testcase TC_vamos_multiplex_tch_f_tch_f() runs on test_CT { |
| 656 | var TestHdlrParams pars1 := f_gen_test_hdlr_pars(); |
| 657 | var MSC_ConnHdlr vc_conn1; |
| 658 | |
| 659 | var TestHdlrParams pars2 := f_gen_test_hdlr_pars(); |
| 660 | var MSC_ConnHdlr vc_conn2; |
| 661 | pars2.imsi := '001014234234234'H; |
| 662 | pars2.media_nr := 2; |
| 663 | |
| 664 | f_init(1, true); |
| 665 | f_sleep(1.0); |
| 666 | |
| 667 | pars1.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR})); |
| 668 | pars2.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecFR})); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 669 | |
Vadim Yanitskiy | 7bd04e4 | 2022-02-07 14:18:38 +0600 | [diff] [blame^] | 670 | vc_conn1 := f_start_handler(refers(f_TC_vamos_multiplex_tch_f_tch_f1), pars1); |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 671 | vc_conn2 := f_start_handler(refers(f_TC_vamos_multiplex_tch_f_tch_f2), pars2); |
Vadim Yanitskiy | 7bd04e4 | 2022-02-07 14:18:38 +0600 | [diff] [blame^] | 672 | connect(vc_conn1:COORD, vc_conn2:COORD); |
| 673 | |
| 674 | vc_conn1.done; |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 675 | vc_conn2.done; |
Vadim Yanitskiy | 7bd04e4 | 2022-02-07 14:18:38 +0600 | [diff] [blame^] | 676 | |
Neels Hofmeyr | 9f3e6ac | 2021-04-08 23:09:24 +0200 | [diff] [blame] | 677 | f_shutdown_helper(); |
| 678 | } |
| 679 | |
| 680 | /* First, primary lchan of TC_vamos_multiplex_tch_h_tch_h_tch_h_tch_h() */ |
| 681 | private function f_TC_vamos_multiplex_tch_h_tch_h1(charstring id) runs on MSC_ConnHdlr { |
| 682 | f_est_lchan_and_mode_modify_to_vamos(); |
| 683 | f_logp(BSCVTY, "f_est_lchan_and_mode_modify_to_vamos done"); |
| 684 | } |
| 685 | |
| 686 | /* Second, VAMOS shadow lchan of TC_vamos_multiplex_tch_h_tch_h_tch_h_tch_h() */ |
| 687 | private function f_TC_vamos_multiplex_tch_h_tch_h2(charstring id) runs on MSC_ConnHdlr { |
| 688 | f_est_and_reassign_to_secondary_lchan(valueof(t_RslChanNr_Osmo_VAMOS_Lm(5, 0))); |
| 689 | } |
| 690 | |
| 691 | private function f_TC_vamos_multiplex_tch_h_tch_h4(charstring id) runs on MSC_ConnHdlr { |
| 692 | f_est_and_reassign_to_secondary_lchan(valueof(t_RslChanNr_Osmo_VAMOS_Lm(5, 1))); |
| 693 | } |
| 694 | |
| 695 | /* Establish a primary lchan and modify it to VAMOS speech mode. Then establish |
| 696 | * another primary lchan, and re-assign it to the VAMOS secondary lchan of the |
| 697 | * first primary lchan. */ |
| 698 | testcase TC_vamos_multiplex_tch_h_tch_h_tch_h_tch_h() runs on test_CT { |
| 699 | var TestHdlrParams pars1 := f_gen_test_hdlr_pars(); |
| 700 | var MSC_ConnHdlr vc_conn1; |
| 701 | pars1.imsi := '001011111111111'H; |
| 702 | pars1.media_nr := 1; |
| 703 | |
| 704 | var TestHdlrParams pars2 := f_gen_test_hdlr_pars(); |
| 705 | var MSC_ConnHdlr vc_conn2; |
| 706 | pars2.imsi := '001012222222222'H; |
| 707 | pars2.media_nr := 2; |
| 708 | |
| 709 | var TestHdlrParams pars3 := f_gen_test_hdlr_pars(); |
| 710 | var MSC_ConnHdlr vc_conn3; |
| 711 | pars3.imsi := '001013333333333'H; |
| 712 | pars3.media_nr := 3; |
| 713 | |
| 714 | var TestHdlrParams pars4 := f_gen_test_hdlr_pars(); |
| 715 | var MSC_ConnHdlr vc_conn4; |
| 716 | pars4.imsi := '001014444444444'H; |
| 717 | pars4.media_nr := 4; |
| 718 | |
| 719 | f_init(1, true); |
| 720 | f_sleep(1.0); |
| 721 | |
| 722 | pars1.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR})); |
| 723 | pars2.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR})); |
| 724 | pars3.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR})); |
| 725 | pars4.ass_codec_list := valueof(ts_BSSMAP_IE_CodecList({ts_CodecHR})); |
| 726 | |
| 727 | vc_conn1 := f_start_handler(refers(f_TC_vamos_multiplex_tch_h_tch_h1), pars1); |
| 728 | vc_conn1.done; |
| 729 | |
| 730 | vc_conn2 := f_start_handler(refers(f_TC_vamos_multiplex_tch_h_tch_h2), pars2); |
| 731 | vc_conn2.done; |
| 732 | |
| 733 | /* Also fill up the second subslot of the TCH/H timeslot */ |
| 734 | vc_conn3 := f_start_handler(refers(f_TC_vamos_multiplex_tch_h_tch_h1), pars3); |
| 735 | vc_conn3.done; |
| 736 | |
| 737 | vc_conn4 := f_start_handler(refers(f_TC_vamos_multiplex_tch_h_tch_h4), pars4); |
| 738 | vc_conn4.done; |
| 739 | f_shutdown_helper(); |
| 740 | } |
| 741 | |
| 742 | control { |
| 743 | execute( TC_chan_act_to_vamos() ); |
| 744 | execute( TC_mode_modify_to_vamos_fr() ); |
| 745 | execute( TC_mode_modify_to_vamos_hr() ); |
| 746 | execute( TC_assign_to_secondary_lchan_fr() ); |
| 747 | execute( TC_assign_to_secondary_lchan_hr() ); |
| 748 | execute( TC_vamos_multiplex_tch_f_tch_f() ); |
| 749 | execute( TC_vamos_multiplex_tch_h_tch_h_tch_h_tch_h() ); |
| 750 | } |
| 751 | |
| 752 | } |