Implement IuCS (large refactoring and addition)

osmo-nitb becomes osmo-msc
add DIUCS debug log constant
add iucs.[hc]
add msc vty, remove nitb vty
add libiudummy, to avoid linking Iu deps in tests
Use new msc_tx_dtap() instead of gsm0808_submit_dtap()
libmgcp: add mgcpgw client API
bridge calls via mgcpgw

Enable MSC specific CTRL commands, bsc_base_ctrl_cmds_install() still needs to
be split up.

Change-Id: I5b5b6a9678b458affa86800afb1ec726e66eed88
diff --git a/include/openbsc/Makefile.am b/include/openbsc/Makefile.am
index 1dfe6c3..2558d7c 100644
--- a/include/openbsc/Makefile.am
+++ b/include/openbsc/Makefile.am
@@ -14,6 +14,7 @@
 	bss.h \
 	bts_ipaccess_nanobts_omlattr.h \
 	chan_alloc.h \
+	common.h \
 	common_bsc.h \
 	common_cs.h \
 	crc24.h \
@@ -46,11 +47,14 @@
 	handover_decision.h \
 	ipaccess.h \
 	iu.h \
+	iucs.h \
+	iucs_ranap.h \
 	meas_feed.h \
 	meas_rep.h \
 	mgcp.h \
 	mgcp_internal.h \
 	mgcp_transcode.h \
+	mgcpgw_client.h \
 	misdn.h \
 	mncc.h \
 	mncc_int.h \
diff --git a/include/openbsc/common.h b/include/openbsc/common.h
new file mode 100644
index 0000000..d91b3d3
--- /dev/null
+++ b/include/openbsc/common.h
@@ -0,0 +1,6 @@
+#pragma once
+
+enum nsap_addr_enc {
+	NSAP_ADDR_ENC_X213,
+	NSAP_ADDR_ENC_V4RAW,
+};
diff --git a/include/openbsc/debug.h b/include/openbsc/debug.h
index 3feb7c3..de00b29 100644
--- a/include/openbsc/debug.h
+++ b/include/openbsc/debug.h
@@ -39,6 +39,7 @@
 	DV42BIS,
 	DPCU,
 	DVLR,
+	DIUCS,
 	Debug_LastEntry,
 };
 
diff --git a/include/openbsc/gprs_gmm.h b/include/openbsc/gprs_gmm.h
index d210a35..c38e49f 100644
--- a/include/openbsc/gprs_gmm.h
+++ b/include/openbsc/gprs_gmm.h
@@ -30,6 +30,6 @@
 
 time_t gprs_max_time_to_idle(void);
 
-int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp, bool use_x213_nsap);
+int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp);
 
 #endif /* _GPRS_GMM_H */
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h
index 17b3d71..c307fee 100644
--- a/include/openbsc/gsm_data.h
+++ b/include/openbsc/gsm_data.h
@@ -13,8 +13,10 @@
 
 #include <osmocom/crypt/auth.h>
 
+#include <openbsc/common.h>
 #include <openbsc/rest_octets.h>
 #include <openbsc/common_cs.h>
+#include <openbsc/mgcpgw_client.h>
 
 /** annotations for msgb ownership */
 #define __uses
@@ -109,6 +111,10 @@
        RAN_UTRAN_IU,	/* 3G / Iu-interface (IuCS or IuPS) */
 };
 
+extern const struct value_string ran_type_names[];
+static inline const char *ran_type_name(enum ran_type val)
+{	return get_value_string(ran_type_names, val);	}
+
 struct gsm_classmark {
 	bool classmark1_set;
 	struct gsm48_classmark1 classmark1;
@@ -190,7 +196,10 @@
 	/* which Iu-CS connection, if any. */
 	struct {
 		struct ue_conn_ctx *ue_ctx;
-		int integrity_protection;
+		unsigned int mgcp_rtp_endpoint;
+		uint16_t mgcp_rtp_port_ue;
+		uint16_t mgcp_rtp_port_cn;
+		uint8_t rab_id;
 	} iu;
 };
 
@@ -371,6 +380,11 @@
 	struct mncc_sock_state *mncc_state;
 	mncc_recv_cb_t mncc_recv;
 	struct llist_head upqueue;
