mncc: Support IPv6 addresses (new version mncc 7)

Apparently commit 06b859ca314f53a902329ed95848dbafef1d4f87 forgot to
bump the MNCC_SOCK_VERSION field from 5 to 6.

Change-Id: I5448ff931ec33f24f4837a51376f1703fe97683b
diff --git a/library/MNCC_Emulation.ttcn b/library/MNCC_Emulation.ttcn
index be087ec..49b1249 100644
--- a/library/MNCC_Emulation.ttcn
+++ b/library/MNCC_Emulation.ttcn
@@ -38,7 +38,7 @@
 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 @@
 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 f2692d7..be5d01a 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 @@
 {
 	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 @@
 		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 @@
 	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 @@
 	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 0a8e7d9..bd233ce 100644
--- a/library/MNCC_Types.ttcn
+++ b/library/MNCC_Types.ttcn
@@ -373,7 +373,8 @@
 
 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 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 @@
 	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 @@
 
 /* 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 @@
 }
 
 /* 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 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 9aff948..a55d155 100644
--- a/library/mncc.h
+++ b/library/mncc.h
@@ -5,6 +5,7 @@
  */
 
 #include <stdint.h>
+#include <netinet/in.h>
 
 /* GSM 04.08 Bearer Capability: Rate Adaption */
 enum gsm48_bcap_ra {
@@ -275,7 +276,7 @@
 	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 @@
 	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 24a56b2..9218c76 100644
--- a/msc/BSC_ConnectionHandler.ttcn
+++ b/msc/BSC_ConnectionHandler.ttcn
@@ -15,6 +15,7 @@
 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 @@
 	/* 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 @@
 	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 @@
 
 		[] 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 @@
 
 		[] 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 @@
 
 		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 fb2a46e..5129c5b 100644
--- a/msc/MSC_Tests.ttcn
+++ b/msc/MSC_Tests.ttcn
@@ -1979,6 +1979,7 @@
 	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 faf87c8..1c8c2dd 100644
--- a/sip/SIP_Tests.default
+++ b/sip/SIP_Tests.default
@@ -25,7 +25,7 @@
 
 [MODULE_PARAMETERS]
 Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoSIPcon";
-MNCC_Emulation.mp_mncc_version := 6;
+MNCC_Emulation.mp_mncc_version := 7;
 
 [MAIN_CONTROLLER]