nat: Look at the assignment command and remember on which timeslot the data is

This information will be needed when we are trying to forward
MGCP connections to and from the BSC through the IPA protocol.
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index bdea434..638791a 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -103,6 +103,10 @@
 	struct sccp_source_reference real_ref;
 	struct sccp_source_reference patched_ref;
 	struct sccp_source_reference remote_ref;
+
+	/* GSM audio handling. That is 32 * multiplex + ts */
+	int msc_timeslot;
+	int bsc_timeslot;
 };
 
 /**
@@ -162,4 +166,10 @@
 struct sccp_connections *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
 struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
 
+/**
+ * MGCP/Audio handling
+ */
+int bsc_mgcp_assign(struct sccp_connections *, struct msgb *msg);
+void bsc_mgcp_clear(struct sccp_connections *);
+
 #endif
diff --git a/openbsc/src/nat/bsc_mgcp_utils.c b/openbsc/src/nat/bsc_mgcp_utils.c
new file mode 100644
index 0000000..55dad38
--- /dev/null
+++ b/openbsc/src/nat/bsc_mgcp_utils.c
@@ -0,0 +1,66 @@
+/*
+ * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2010 by On-Waves
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <openbsc/bsc_nat.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/bssap.h>
+#include <openbsc/debug.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int bsc_mgcp_assign(struct sccp_connections *con, struct msgb *msg)
+{
+	struct tlv_parsed tp;
+	u_int16_t cic;
+	u_int8_t timeslot;
+	u_int8_t multiplex;
+
+	if (!msg->l3h) {
+		LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n");
+		return -1;
+	}
+
+	if (msgb_l3len(msg) < 3) {
+		LOGP(DNAT, LOGL_ERROR, "Assignment message has not enough space for GSM0808.\n");
+		return -1;
+	}
+
+	tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
+	if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
+		LOGP(DNAT, LOGL_ERROR, "Circuit identity code not found in assignment message.\n");
+		return -1;
+	}
+
+	cic = ntohs(*(u_int16_t *)TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
+	timeslot = cic & 0x1f;
+	multiplex = (cic & ~0x1f) >> 5;
+
+	con->msc_timeslot = (32 * multiplex) + timeslot;
+	con->bsc_timeslot = con->msc_timeslot;
+	return 0;
+}
+
+void bsc_mgcp_clear(struct sccp_connections *con)
+{
+	con->msc_timeslot = -1;
+	con->bsc_timeslot = -1;
+}
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index c7c6c41..1568230 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -193,6 +193,13 @@
 		case SCCP_MSG_TYPE_CREF:
 		case SCCP_MSG_TYPE_DT1:
 			con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
+			if (parsed->gsm_type == BSS_MAP_MSG_ASSIGMENT_RQST) {
+				if (con) {
+					if (bsc_mgcp_assign(con, msg) != 0)
+						LOGP(DNAT, LOGL_ERROR, "Failed to assign...\n");
+				} else
+					LOGP(DNAT, LOGL_ERROR, "Assignment command but no BSC.\n");
+			}
 			break;
 		case SCCP_MSG_TYPE_CC:
 			con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
@@ -401,7 +408,10 @@
 			break;
 		case SCCP_MSG_TYPE_RLC:
 			con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
-			remove_sccp_src_ref(bsc, msg, parsed);
+			if (con) {
+				remove_sccp_src_ref(bsc, msg, parsed);
+				bsc_mgcp_clear(con);
+			}
 			break;
 		case SCCP_MSG_TYPE_UDT:
 			/* simply forward everything */
diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c
index 3e44193..f1bb4b5 100644
--- a/openbsc/src/nat/bsc_nat_utils.c
+++ b/openbsc/src/nat/bsc_nat_utils.c
@@ -79,6 +79,7 @@
 	LOGP(DNAT, LOGL_DEBUG, "Destroy 0x%x <-> 0x%x mapping for con %p\n",
 	     sccp_src_ref_to_int(&conn->real_ref),
 	     sccp_src_ref_to_int(&conn->patched_ref), conn->bsc);
+	bsc_mgcp_clear(conn);
 	llist_del(&conn->list_entry);
 	talloc_free(conn);
 }
diff --git a/openbsc/tests/bsc-nat/Makefile.am b/openbsc/tests/bsc-nat/Makefile.am
index d26bbeb..bcd9f18 100644
--- a/openbsc/tests/bsc-nat/Makefile.am
+++ b/openbsc/tests/bsc-nat/Makefile.am
@@ -9,5 +9,6 @@
 			$(top_srcdir)/src/nat/bsc_filter.c \
 			$(top_srcdir)/src/nat/bsc_sccp.c \
 			$(top_srcdir)/src/nat/bsc_nat_utils.c \
+			$(top_srcdir)/src/nat/bsc_mgcp_utils.c \
 			$(top_srcdir)/src/bssap.c
 bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libsccp.a $(LIBOSMOCORE_LIBS)
diff --git a/openbsc/tests/bsc-nat/bsc_data.c b/openbsc/tests/bsc-nat/bsc_data.c
index b73aff1..ca170e2 100644
--- a/openbsc/tests/bsc-nat/bsc_data.c
+++ b/openbsc/tests/bsc-nat/bsc_data.c
@@ -80,3 +80,10 @@
 0x10, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, 0x02,
 0x01, 0x50, 0x02, 0x30, 0x1a, 0x03, 0x05, 0x20,
 0x15 };
+
+/* an assignment command */
+static const u_int8_t ass_cmd[] = {
+0x00, 0x12, 0xfd, 0x06,
+0x00, 0x00, 0x49, 0x00, 0x01, 0x0b, 0x00, 0x09,
+0x01, 0x0b, 0x03, 0x01, 0x0a, 0x11, 0x01, 0x00,
+0x15 };
diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c
index 3a10960..70e98d7 100644
--- a/openbsc/tests/bsc-nat/bsc_nat_test.c
+++ b/openbsc/tests/bsc-nat/bsc_nat_test.c
@@ -335,6 +335,41 @@
 	talloc_free(parsed);
 }
 
+static void test_mgcp(void)
+{
+	struct sccp_connections con;
+	struct bsc_nat_parsed *parsed;
+	struct msgb *msg;
+
+	fprintf(stderr, "Testing MGCP.\n");
+	memset(&con, 0, sizeof(con));
+
+	msg = msgb_alloc(4096, "foo");
+	copy_to_msg(msg, ass_cmd, sizeof(ass_cmd));
+	parsed = bsc_nat_parse(msg);
+	if (bsc_mgcp_assign(&con, msg) != 0) {
+		fprintf(stderr, "Failed to handle assignment.\n");
+		abort();
+	}
+
+	if (con.msc_timeslot != 21) {
+		fprintf(stderr, "Timeslot should be 21.\n");
+		abort();
+	}
+
+	if (con.bsc_timeslot != 21) {
+		fprintf(stderr, "Assigned timeslot should have been 21.\n");
+		abort();
+	}
+	talloc_free(parsed);
+
+	bsc_mgcp_clear(&con);
+	if (con.bsc_timeslot != -1 || con.msc_timeslot != -1) {
+		fprintf(stderr, "Clearing should remove the mapping.\n");
+		abort();
+	}
+}
+
 int main(int argc, char **argv)
 {
 	struct debug_target *stderr_target;
@@ -345,9 +380,8 @@
 
 	test_filter();
 	test_contrack();
-
-	debug_set_log_level(stderr_target, 1);
 	test_paging();
+	test_mgcp();
 	return 0;
 }