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/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c
index 21ffaaa..3f3f905 100644
--- a/src/libmsc/gsm_04_08.c
+++ b/src/libmsc/gsm_04_08.c
@@ -31,6 +31,7 @@
 #include <netinet/in.h>
 #include <regex.h>
 #include <sys/types.h>
+#include <openssl/rand.h>
 
 #include "bscconfig.h"
 
@@ -69,6 +70,13 @@
 #include <osmocom/core/talloc.h>
 #include <osmocom/core/utils.h>
 #include <osmocom/gsm/tlv.h>
+#include <osmocom/crypt/auth.h>
+
+#include <openbsc/msc_ifaces.h>
+
+#ifdef BUILD_IU
+#include <openbsc/iu.h>
+#endif
 
 #include <assert.h>
 
@@ -105,7 +113,7 @@
 		gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
 	}
 
-	return gsm0808_submit_dtap(conn, msg, 0, 0);
+	return msc_tx_dtap(conn, msg);
 }
 
 int gsm48_cc_tx_notify_ss(struct gsm_trans *trans, const char *message)
@@ -141,7 +149,7 @@
 }
 
 /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
-int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause)
+static int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause)
 {
 	struct msgb *msg;
 
@@ -184,12 +192,17 @@
 		len = gsm48_generate_mid_from_imsi(mi, conn->vsub->imsi);
 		mid = msgb_put(msg, len);
 		memcpy(mid, mi, len);
+		DEBUGP(DMM, "-> %s LOCATION UPDATE ACCEPT\n",
+		       vlr_subscr_name(conn->vsub));
 	} else {
 		/* Include the TMSI, which means that the MS will send a
 		 * TMSI REALLOCATION COMPLETE, and we should wait for
 		 * that until T3250 expiration */
 		mid = msgb_put(msg, GSM48_MID_TMSI_LEN);
 		gsm48_generate_mid_from_tmsi(mid, send_tmsi);
+		DEBUGP(DMM, "-> %s LOCATION UPDATE ACCEPT (TMSI = 0x%08x)\n",
+		       vlr_subscr_name(conn->vsub),
+		       send_tmsi);
 	}
 	/* TODO: Follow-on proceed */
 	/* TODO: CTS permission */
@@ -197,7 +210,6 @@
 	/* TODO: Emergency Number List */
 	/* TODO: Per-MS T3312 */
 
-	DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
 
 	return gsm48_conn_sendmsg(msg, conn, NULL);
 }
@@ -257,11 +269,11 @@
 	uint8_t mi_type;
 	char mi_string[GSM48_MI_SIZE];
 	enum vlr_lu_type vlr_lu_type = VLR_LU_TYPE_REGULAR;
-
 	uint32_t tmsi;
 	char *imsi;
 	struct osmo_location_area_id old_lai, new_lai;
 	struct osmo_fsm_inst *lu_fsm;
+	bool is_utran;
 	int rc;
 
  	lu = (struct gsm48_loc_upd_req *) gh->data;
@@ -327,16 +339,18 @@
 	new_lai.lac = conn->lac;
 	DEBUGP(DMM, "LU/new-LAC: %u/%u\n", old_lai.lac, new_lai.lac);
 
+	is_utran = (conn->via_ran == RAN_UTRAN_IU);
 	lu_fsm = vlr_loc_update(conn->conn_fsm,
 				SUBSCR_CONN_E_ACCEPTED,
 				SUBSCR_CONN_E_CN_CLOSE,
 				(void*)&conn_from_lu,
 				net->vlr, conn, vlr_lu_type, tmsi, imsi,
 				&old_lai, &new_lai,
-				conn->network->authentication_required,
-				conn->network->a5_encryption,
+				is_utran || conn->network->authentication_required,
+				is_utran? VLR_CIPH_A5_3
+					: conn->network->a5_encryption,
 				classmark_is_r99(&conn->classmark),
-				conn->via_ran == RAN_UTRAN_IU,
+				is_utran,
 				net->vlr->cfg.assign_tmsi);
 	if (!lu_fsm) {
 		DEBUGP(DRR, "%s: Can't start LU FSM\n", mi_string);
@@ -629,6 +643,7 @@
 	uint8_t mi_len = *(classmark2 + classmark2_len);
 	uint8_t *mi = (classmark2 + classmark2_len + 1);
 	struct osmo_location_area_id lai;
+	bool is_utran;
 	int rc;
 
 	lai.plmn.mcc = conn->network->country_code;
@@ -685,16 +700,18 @@
 		return rc;
 	}
 
