Move processing of CLASSMARK CHANGE behind bsc_api

This prevents osmo-bsc from sending RR messages to the MSC and rather
process them inside the BSC and turn them into BSSAP CM UPDATE.
diff --git a/openbsc/include/openbsc/bsc_api.h b/openbsc/include/openbsc/bsc_api.h
index ae700ee..910ce9e 100644
--- a/openbsc/include/openbsc/bsc_api.h
+++ b/openbsc/include/openbsc/bsc_api.h
@@ -30,6 +30,10 @@
 	/*! \brief BSC->MSC: RR conn has been cleared */
 	int (*clear_request)(struct gsm_subscriber_connection *conn,
 			      uint32_t cause);
+	/*! \brief BSC->MSC: Classmark Update */
+	void (*classmark_chg)(struct gsm_subscriber_connection *conn,
+			      const uint8_t *cm2, uint8_t cm2_len,
+			      const uint8_t *cm3, uint8_t cm3_len);
 };
 
 int bsc_api_init(struct gsm_network *network, struct bsc_api *api);
diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c
index ad4391d..bb13747 100644
--- a/openbsc/src/libbsc/bsc_api.c
+++ b/openbsc/src/libbsc/bsc_api.c
@@ -418,6 +418,44 @@
 			 rr_failure);
 }
 
+static void handle_classmark_chg(struct gsm_subscriber_connection *conn,
+				 struct msgb *msg)
+{
+	struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
+	struct gsm48_hdr *gh = msgb_l3(msg);
+	unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
+	uint8_t cm2_len, cm3_len = 0;
+	uint8_t *cm2, *cm3 = NULL;
+
+	DEBUGP(DRR, "CLASSMARK CHANGE ");
+
+	/* classmark 2 */
+	cm2_len = gh->data[0];
+	cm2 = &gh->data[1];
+	DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
+
+	if (payload_len > cm2_len + 1) {
+		/* we must have a classmark3 */
+		if (gh->data[cm2_len+1] != 0x20) {
+			DEBUGPC(DRR, "ERR CM3 TAG\n");
+			return -EINVAL;
+		}
+		if (cm2_len > 3) {
+			DEBUGPC(DRR, "CM2 too long!\n");
+			return -EINVAL;
+		}
+
+		cm3_len = gh->data[cm2_len+2];
+		cm3 = &gh->data[cm2_len+3];
+		if (cm3_len > 14) {
+			DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
+			return -EINVAL;
+		}
+		DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
+	}
+	api->classmark_chg(conn, cm2, cm2_len, cm3, cm3_len);
+}
+
 static void dispatch_dtap(struct gsm_subscriber_connection *conn,
 			  uint8_t link_id, struct msgb *msg)
 {
@@ -462,6 +500,10 @@
 			}
 			return;
 			break;
+		case GSM48_MT_RR_CLSM_CHG:
+			handle_classmark_chg(conn, msg);
+			return;
+			break;
 		}
 		break;
 	case GSM48_PDISC_MM:
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 7c0d628..a2a49aa 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1101,53 +1101,6 @@
 	return rc;
 }
 