+	/*
+	 * TODO: Move the trans_list into the subscriber connection and
+	 * create a pending list for MT transactions. These exist before
+	 * we have a subscriber connection.
+	 */
 	struct llist_head trans_list;
 	struct bsc_api *bsc_api;
 
@@ -441,6 +455,15 @@
 
 	/* Periodic location update default value */
 	uint8_t t3212;
+
+	struct {
+		struct mgcpgw_client_conf conf;
+		struct mgcpgw_client *client;
+	} mgcpgw;
+
+	struct {
+		enum nsap_addr_enc rab_assign_addr_enc;
+	} iu;
 };
 
 struct osmo_esme;
diff --git a/include/openbsc/gsm_subscriber.h b/include/openbsc/gsm_subscriber.h
index 60eb0cd..d88e32a 100644
--- a/include/openbsc/gsm_subscriber.h
+++ b/include/openbsc/gsm_subscriber.h
@@ -41,6 +41,9 @@
 struct subscr_request {
        struct llist_head entry;
 
+       /* human readable label to be able to log pending request kinds */
+       const char *label;
+
        /* the callback data */
        gsm_cbfn *cbfn;
        void *param;
@@ -52,15 +55,14 @@
  * Paging handling with authentication
  */
 struct subscr_request *subscr_request_conn(struct vlr_subscr *vsub,
-					   int channel_type,
-					   gsm_cbfn *cbfn, void *param);
+					   gsm_cbfn *cbfn, void *param,
+					   const char *label);
 
 void subscr_remove_request(struct subscr_request *req);
+int subscr_rx_paging_response(struct msgb *msg,
+			      struct gsm_subscriber_connection *conn);
 
 int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
 			   struct msgb *msg, void *data, void *param);
 
-int msc_fake_paging_request(struct vlr_subscr *vsub);
-void msc_fake_paging_request_stop(struct vlr_subscr *vsub);
-
 #endif /* _GSM_SUBSCR_H */
diff --git a/include/openbsc/iu.h b/include/openbsc/iu.h
index 8cf830e..5b29830 100644
--- a/include/openbsc/iu.h
+++ b/include/openbsc/iu.h
@@ -1,13 +1,25 @@
 #pragma once
 
 #include <stdbool.h>
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/gsm48.h>
+
+#include <openbsc/common.h>
 
 struct sgsn_pdp_ctx;
 struct msgb;
-struct gprs_ra_id;
+struct osmo_sccp_link;
+struct gsm_auth_tuple;
 
 struct RANAP_RAB_SetupOrModifiedItemIEs_s;
 struct RANAP_GlobalRNC_ID;
+struct RANAP_Cause;
+
+/* Debugging switches from asn1c and osmo-iuh */
+extern int asn_debug;
+extern int asn1_xer_print;
 
 struct ue_conn_ctx {
 	struct llist_head list;
@@ -15,6 +27,7 @@
 	uint32_t conn_id;
 	int integrity_active;
 	struct gprs_ra_id ra_id;
+	enum nsap_addr_enc rab_assign_addr_enc;
 };
 
 enum iu_event_type {
@@ -54,5 +67,8 @@
 int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id);
 int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp,
 		       int send_ck, int new_key);
+int iu_tx_common_id(struct ue_conn_ctx *ue_ctx, const char *imsi);
+int iu_tx_release(struct ue_conn_ctx *ctx, const struct RANAP_Cause *cause);
 
-void iu_vty_init(int *asn_debug_p);
+void iu_vty_init(int iu_parent_node, enum nsap_addr_enc *rab_assign_addr_enc);
+int iu_vty_config_write(struct vty *vty, const char *indent);
diff --git a/include/openbsc/iucs.h b/include/openbsc/iucs.h
new file mode 100644
index 0000000..fb61a5c
--- /dev/null
+++ b/include/openbsc/iucs.h
@@ -0,0 +1,7 @@
+#pragma once
+
+int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
+			uint16_t *lac);
+
+struct gsm_subscriber_connection *subscr_conn_lookup_iu(struct gsm_network *network,
+							struct ue_conn_ctx *ue);
diff --git a/include/openbsc/iucs_ranap.h b/include/openbsc/iucs_ranap.h
new file mode 100644
index 0000000..748de23
--- /dev/null
+++ b/include/openbsc/iucs_ranap.h
@@ -0,0 +1,7 @@
+#pragma once
+
+struct gsm_network;
+struct ue_conn_ctx;
+
+int iucs_rx_ranap_event(struct gsm_network *network,
+			struct ue_conn_ctx *ue_ctx, int type, void *data);
diff --git a/include/openbsc/mgcp.h b/include/openbsc/mgcp.h
index b2262bc..7cf83b2 100644
--- a/include/openbsc/mgcp.h
+++ b/include/openbsc/mgcp.h
@@ -170,6 +170,21 @@
 	MGCP_BSC_NAT,
 };
 
