diff --git a/library/MNCC_Emulation.ttcn b/library/MNCC_Emulation.ttcn index be087ec78..49b1249cc 100644 --- a/library/MNCC_Emulation.ttcn +++ b/library/MNCC_Emulation.ttcn @@ -38,7 +38,7 @@ import from MNCC_Types all; import from UD_Types all; modulepar { - int mp_mncc_version := 6; + int mp_mncc_version := 7; } /* General "base class" component definition, of which specific implementations @@ -266,6 +266,11 @@ type record MnccOps { function main(MnccOps ops, charstring id, charstring sock, boolean role_server := false) runs on MNCC_Emulation_CT { + if (not set_MNCC_version(mp_mncc_version)) { + setverdict(fail, "Failed configuring MNCC enc/dec to version ", mp_mncc_version); + return; + } + if (role_server) { f_listen(sock); MNCC.send(t_SD_MNCC(g_mncc_ud_id, ts_MNCC_HELLO(version := mp_mncc_version))); diff --git a/library/MNCC_EncDec.cc b/library/MNCC_EncDec.cc index f2692d7a7..be5d01a5a 100644 --- a/library/MNCC_EncDec.cc +++ b/library/MNCC_EncDec.cc @@ -5,6 +5,16 @@ namespace MNCC__Types { +static int mncc_sock_version = MNCC_SOCK_VERSION; + +BOOLEAN set__MNCC__version(INTEGER const& version) +{ + if (version != 6 && version != 7) + return false; + mncc_sock_version = version; + return true; +} + static void enc_bcap(struct gsm_mncc_bearer_cap *out, const MNCC__bearer__cap& in) { out->transfer = in.transfer(); @@ -76,6 +86,7 @@ OCTETSTRING enc__MNCC__PDU(const MNCC__PDU& in) { struct gsm_mncc mncc; OCTETSTRING ret_val; + TTCN_Buffer ttcn_buffer; memset(&mncc, 0, sizeof(mncc)); mncc.msg_type = in.msg__type(); @@ -184,15 +195,46 @@ OCTETSTRING enc__MNCC__PDU(const MNCC__PDU& in) ret_val = ret_val & in.u().data().data(); break; case MNCC__MsgUnion::ALT_rtp: - struct gsm_mncc_rtp rtp; - memset(&rtp, 0, sizeof(rtp)); - rtp.msg_type = in.msg__type(); - rtp.callref = in.u().rtp().callref(); - rtp.ip = in.u().rtp().ip(); - rtp.port = in.u().rtp().rtp__port(); - rtp.payload_type = in.u().rtp().payload__type(); - rtp.payload_msg_type = in.u().rtp().payload__msg__type(); - ret_val = OCTETSTRING(sizeof(rtp), (uint8_t *) &rtp); + switch (mncc_sock_version) { + case 6: + struct gsm_mncc_rtp_mncc6 rtp_old; + memset(&rtp_old, 0, sizeof(rtp_old)); + rtp_old.msg_type = in.msg__type(); + rtp_old.callref = in.u().rtp().callref(); + ttcn_buffer.put_string(in.u().rtp().ip()); + if (!in.u().rtp().is__ipv6()) { + memcpy(&rtp_old.ip, ttcn_buffer.get_data(), sizeof(struct in_addr)); + rtp_old.ip = ntohl(rtp_old.ip); + } /* else: ipv6 not supported in MNCCv6 */ + rtp_old.port = in.u().rtp().rtp__port(); + rtp_old.payload_type = in.u().rtp().payload__type(); + rtp_old.payload_msg_type = in.u().rtp().payload__msg__type(); + ret_val = OCTETSTRING(sizeof(rtp_old), (uint8_t *) &rtp_old); + break; + case 7: + struct gsm_mncc_rtp rtp; + memset(&rtp, 0, sizeof(rtp)); + rtp.msg_type = in.msg__type(); + rtp.callref = in.u().rtp().callref(); + ttcn_buffer.put_string(in.u().rtp().ip()); + if (in.u().rtp().is__ipv6()) { + // if(in.u().rtp().ip().lengthof() != 16) print error + rtp.addr.ss_family = AF_INET6; + memcpy(&((struct sockaddr_in6*)&rtp.addr)->sin6_addr, ttcn_buffer.get_data(), + sizeof(struct in6_addr)); + ((struct sockaddr_in6*)&rtp.addr)->sin6_port = htons(in.u().rtp().rtp__port()); + } else { + // if(in.u().rtp().ip().lengthof() != 4) print error + rtp.addr.ss_family = AF_INET; + memcpy(&((struct sockaddr_in*)&rtp.addr)->sin_addr, ttcn_buffer.get_data(), + sizeof(struct in_addr)); + ((struct sockaddr_in*)&rtp.addr)->sin_port = htons(in.u().rtp().rtp__port()); + } + rtp.payload_type = in.u().rtp().payload__type(); + rtp.payload_msg_type = in.u().rtp().payload__msg__type(); + ret_val = OCTETSTRING(sizeof(rtp), (uint8_t *) &rtp); + break; + } break; case MNCC__MsgUnion::ALT_hello: struct gsm_mncc_hello hello; @@ -222,8 +264,12 @@ MNCC__PDU dec__MNCC__PDU(const OCTETSTRING& in) const struct gsm_data_frame *in_data; MNCC__PDU__Data data; const struct gsm_mncc_rtp *in_rtp; + const struct gsm_mncc_rtp_mncc6 *in_rtp_old; MNCC__PDU__Rtp rtp; MNCC__MsgUnion u; + bool is_ipv6; + OCTETSTRING ip; + uint16_t port; in_mncc = (struct gsm_mncc *) ttcn_buffer.get_read_data(); @@ -257,10 +303,40 @@ MNCC__PDU dec__MNCC__PDU(const OCTETSTRING& in) case MNCC_RTP_CREATE: case MNCC_RTP_CONNECT: case MNCC_RTP_FREE: - in_rtp = (const struct gsm_mncc_rtp *) in_mncc; - rtp = MNCC__PDU__Rtp(in_rtp->callref, in_rtp->ip, in_rtp->port, in_rtp->payload_type, - in_rtp->payload_msg_type, in_rtp->sdp); - u.rtp() = rtp; + switch (mncc_sock_version) { + case 6: + struct in_addr inaddr; + in_rtp_old = (const struct gsm_mncc_rtp_mncc6 *) in_mncc; + inaddr.s_addr = htonl(in_rtp_old->ip); + ip = OCTETSTRING(sizeof(struct in_addr), + (const unsigned char*)&inaddr); + rtp = MNCC__PDU__Rtp(in_rtp_old->callref, false, ip, in_rtp_old->port, in_rtp_old->payload_type, + in_rtp_old->payload_msg_type, in_rtp_old->sdp); + u.rtp() = rtp; + break; + case 7: + in_rtp = (const struct gsm_mncc_rtp *) in_mncc; + switch (in_rtp->addr.ss_family) { + case AF_INET6: + is_ipv6 = true; + port = ntohs(((struct sockaddr_in6*)&in_rtp->addr)->sin6_port); + ip = OCTETSTRING(sizeof(struct in6_addr), + (const unsigned char*)&((struct sockaddr_in6*)&in_rtp->addr)->sin6_addr); + + break; + case AF_UNSPEC: //RTP_CREATE and RTP_FREE can contain fully zeroed addr + case AF_INET: + is_ipv6 = false; + port = ntohs(((struct sockaddr_in*)&in_rtp->addr)->sin_port); + ip = OCTETSTRING(sizeof(struct in_addr), + (const unsigned char*)&((struct sockaddr_in*)&in_rtp->addr)->sin_addr); + break; + } + rtp = MNCC__PDU__Rtp(in_rtp->callref, is_ipv6, ip, port, in_rtp->payload_type, + in_rtp->payload_msg_type, in_rtp->sdp); + u.rtp() = rtp; + break; + } break; default: sign.callref() = in_mncc->callref; diff --git a/library/MNCC_Types.ttcn b/library/MNCC_Types.ttcn index 0a8e7d9f0..bd233cea9 100644 --- a/library/MNCC_Types.ttcn +++ b/library/MNCC_Types.ttcn @@ -373,7 +373,8 @@ type record MNCC_PDU_Data { type record MNCC_PDU_Rtp { uint32_t callref, - uint32_t ip, + boolean is_ipv6, + octetstring ip, uint16_t rtp_port, uint32_t payload_type, uint32_t payload_msg_type, @@ -421,6 +422,8 @@ external function enc_MNCC_PDU(in MNCC_PDU pdu) return octetstring; external function dec_MNCC_PDU(in octetstring stream) return MNCC_PDU; +external function set_MNCC_version(in integer version) return boolean; + template (value) MNCC_PDU ts_MNCC_HELLO(uint32_t version := 5) := { msg_type := MNCC_SOCKET_HELLO, u := { @@ -1921,7 +1924,8 @@ template MNCC_PDU ts_MNCC_SIMPLE_RTP(MNCC_MsgType msg_type, uint32_t call_id) := u := { rtp := { callref := call_id, - ip := 0, + is_ipv6 := false, + ip := '00000000'O, rtp_port := 0, payload_type := 0, payload_msg_type := 0, @@ -1935,13 +1939,14 @@ template MNCC_PDU ts_MNCC_RTP_CREATE(uint32_t call_id) := ts_MNCC_SIMPLE_RTP(MNC /* MSC -> MNCC: RTP_CREATE.rsp; acknowledge creation of RTP (stating MSC side IP/Port) */ template MNCC_PDU tr_MNCC_RTP_CREATE(template uint32_t call_id := ?, - template uint32_t ip := ?, - template uint32_t rtp_port := ?, + template octetstring ip := ?, + template uint16_t rtp_port := ?, template uint32_t payload_type := ?) := { msg_type := MNCC_RTP_CREATE, u := { rtp := { callref := call_id, + is_ipv6 := ?, ip := ip, rtp_port := rtp_port, payload_type := payload_type, @@ -1952,11 +1957,12 @@ template MNCC_PDU tr_MNCC_RTP_CREATE(template uint32_t call_id := ?, } /* MSC <- MNCC: RTP_CONNECT.req; request connect of RTP */ -template MNCC_PDU ts_MNCC_RTP_CONNECT(uint32_t call_id, uint32_t ip, uint32_t rtp_port, uint32_t pt) := { +template MNCC_PDU ts_MNCC_RTP_CONNECT(uint32_t call_id, boolean is_ipv6, octetstring ip, uint16_t rtp_port, uint32_t pt) := { msg_type := MNCC_RTP_CONNECT, u := { rtp := { callref := call_id, + is_ipv6 := is_ipv6, ip := ip, rtp_port := rtp_port, payload_type := pt, @@ -1966,13 +1972,14 @@ template MNCC_PDU ts_MNCC_RTP_CONNECT(uint32_t call_id, uint32_t ip, uint32_t rt } } template MNCC_PDU tr_MNCC_RTP_CONNECT(template uint32_t call_id, - template uint32_t ip := ?, - template uint32_t rtp_port := ?, + template octetstring ip := ?, + template uint16_t rtp_port := ?, template uint32_t pt := ?) := { msg_type := MNCC_RTP_CONNECT, u := { rtp := { callref := call_id, + is_ipv6 := ?, ip := ip, rtp_port := rtp_port, payload_type := pt, diff --git a/library/mncc.h b/library/mncc.h index 9aff94812..a55d155bf 100644 --- a/library/mncc.h +++ b/library/mncc.h @@ -5,6 +5,7 @@ */ #include +#include /* GSM 04.08 Bearer Capability: Rate Adaption */ enum gsm48_bcap_ra { @@ -275,7 +276,7 @@ struct gsm_data_frame { unsigned char data[0]; }; -#define MNCC_SOCK_VERSION 5 +#define MNCC_SOCK_VERSION 7 struct gsm_mncc_hello { uint32_t msg_type; uint32_t version; @@ -291,11 +292,22 @@ struct gsm_mncc_hello { uint32_t lchan_type_offset; }; +/* Use this one in MNCCv6 */ +struct gsm_mncc_rtp_mncc6 { + uint32_t msg_type; + uint32_t callref; + uint32_t ip; + uint16_t port; + uint32_t payload_type; + uint32_t payload_msg_type; + + char sdp[1024]; +}; + struct gsm_mncc_rtp { uint32_t msg_type; uint32_t callref; - uint32_t ip; - uint16_t port; + struct sockaddr_storage addr; uint32_t payload_type; uint32_t payload_msg_type; diff --git a/msc/BSC_ConnectionHandler.ttcn b/msc/BSC_ConnectionHandler.ttcn index 24a56b290..9218c760f 100644 --- a/msc/BSC_ConnectionHandler.ttcn +++ b/msc/BSC_ConnectionHandler.ttcn @@ -15,6 +15,7 @@ module BSC_ConnectionHandler { import from General_Types all; import from Osmocom_Types all; import from Native_Functions all; +import from Misc_Helpers all; import from GSM_Types all; import from IPL4asp_Types all; import from SCCPasp_Types all; @@ -813,6 +814,8 @@ type record CallParameters { /* MNCC related parameters */ uint32_t mncc_callref optional, /* call reference on the MNCC side */ MNCC_bearer_cap mncc_bearer_cap optional, /* MNCC-side bearer capabilities */ + HostName mncc_rtp_ip optional, /* MNCC Side RTP IP */ + PortNumber mncc_rtp_port optional, /* MNCC Side RTP port */ /* RTP related parameters */ HostName bss_rtp_ip optional, /* BSS Side RTP IP */ @@ -845,6 +848,8 @@ template (value) CallParameters t_CallParams(hexstring called := '12345'H, integ emergency := false, mncc_callref := omit, mncc_bearer_cap := valueof(ts_MNCC_bcap_voice), + mncc_rtp_ip := "42.23.11.5", + mncc_rtp_port := 423, bss_rtp_ip := "9.8.7.6", bss_rtp_port := 9000, mss_rtp_ip := omit, @@ -979,9 +984,16 @@ runs on BSC_ConnHdlr { [] MNCC.receive(tr_MNCC_SETUP_cnf(cpars.mncc_callref)) { log("f_mt_call_complete 7"); + var octetstring ip; + var boolean is_ipv6 := f_addr_is_ipv6(cpars.mncc_rtp_ip); + if (is_ipv6) { + ip := f_inet6_addr(cpars.mncc_rtp_ip); + } else { + ip := f_inet_addr(cpars.mncc_rtp_ip); + } MNCC.send(ts_MNCC_RTP_CONNECT(cpars.mncc_callref, - /* ip 42.23.11.5 */ hex2int('42231105'H), - /* port 423 */ 423, + is_ipv6, ip, + cpars.mncc_rtp_port, /* payload type 3 = GSM FR */ 3)); } @@ -1064,9 +1076,16 @@ runs on BSC_ConnHdlr { [] MNCC.receive(tr_MNCC_SETUP_cnf(cpars.mncc_callref)) { log("f_mt_call_complete 7.iu"); + var octetstring ip; + var boolean is_ipv6 := f_addr_is_ipv6(cpars.mncc_rtp_ip); + if (is_ipv6) { + ip := f_inet6_addr(cpars.mncc_rtp_ip); + } else { + ip := f_inet_addr(cpars.mncc_rtp_ip); + } MNCC.send(ts_MNCC_RTP_CONNECT(cpars.mncc_callref, - /* ip 42.23.11.5 */ hex2int('42231105'H), - /* port 423 */ 423, + is_ipv6, ip, + cpars.mncc_rtp_port, /* payload type 3 = GSM FR */ 3)); } @@ -1458,9 +1477,16 @@ runs on BSC_ConnHdlr { cpars.mncc_callref := mncc.u.signal.callref; /* Call Proceeding */ + var octetstring ip; + var boolean is_ipv6 := f_addr_is_ipv6(cpars.mncc_rtp_ip); + if (is_ipv6) { + ip := f_inet6_addr(cpars.mncc_rtp_ip); + } else { + ip := f_inet_addr(cpars.mncc_rtp_ip); + } MNCC.send(ts_MNCC_RTP_CONNECT(cpars.mncc_callref, - /* ip 42.23.11.5 */ hex2int('42231105'H), - /* port 423 */ 423, + is_ipv6, ip, + cpars.mncc_rtp_port, /* payload type 3 = GSM FR */ 3)); MNCC.send(ts_MNCC_SETUP_rsp(cpars.mncc_callref)); } diff --git a/msc/MSC_Tests.ttcn b/msc/MSC_Tests.ttcn index fb2a46ed2..5129c5bd3 100644 --- a/msc/MSC_Tests.ttcn +++ b/msc/MSC_Tests.ttcn @@ -1979,6 +1979,7 @@ friend function f_tc_lu_and_mt_call_ipv6(charstring id, BSC_ConnHdlrPars pars) r cpars.mgw_conn_1.mgw_rtp_ip := "::1"; cpars.mgw_conn_2.mgw_rtp_ip := "::2"; cpars.bss_rtp_ip := "::3"; + cpars.mncc_rtp_ip := "::9"; f_perform_lu(); f_mt_call(cpars); } diff --git a/sip/SIP_Tests.default b/sip/SIP_Tests.default index faf87c8d0..1c8c2dd6f 100644 --- a/sip/SIP_Tests.default +++ b/sip/SIP_Tests.default @@ -25,7 +25,7 @@ mtc.FileMask := ERROR | WARNING | PARALLEL | VERDICTOP; [MODULE_PARAMETERS] Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoSIPcon"; -MNCC_Emulation.mp_mncc_version := 6; +MNCC_Emulation.mp_mncc_version := 7; [MAIN_CONTROLLER]