-static int gsm48_rx_rr_classmark(struct gsm_subscriber_connection *conn, struct msgb *msg)
-{
-	struct gsm48_hdr *gh = msgb_l3(msg);
-	struct gsm_subscriber *subscr = conn->subscr;
-	unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
-	uint8_t cm2_len, cm3_len = 0;
-	uint8_t *cm2, *cm3 = NULL;
-
-	DEBUGP(DRR, "CLASSMARK CHANGE ");
-
-	/* classmark 2 */
-	cm2_len = gh->data[0];
-	cm2 = &gh->data[1];
-	DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
-
-	if (payload_len > cm2_len + 1) {
-		/* we must have a classmark3 */
-		if (gh->data[cm2_len+1] != 0x20) {
-			DEBUGPC(DRR, "ERR CM3 TAG\n");
-			return -EINVAL;
-		}
-		if (cm2_len > 3) {
-			DEBUGPC(DRR, "CM2 too long!\n");
-			return -EINVAL;
-		}
-		
-		cm3_len = gh->data[cm2_len+2];
-		cm3 = &gh->data[cm2_len+3];
-		if (cm3_len > 14) {
-			DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
-			return -EINVAL;
-		}
-		DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
-	}
-	if (subscr) {
-		subscr->equipment.classmark2_len = cm2_len;
-		memcpy(subscr->equipment.classmark2, cm2, cm2_len);
-		if (cm3) {
-			subscr->equipment.classmark3_len = cm3_len;
-			memcpy(subscr->equipment.classmark3, cm3, cm3_len);
-		}
-		db_sync_equipment(&subscr->equipment);
-	}
-
-	return 0;
-}
-
 static int gsm48_rx_rr_status(struct msgb *msg)
 {
 	struct gsm48_hdr *gh = msgb_l3(msg);
@@ -1258,9 +1211,6 @@
 	int rc = 0;
 
 	switch (gh->msg_type) {
-	case GSM48_MT_RR_CLSM_CHG:
-		rc = gsm48_rx_rr_classmark(conn, msg);
-		break;
 	case GSM48_MT_RR_GPRS_SUSP_REQ:
 		DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
 		break;
diff --git a/openbsc/src/libmsc/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c
index 154386b..121de67 100644
--- a/openbsc/src/libmsc/osmo_msc.c
+++ b/openbsc/src/libmsc/osmo_msc.c
@@ -24,6 +24,7 @@
 #include <openbsc/bsc_api.h>
 #include <openbsc/debug.h>
 #include <openbsc/transaction.h>
+#include <openbsc/db.h>
 
 #include <openbsc/gsm_04_11.h>
 
@@ -83,6 +84,25 @@
 	     "Assignment fail should not have been reached.\n");
 }
 
+static void msc_classmark_chg(struct gsm_subscriber_connection *conn,
+			      const uint8_t *cm2, uint8_t cm2_len,
+			      const uint8_t *cm3, uint8_t cm3_len)
+{
+	struct gsm_subscriber *subscr = conn->subscr;
+
+	if (subscr) {
+		subscr->equipment.classmark2_len = cm2_len;
+		memcpy(subscr->equipment.classmark2, cm2, cm2_len);
+		if (cm3) {
+			subscr->equipment.classmark3_len = cm3_len;
+			memcpy(subscr->equipment.classmark3, cm3, cm3_len);
+		}
+		db_sync_equipment(&subscr->equipment);
+	}
+}
+
+
+
 static struct bsc_api msc_handler = {
 	.sapi_n_reject = msc_sapi_n_reject,
 	.compl_l3 = msc_compl_l3,
@@ -90,6 +110,7 @@
 	.clear_request = msc_clear_request,
 	.assign_compl = msc_assign_compl,
 	.assign_fail = msc_assign_fail,
+	.classmark_chg = msc_classmark_chg,
 };
 
 struct bsc_api *msc_bsc_api() {
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_api.c b/openbsc/src/osmo-bsc/osmo_bsc_api.c
index 2869f47..72e7b9b 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_api.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_api.c
@@ -183,6 +183,19 @@
 	return 1;
 }
 
+static void bsc_cm_update(struct gsm_subscriber_connection *conn,
+			  const uint8_t *cm2, uint8_t cm2_len,
+			  const uint8_t *cm3, uint8_t cm3_len)
+{
+	struct osmo_bsc_sccp_con *sccp;
+	struct msgb *resp;
+	return_when_not_connected_val(conn, 1);
+
+	resp = gsm0808_create_classmark_update(cm2, cm2_len, cm3, cm3_len);
+
+	queue_msg_or_return(resp);
+}
+
 static struct bsc_api bsc_handler = {
 	.sapi_n_reject = bsc_sapi_n_reject,
 	.cipher_mode_compl = bsc_cipher_mode_compl,
@@ -191,6 +204,7 @@
 	.assign_compl = bsc_assign_compl,
 	.assign_fail = bsc_assign_fail,
 	.clear_request = bsc_clear_request,
+	.classmark_chg = bsc_cm_update,
 };
 
 struct bsc_api *osmo_bsc_api()