+	is_utran = (conn->via_ran == RAN_UTRAN_IU);
 	vlr_proc_acc_req(conn->conn_fsm,
 			 SUBSCR_CONN_E_ACCEPTED,
 			 SUBSCR_CONN_E_CN_CLOSE,
 			 (void*)&conn_from_cm_service_req,
 			 net->vlr, conn,
 			 VLR_PR_ARQ_T_CM_SERV_REQ, mi-1, &lai,
-			 conn->network->authentication_required,
-			 conn->network->a5_encryption,
+			 is_utran || conn->network->authentication_required,
+			 is_utran? VLR_CIPH_A5_3
+				 : conn->network->a5_encryption,
 			 classmark_is_r99(&conn->classmark),
-			 conn->via_ran == RAN_UTRAN_IU);
+			 is_utran);
 
 	return 0;
 }
@@ -1038,6 +1055,7 @@
 	char mi_string[GSM48_MI_SIZE];
 	int rc = 0;
 	struct osmo_location_area_id lai;
+	bool is_utran;
 
 	lai.plmn.mcc = conn->network->country_code;
 	lai.plmn.mnc = conn->network->network_code;
@@ -1063,18 +1081,20 @@
 	memcpy(conn->classmark.classmark2, classmark2_lv+1, *classmark2_lv);
 	conn->classmark.classmark2_len = *classmark2_lv;
 
+	is_utran = (conn->via_ran == RAN_UTRAN_IU);
 	vlr_proc_acc_req(conn->conn_fsm,
 			 SUBSCR_CONN_E_ACCEPTED,
 			 SUBSCR_CONN_E_CN_CLOSE,
 			 (void*)&conn_from_paging_resp,
 			 net->vlr, conn,
 			 VLR_PR_ARQ_T_PAGING_RESP, mi_lv, &lai,
-			 conn->network->authentication_required,
-			 conn->network->a5_encryption,
+			 is_utran || conn->network->authentication_required,
+			 is_utran? VLR_CIPH_A5_3
+				 : conn->network->a5_encryption,
 			 classmark_is_r99(&conn->classmark),
-			 conn->via_ran == RAN_UTRAN_IU);
+			 is_utran);
 
-	return rc;
+	return 0;
 }
 
 static int gsm48_rx_rr_app_info(struct gsm_subscriber_connection *conn, struct msgb *msg)
@@ -1365,8 +1385,7 @@
 	/* Which subscriber do we want to track trans1 or trans2? */
 	log_set_context(LOG_CTX_VLR_SUBSCR, trans1->vsub);
 
-	/* future: msc_call_bridge(trans1, trans2); */
-	return -1;
+	return msc_call_bridge(trans1, trans2);
 }
 
 static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
@@ -1694,15 +1713,18 @@
 
 	new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
 
+	msc_call_assignment(trans);
+
 	return mncc_recvmsg(trans->net, trans, MNCC_CALL_CONF_IND,
 			    &call_conf);
 }
 
-static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg)
+static int gsm48_cc_tx_call_proc_and_assign(struct gsm_trans *trans, void *arg)
 {
 	struct gsm_mncc *proceeding = arg;
 	struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 CC PROC");
 	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	int rc;
 
 	gh->msg_type = GSM48_MT_CC_CALL_PROC;
 
@@ -1718,7 +1740,11 @@
 	if (proceeding->fields & MNCC_F_PROGRESS)
 		gsm48_encode_progress(msg, 0, &proceeding->progress);
 
-	return gsm48_conn_sendmsg(msg, trans->conn, trans);
+	rc = gsm48_conn_sendmsg(msg, trans->conn, trans);
+	if (rc)
+		return rc;
+
+	return msc_call_assignment(trans);
 }
 
 static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
@@ -2555,7 +2581,7 @@
 } downstatelist[] = {
 	/* mobile originating call establishment */
 	{SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.2 */
-	 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc},
+	 MNCC_CALL_PROC_REQ, gsm48_cc_tx_call_proc_and_assign},
 	{SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.2 | 5.2.1.5 */
 	 MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
 	{SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC) | SBIT(GSM_CSTATE_CALL_DELIVERED), /* 5.2.1.2 | 5.2.1.6 | 5.2.1.6 */
@@ -2732,15 +2758,15 @@
 				trans_free(trans);
 				return 0;
 			}
-			/* store setup informations until paging was successfull */
+			/* store setup information until paging succeeds */
 			memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
 
 			/* Request a channel */
 			trans->paging_request = subscr_request_conn(
 							vsub,
-							RSL_CHANNEED_TCH_F,
 							setup_trig_pag_evt,
-							trans);
+							trans,
+							"MNCC: establish call");
 			if (!trans->paging_request) {
 				LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n");
 				vlr_subscr_put(vsub);
@@ -3007,6 +3033,16 @@
 		return -EACCES;
 	}
 
+	if (conn->vsub && conn->vsub->cs.attached_via_ran != conn->via_ran) {
+		LOGP(DMM, LOGL_ERROR,
+		     "%s: Illegal situation: RAN type mismatch:"
+		     " attached via %s, received message via %s\n",
+		     vlr_subscr_name(conn->vsub),
+		     ran_type_name(conn->vsub->cs.attached_via_ran),
+		     ran_type_name(conn->via_ran));
+		return -EACCES;
+	}
+
 #if 0
 	if (silent_call_reroute(conn, msg))
 		return silent_call_rx(conn, msg);