+enum mgcp_connection_mode {
+	MGCP_CONN_NONE = 0,
+	MGCP_CONN_RECV_ONLY = 1,
+	MGCP_CONN_SEND_ONLY = 2,
+	MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
+	MGCP_CONN_LOOPBACK  = 4 | MGCP_CONN_RECV_SEND,
+};
+
+extern const struct value_string mgcp_connection_mode_strs[];
+
+static inline const char *mgcp_cmode_name(enum mgcp_connection_mode mode)
+{
+	return get_value_string(mgcp_connection_mode_strs, mode);
+}
+
 struct mgcp_config {
 	int source_port;
 	char *local_ip;
diff --git a/include/openbsc/mgcp_internal.h b/include/openbsc/mgcp_internal.h
index 7c89d10..b58eb9b 100644
--- a/include/openbsc/mgcp_internal.h
+++ b/include/openbsc/mgcp_internal.h
@@ -28,14 +28,6 @@
 
 #define CI_UNUSED 0
 
-enum mgcp_connection_mode {
-	MGCP_CONN_NONE = 0,
-	MGCP_CONN_RECV_ONLY = 1,
-	MGCP_CONN_SEND_ONLY = 2,
-	MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
-	MGCP_CONN_LOOPBACK  = 4 | MGCP_CONN_RECV_SEND,
-};
-
 enum mgcp_trunk_type {
 	MGCP_TRUNK_VIRTUAL,
 	MGCP_TRUNK_E1,
@@ -340,3 +332,5 @@
 		return endp->cfg->bts_ports.bind_addr;
 	return endp->cfg->source_addr;
 }
+
+int mgcp_msg_terminate_nul(struct msgb *msg);
diff --git a/include/openbsc/mgcpgw_client.h b/include/openbsc/mgcpgw_client.h
new file mode 100644
index 0000000..b353db0
--- /dev/null
+++ b/include/openbsc/mgcpgw_client.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+
+enum mgcp_connection_mode;
+
+struct msgb;
+struct mgcpgw_client;
+struct vty;
+
+#define MGCPGW_CLIENT_LOCAL_ADDR_DEFAULT "0.0.0.0"
+#define MGCPGW_CLIENT_LOCAL_PORT_DEFAULT 0
+#define MGCPGW_CLIENT_REMOTE_ADDR_DEFAULT "127.0.0.1"
+#define MGCPGW_CLIENT_REMOTE_PORT_DEFAULT 2427
+
+#define MSGB_CB_MGCP_TRANS_ID 0
+
+typedef unsigned int mgcp_trans_id_t;
+
+struct mgcpgw_client_conf {
+	const char *local_addr;
+	int local_port;
+	const char *remote_addr;
+	int remote_port;
+};
+
+struct mgcp_response_head {
+       int response_code;
+       mgcp_trans_id_t trans_id;
+       const char *comment;
+};
+
+struct mgcp_response {
+	char *body;
+	struct mgcp_response_head head;
+	uint16_t audio_port;
+};
+
+/* Invoked when an MGCP response is received or sending failed.  When the
+ * response is passed as NULL, this indicates failure during transmission. */
+typedef void (* mgcp_response_cb_t )(struct mgcp_response *response, void *priv);
+
+struct mgcp_response_pending {
+	struct llist_head entry;
+
+	mgcp_trans_id_t trans_id;
+	mgcp_response_cb_t response_cb;
+	void *priv;
+};
+
+
+void mgcpgw_client_conf_init(struct mgcpgw_client_conf *conf);
+
+struct mgcpgw_client *mgcpgw_client_init(void *ctx,
+					 struct mgcpgw_client_conf *conf);
+int mgcpgw_client_connect(struct mgcpgw_client *mgcp);
+
+const char *mgcpgw_client_remote_addr_str(struct mgcpgw_client *mgcp);
+uint16_t mgcpgw_client_remote_port(struct mgcpgw_client *mgcp);
+uint32_t mgcpgw_client_remote_addr_n(struct mgcpgw_client *mgcp);
+
+unsigned int mgcpgw_client_next_endpoint(struct mgcpgw_client *client);
+
+int mgcp_response_parse_params(struct mgcp_response *r);
+
+int mgcpgw_client_tx(struct mgcpgw_client *mgcp, struct msgb *msg,
+		     mgcp_response_cb_t response_cb, void *priv);
+
+struct msgb *mgcp_msg_crcx(struct mgcpgw_client *mgcp,
+			   uint16_t rtp_endpoint, unsigned int call_id,
+			   enum mgcp_connection_mode mode);
+
+struct msgb *mgcp_msg_mdcx(struct mgcpgw_client *mgcp,
+			   uint16_t rtp_endpoint, const char *rtp_conn_addr,
+			   uint16_t rtp_port, enum mgcp_connection_mode mode);
+
+void mgcpgw_client_vty_init(int node, struct mgcpgw_client_conf *conf);
+int mgcpgw_client_config_write(struct vty *vty, const char *indent);
+
+struct mgcp_response_pending * mgcpgw_client_pending_add(
+					struct mgcpgw_client *mgcp,
+					mgcp_trans_id_t trans_id,
+					mgcp_response_cb_t response_cb,
+					void *priv);
+int mgcpgw_client_rx(struct mgcpgw_client *mgcp, struct msgb *msg);
diff --git a/include/openbsc/msc_ifaces.h b/include/openbsc/msc_ifaces.h
index 83aad92..2965c72 100644
--- a/include/openbsc/msc_ifaces.h
+++ b/include/openbsc/msc_ifaces.h
@@ -22,7 +22,7 @@
  * the compiler complains about an undefined reference to iu_tx(). If you,
  * however, link against libiu as well as the osmo-iuh libs (etc.), iu_tx() is
  * available. A unit test may instead simply implement a dummy iu_tx() function
- * and not link against osmo-iuh.
+ * and not link against osmo-iuh, see tests/libiudummy/.
  */
 
 /* Each main linkage must implement this function (see comment above). */
@@ -35,6 +35,13 @@
  * " */
 extern int a_tx(struct msgb *msg);
 
+/* So far this is a dummy implemented in libmsc/a_iface.c. When A-interface
+ * gets implemented, it should be in a separate lib (like libiu), this function
+ * should move there, and the following comment should remain here: "
+ * Each main linkage must implement this function (see comment above).
+ * " */
+extern int a_page(const char *imsi, uint32_t tmsi, uint16_t lac);
+
 int msc_tx_dtap(struct gsm_subscriber_connection *conn,
 		struct msgb *msg);
 
@@ -45,3 +52,7 @@
 /* TODO: specific to A interface, move this away */
 int msc_gsm0808_tx_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
 			       const uint8_t *key, int len, int include_imeisv);
