nat: Attempt to assign the BSC Timeslot based on a free list

Do attempt to not reassign an endpoint immediately but go
to the next free one.
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index 5f746f2..11c24dc 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -75,6 +75,10 @@
 	struct timer_list ping_timeout;
 	struct timer_list pong_timeout;
 
+	/* mgcp related code */
+	int endpoint_status[33];
+	int last_endpoint;
+
 	/* a back pointer */
 	struct bsc_nat *nat;
 };
@@ -253,7 +257,7 @@
  * MGCP/Audio handling
  */
 int bsc_write_mgcp(struct bsc_connection *bsc, const uint8_t *data, unsigned int length);
-int bsc_mgcp_assign(struct sccp_connections *, struct msgb *msg);
+int bsc_mgcp_assign_patch(struct sccp_connections *, struct msgb *msg);
 void bsc_mgcp_init(struct sccp_connections *);
 void bsc_mgcp_dlcx(struct sccp_connections *);
 void bsc_mgcp_free_endpoints(struct bsc_nat *nat);
diff --git a/openbsc/src/nat/bsc_mgcp_utils.c b/openbsc/src/nat/bsc_mgcp_utils.c
index 8ed9301..475e04c 100644
--- a/openbsc/src/nat/bsc_mgcp_utils.c
+++ b/openbsc/src/nat/bsc_mgcp_utils.c
@@ -38,7 +38,36 @@
 #include <errno.h>
 #include <unistd.h>
 
-int bsc_mgcp_assign(struct sccp_connections *con, struct msgb *msg)
+static int bsc_assign_endpoint(struct bsc_connection *bsc, struct sccp_connections *con)
+{
+	const int number_endpoints = ARRAY_SIZE(bsc->endpoint_status);
+	int i;
+
+	for (i = 1; i < number_endpoints; ++i) {
+		int endpoint = (bsc->last_endpoint + i) % number_endpoints;
+		if (endpoint == 0)
+			endpoint = 1;
+
+		if (bsc->endpoint_status[endpoint] == 0) {
+			bsc->endpoint_status[endpoint] = 1;
+			con->bsc_endp = endpoint;
+			bsc->last_endpoint = endpoint;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static uint16_t create_cic(int endpoint)
+{
+	int timeslot, multiplex;
+
+	mgcp_endpoint_to_timeslot(endpoint, &multiplex, &timeslot);
+	return (multiplex << 5) | (timeslot & 0x1f);
+}
+
+int bsc_mgcp_assign_patch(struct sccp_connections *con, struct msgb *msg)
 {
 	struct sccp_connections *mcon;
 	struct tlv_parsed tp;
@@ -83,7 +112,17 @@
 	}
 
 	con->msc_endp = endp;
-	con->bsc_endp = endp;
+	if (bsc_assign_endpoint(con->bsc, con) != 0)
+		return -1;
+
+	/*
+	 * now patch the message for the new CIC...
+	 * still assumed to be one multiplex only
+	 */
+	cic = htons(create_cic(con->bsc_endp));
+	memcpy((uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE),
+		&cic, sizeof(cic));
+
 	return 0;
 }
 
@@ -94,6 +133,15 @@
 		nat->bsc_endpoints[i].transaction_id = NULL;
 	}
 
+	/* Free the endpoint status, so we can allocate it again */
+	if (nat->bsc_endpoints[i].bsc) {
+		struct bsc_connection *bsc = nat->bsc_endpoints[i].bsc;
+		if (bsc->endpoint_status[i] != 1)
+			LOGP(DNAT, LOGL_ERROR, "Endpoint %d should be allocated\n", i);
+
+		bsc->endpoint_status[i] = 0;
+	}
+
 	nat->bsc_endpoints[i].transaction_state = 0;
 	nat->bsc_endpoints[i].bsc = NULL;
 }
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index 997a57f..a380a61 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -422,7 +422,7 @@
 					struct rate_ctr_group *ctrg;
 					ctrg = con->bsc->cfg->stats.ctrg;
 					rate_ctr_inc(&ctrg->ctr[BCFG_CTR_SCCP_CALLS]);
-					if (bsc_mgcp_assign(con, msg) != 0)
+					if (bsc_mgcp_assign_patch(con, msg) != 0)
 						LOGP(DNAT, LOGL_ERROR, "Failed to assign...\n");
 				} else
 					LOGP(DNAT, LOGL_ERROR, "Assignment command but no BSC.\n");
diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c
index b7a89c5..acc5de3 100644
--- a/openbsc/tests/bsc-nat/bsc_nat_test.c
+++ b/openbsc/tests/bsc-nat/bsc_nat_test.c
@@ -444,7 +444,7 @@
 	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) {
+	if (bsc_mgcp_assign_patch(&con, msg) != 0) {
 		fprintf(stderr, "Failed to handle assignment.\n");
 		abort();
 	}
@@ -454,14 +454,19 @@
 		abort();
 	}
 
-	if (con.bsc_endp != 21) {
-		fprintf(stderr, "Assigned timeslot should have been 21.\n");
+	if (con.bsc_endp != 1) {
+		fprintf(stderr, "Assigned timeslot should have been 1.\n");
 		abort();
 	}
+	if (con.bsc->endpoint_status[1] != 1) {
+		fprintf(stderr, "The status on the BSC is wrong.\n");
+		abort();
+	}
+
 	talloc_free(parsed);
 
 	bsc_mgcp_dlcx(&con);
-	if (con.bsc_endp != -1 || con.msc_endp != -1) {
+	if (con.bsc_endp != -1 || con.msc_endp != -1 || con.bsc->endpoint_status[1] != 0) {
 		fprintf(stderr, "Clearing should remove the mapping.\n");
 		abort();
 	}