@@ -3090,7 +3126,13 @@
 static int msc_vlr_tx_cm_serv_acc(void *msc_conn_ref)
 {
 	struct gsm_subscriber_connection *conn = msc_conn_ref;
-	return gsm48_tx_mm_serv_ack(conn);
+	return msc_gsm48_tx_mm_serv_ack(conn);
+}
+
+static int msc_vlr_tx_common_id(void *msc_conn_ref)
+{
+	struct gsm_subscriber_connection *conn = msc_conn_ref;
+	return msc_tx_common_id(conn);
 }
 
 /* VLR asks us to transmit a CM Service Reject */
@@ -3124,7 +3166,7 @@
 		break;
 	};
 
-	return gsm48_tx_mm_serv_rej(conn, cause);
+	return msc_gsm48_tx_mm_serv_rej(conn, cause);
 }
 
 /* VLR asks us to start using ciphering */
@@ -3152,9 +3194,47 @@
 		return -EINVAL;
 	}
 
-	/* TODO: MSCSPLIT: don't directly push BSC buttons */
-	return gsm0808_cipher_mode(conn, ciph, tuple->vec.kc, 8,
-				   retrieve_imeisv);
+	switch (conn->via_ran) {
+	case RAN_GERAN_A:
+		DEBUGP(DMM, "-> CIPHER MODE COMMAND %s\n",
+		       vlr_subscr_name(conn->vsub));
+		return msc_gsm0808_tx_cipher_mode(conn, ciph, tuple->vec.kc, 8,
+						  retrieve_imeisv);
+	case RAN_UTRAN_IU:
+#ifdef BUILD_IU
+		DEBUGP(DMM, "-> SECURITY MODE CONTROL %s\n",
+		       vlr_subscr_name(conn->vsub));
+		return iu_tx_sec_mode_cmd(conn->iu.ue_ctx, tuple, 0, 1);
+#else
+		LOGP(DMM, LOGL_ERROR, "Cannot send Security Mode Control over RAN_UTRAN_IU,"
+		     " built without Iu support\n");
+		return -ENOTSUP;
+#endif
+
+	default:
+		break;
+	}
+	LOGP(DMM, LOGL_ERROR,
+	     "%s: cannot start ciphering, unknown RAN type %d\n",
+	     vlr_subscr_name(conn->vsub), conn->via_ran);
+	return -ENOTSUP;
+}
+
+void msc_rx_sec_mode_compl(struct gsm_subscriber_connection *conn)
+{
+	struct vlr_ciph_result vlr_res = {};
+
+	if (!conn || !conn->vsub) {
+		LOGP(DMM, LOGL_ERROR,
+		     "Rx Security Mode Complete for invalid conn\n");
+		return;
+	}
+
+	DEBUGP(DMM, "<- SECURITY MODE COMPLETE %s\n",
+	       vlr_subscr_name(conn->vsub));
+
+	vlr_res.cause = VLR_CIPH_COMPL;
+	vlr_subscr_rx_ciph_res(conn->vsub, &vlr_res);
 }
 
 /* VLR informs us that the subscriber data has somehow been modified */
@@ -3170,6 +3250,7 @@
 	struct gsm_subscriber_connection *conn = msc_conn_ref;
 	OSMO_ASSERT(!conn->vsub);
 	conn->vsub = vlr_subscr_get(vsub);
+	conn->vsub->cs.attached_via_ran = conn->via_ran;
 }
 
 /* operations that we need to implement for libvlr */
@@ -3182,6 +3263,7 @@
 	.tx_cm_serv_acc = msc_vlr_tx_cm_serv_acc,
 	.tx_cm_serv_rej = msc_vlr_tx_cm_serv_rej,
 	.set_ciph_mode = msc_vlr_set_ciph_mode,
+	.tx_common_id = msc_vlr_tx_common_id,
 	.subscr_update = msc_vlr_subscr_update,
 	.subscr_assoc = msc_vlr_subscr_assoc,
 };
@@ -3203,19 +3285,3 @@
 	return vlr_start("MSC", net->vlr, net->gsup_server_addr_str,
 			 net->gsup_server_port);
 }
-
-/* This is a temporary shim merely to ensure that the unit tests still work. It
- * shall be removed as soon as Iu and A interface paging is implemented. */
-int msc_fake_paging_request(struct vlr_subscr *vsub)
-{
-	LOGP(DMM, LOGL_ERROR, "Paging currently not implemented in the MSC.\n");
-	OSMO_ASSERT(false);
-}
-
-/* This is a temporary shim merely to ensure that the unit tests still work. It
- * shall be removed as soon as Iu and A interface paging is implemented. */
-void msc_fake_paging_request_stop(struct vlr_subscr *vsub)
-{
-	LOGP(DMM, LOGL_ERROR, "Paging currently not implemented in the MSC.\n");
-	OSMO_ASSERT(false);
-}