+
+int msc_tx_common_id(struct gsm_subscriber_connection *conn);
+int msc_call_assignment(struct gsm_trans *trans);
+int msc_call_bridge(struct gsm_trans *trans1, struct gsm_trans *trans2);
diff --git a/include/openbsc/osmo_msc.h b/include/openbsc/osmo_msc.h
index 5a26b60..bc96f1d 100644
--- a/include/openbsc/osmo_msc.h
+++ b/include/openbsc/osmo_msc.h
@@ -56,7 +56,6 @@
 	MSC_CONN_REJECT = 1,
 };
 
-
 struct bsc_api *msc_bsc_api();
 
 int msc_create_conn_fsm(struct gsm_subscriber_connection *conn, const char *id);
@@ -64,6 +63,14 @@
 int msc_vlr_alloc(struct gsm_network *net);
 int msc_vlr_start(struct gsm_network *net);
 
+int msc_compl_l3(struct gsm_subscriber_connection *conn,
+		 struct msgb *msg, uint16_t chosen_channel);
+void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id,
+	      struct msgb *msg);
+void msc_cipher_mode_compl(struct gsm_subscriber_connection *conn,
+			   struct msgb *msg, uint8_t alg_id);
+void msc_rx_sec_mode_compl(struct gsm_subscriber_connection *conn);
+
 void msc_subscr_conn_init(void);
 bool msc_subscr_conn_is_accepted(struct gsm_subscriber_connection *conn);
 void msc_subscr_conn_communicating(struct gsm_subscriber_connection *conn);
@@ -80,4 +87,6 @@
 void _msc_subscr_conn_put(struct gsm_subscriber_connection *conn,
 			  const char *file, int line);
 
+void msc_stop_paging(struct vlr_subscr *vsub);
+
 #endif
diff --git a/include/openbsc/sgsn.h b/include/openbsc/sgsn.h
index 1ed1583..57b2978 100644
--- a/include/openbsc/sgsn.h
+++ b/include/openbsc/sgsn.h
@@ -7,6 +7,7 @@
 #include <osmocom/gprs/gprs_ns.h>
 #include <openbsc/gprs_sgsn.h>
 #include <openbsc/oap_client.h>
+#include <openbsc/common.h>
 
 #include <ares.h>
 
@@ -109,6 +110,10 @@
 		int p1;
 		int p2;
 	} dcomp_v42bis;
+
+	struct {
+		enum nsap_addr_enc rab_assign_addr_enc;
+	} iu;
 };
 
 struct sgsn_instance {
diff --git a/include/openbsc/transaction.h b/include/openbsc/transaction.h
index 07ab7a7..713d878 100644
--- a/include/openbsc/transaction.h
+++ b/include/openbsc/transaction.h
@@ -9,6 +9,14 @@
 #include <osmocom/gsm/gsm0411_smc.h>
 #include <osmocom/gsm/gsm0411_smr.h>
 
+enum bridge_state {
+	BRIDGE_STATE_NONE,
+	BRIDGE_STATE_LOOPBACK_PENDING,
+	BRIDGE_STATE_LOOPBACK_ESTABLISHED,
+	BRIDGE_STATE_BRIDGE_PENDING,
+	BRIDGE_STATE_BRIDGE_ESTABLISHED,
+};
+
 /* One transaction */
 struct gsm_trans {
 	/* Entry in list of all transactions */
@@ -57,6 +65,11 @@
 			struct gsm_sms *sms;
 		} sms;
 	};
+
+	struct {
+		struct gsm_trans *peer;
+		enum bridge_state state;
+	} bridge;
 };
 
 
@@ -74,7 +87,7 @@
 
 int trans_assign_trans_id(struct gsm_network *net, struct vlr_subscr *vsub,
 			  uint8_t protocol, uint8_t ti_flag);
-int trans_has_conn(const struct gsm_subscriber_connection *conn);
+struct gsm_trans *trans_has_conn(const struct gsm_subscriber_connection *conn);
 void trans_conn_closed(struct gsm_subscriber_connection *conn);
 
 #endif
diff --git a/include/openbsc/vlr.h b/include/openbsc/vlr.h
index 09e2ff4..619971a 100644
--- a/include/openbsc/vlr.h
+++ b/include/openbsc/vlr.h
@@ -156,7 +156,10 @@
 	struct {
 		/* pending requests */
 		bool is_paging;
+		/* list of struct subscr_request */
 		struct llist_head requests;
+		uint8_t lac;
+		enum ran_type attached_via_ran;
 	} cs;
 };
 
@@ -190,6 +193,10 @@
 	int (*set_ciph_mode)(void *msc_conn_ref, enum vlr_ciph ciph_mode,
 			     bool retrieve_imeisv);
 
+	/* UTRAN: send Common Id (when auth+ciph are complete) */
+	int (*tx_common_id)(void *msc_conn_ref);
+
+
 	/* notify MSC/SGSN that the subscriber data in VLR has been updated */
 	void (*subscr_update)(struct vlr_subscr *vsub);
 	/* notify MSC/SGSN that the given subscriber has been associated
diff --git a/include/openbsc/vty.h b/include/openbsc/vty.h
index 0cb0eec..f705601 100644
--- a/include/openbsc/vty.h
+++ b/include/openbsc/vty.h
@@ -47,6 +47,8 @@
 int bsc_vty_init(struct gsm_network *network);
 int bsc_vty_init_extra(void);
 
+void msc_vty_init(struct gsm_network *msc_network);
+
 struct gsm_network *gsmnet_from_vty(struct vty *vty);
 
 #endif