bsc_api: Allocate the subscriber_connection dynamically

This is a big change to the way we use the subscriber
connection. From now on it is is dynamically allocated
and we will slowly move from a 1:1 lchan to conn to
having more than one lchan per connection.

This is the first commit, the subscr_con* methods will
move to gsm_data once the use_count is removed from the
connection, the freeing of the connection will also change.
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 2e41e8b..b1091cd 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -255,7 +255,6 @@
 	int silent_call;
 
 	/* back pointers */
-	int allocated;
 	struct gsm_lchan *lchan;
 	struct gsm_bts *bts;
 };
@@ -316,7 +315,7 @@
 		struct rtp_socket *rtp_socket;
 	} abis_ip;
 
-	struct gsm_subscriber_connection conn;
+	struct gsm_subscriber_connection *conn;
 };
 
 struct gsm_e1_subslot {
@@ -822,4 +821,7 @@
 int gsm_bts_has_feature(struct gsm_bts *bts, enum gsm_bts_features feat);
 int gsm_bts_model_register(struct gsm_bts_model *model);
 
+struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan);
+void subscr_con_free(struct gsm_subscriber_connection *conn);
+
 #endif
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index 6c6230f..f5ebb77 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -123,7 +123,8 @@
 
 	lchan = &ts->lchan[lch_idx];
 	log_set_context(BSC_CTX_LCHAN, lchan);
-	log_set_context(BSC_CTX_SUBSCR, lchan->conn.subscr);
+	if (lchan->conn)
+		log_set_context(BSC_CTX_SUBSCR, lchan->conn->subscr);
 
 	return lchan;
 }
diff --git a/openbsc/src/bsc_api.c b/openbsc/src/bsc_api.c
index cac08be..92fe661 100644
--- a/openbsc/src/bsc_api.c
+++ b/openbsc/src/bsc_api.c
@@ -89,19 +89,23 @@
 int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
 {
 	int rc;
-	struct gsm_subscriber_connection *conn;
 	struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
+	struct gsm_lchan *lchan;
 
-	conn = &msg->lchan->conn;
-	if (conn->allocated) {
-		api->dtap(conn, msg);
+	lchan = msg->lchan;
+	if (lchan->conn) {
+		api->dtap(lchan->conn, msg);
 	} else {
-		/* accept the connection or close the lchan */
-		rc = api->compl_l3(conn, msg, 0);
-		if (rc == BSC_API_CONN_POL_ACCEPT)
-			conn->allocated = 1;
-		else
-			lchan_auto_release(msg->lchan);
+		rc = BSC_API_CONN_POL_REJECT;
+		lchan->conn = subscr_con_allocate(msg->lchan);
+
+		if (lchan->conn)
+			rc = api->compl_l3(lchan->conn, msg, 0);
+
+		if (rc != BSC_API_CONN_POL_ACCEPT) {
+			subscr_con_free(lchan->conn);
+			lchan_auto_release(lchan);
+		}
 	}
 
 	return 0;
@@ -111,6 +115,9 @@
 {
 	struct bsc_api *api;
 
+	if (!conn)
+		return;
+
 	api = conn->bts->network->bsc_api;
 	if (!api || !api->sapi_n_reject)
 		return;
@@ -129,7 +136,7 @@
 	case BSC_RLLR_IND_REL_IND:
 	case BSC_RLLR_IND_ERR_IND:
 	case BSC_RLLR_IND_TIMEOUT:
-		send_sapi_reject(&lchan->conn, OBSC_LINKID_CB(msg));
+		send_sapi_reject(lchan->conn, OBSC_LINKID_CB(msg));
 		msgb_free(msg);
 		break;
 	}
@@ -145,7 +152,7 @@
 		return 0;
 
 	lchan = (struct gsm_lchan *)signal_data;
-	if (!lchan)
+	if (!lchan || !lchan->conn)
 		return 0;
 
 
@@ -153,7 +160,7 @@
 	if (!bsc || !bsc->clear_request)
 		return 0;
 
-	bsc->clear_request(&lchan->conn, 0);
+	bsc->clear_request(lchan->conn, 0);
 	return 0;
 }
 
diff --git a/openbsc/src/bsc_vty.c b/openbsc/src/bsc_vty.c
index 68a0597..3215745 100644
--- a/openbsc/src/bsc_vty.c
+++ b/openbsc/src/bsc_vty.c
@@ -700,16 +700,17 @@
 		lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
 		lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type),
 		VTY_NEWLINE);
-	vty_out(vty, "  Use Count: %u, State: %s%s", lchan->conn.use_count,
+	vty_out(vty, "  Use Count: %u, State: %s%s",
+		lchan->conn ? lchan->conn->use_count : -23,
 		gsm_lchans_name(lchan->state), VTY_NEWLINE);
 	vty_out(vty, "  BS Power: %u dBm, MS Power: %u dBm%s",
 		lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red
 		- lchan->bs_power*2,
 		ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
 		VTY_NEWLINE);
-	if (lchan->conn.subscr) {
+	if (lchan->conn && lchan->conn->subscr) {
 		vty_out(vty, "  Subscriber:%s", VTY_NEWLINE);
-		subscr_dump_vty(vty, lchan->conn.subscr);
+		subscr_dump_vty(vty, lchan->conn->subscr);
 	} else
 		vty_out(vty, "  No Subscriber%s", VTY_NEWLINE);
 	if (is_ipaccess_bts(lchan->ts->trx->bts)) {
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index 8115d87..f5c4ec6 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -271,15 +271,10 @@
 		memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf));
 
 		/* clear per MSC/BSC data */
-		memset(&lchan->conn, 0, sizeof(lchan->conn));
-
-		/* Configure the time and start it so it will be closed */
-		lchan->conn.lchan = lchan;
-		lchan->conn.bts = lchan->ts->trx->bts;
-		lchan->conn.release_timer.cb = auto_release_channel;
-		lchan->conn.release_timer.data = lchan;
-		bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT);
-
+		if (lchan->conn) {
+			LOGP(DRLL, LOGL_ERROR, "lchan->conn should be NULL.\n");
+			subscr_con_free(lchan->conn);
+		}
 	} else {
 		struct challoc_signal_data sig;
 		sig.bts = bts;
@@ -298,19 +293,25 @@
 
 	sig.type = lchan->type;
 	lchan->type = GSM_LCHAN_NONE;
-	if (lchan->conn.subscr) {
-		subscr_put(lchan->conn.subscr);
-		lchan->conn.subscr = NULL;
+
+
+	if (lchan->conn) {
+		if (lchan->conn->subscr) {
+			subscr_put(lchan->conn->subscr);
+			lchan->conn->subscr = NULL;
+		}
+
+		/* We might kill an active channel... */
+		if (lchan->conn->use_count != 0) {
+			dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan);
+			lchan->conn->use_count = 0;
+		}
+		/* stop the timer */
+		bsc_del_timer(&lchan->conn->release_timer);
 	}
 
-	/* We might kill an active channel... */
-	if (lchan->conn.use_count != 0) {
-		dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan);
-		lchan->conn.use_count = 0;
-	}
 
 	/* stop the timer */
-	bsc_del_timer(&lchan->conn.release_timer);
 	bsc_del_timer(&lchan->T3101);
 
 	/* clear cached measuement reports */
@@ -328,12 +329,15 @@
 		lchan->rqd_ta = 0;
 	}
 
-	lchan->conn.silent_call = 0;
-
 	sig.lchan = lchan;
 	sig.bts = lchan->ts->trx->bts;
 	dispatch_signal(SS_CHALLOC, S_CHALLOC_FREED, &sig);
 
+	if (lchan->conn) {
+		subscr_con_free(lchan->conn);
+		lchan->conn = NULL;
+	}
+
 	/* FIXME: ts_free() the timeslot, if we're the last logical
 	 * channel using it */
 }
@@ -362,19 +366,22 @@
 /* Consider releasing the channel now */
 int lchan_auto_release(struct gsm_lchan *lchan)
 {
-	if (lchan->conn.use_count > 0) {
+	if (!lchan->conn)
+		return 0;
+
+	if (lchan->conn->use_count > 0) {
 		return 0;
 	}
 
 	/* Assume we have GSM04.08 running and send a release */
-	if (lchan->conn.subscr) {
+	if (lchan->conn->subscr) {
 		gsm48_send_rr_release(lchan);
 	}
 
 	/* spoofed? message */
-	if (lchan->conn.use_count < 0)
+	if (lchan->conn->use_count < 0)
 		LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n",
-			lchan->conn.use_count);
+			lchan->conn->use_count);
 
 	DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
 	rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
@@ -388,7 +395,7 @@
 	struct gsm_lchan *lchan = _lchan;
 
 	if (!lchan_auto_release(lchan))
-		bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT);
+		bsc_schedule_timer(&lchan->conn->release_timer, LCHAN_RELEASE_TIMEOUT);
 }
 
 static struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
@@ -400,7 +407,7 @@
 			for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
 				struct gsm_lchan *lchan =
 					&trx->ts[ts_no].lchan[lchan_no];
-				if (subscr == lchan->conn.subscr)
+				if (lchan->conn && subscr == lchan->conn->subscr)
 					return lchan;
 			}
 		}
@@ -418,7 +425,7 @@
 	llist_for_each_entry(bts, &net->bts_list, list) {
 		lchan = lchan_find(bts, subscr);
 		if (lchan)
-			return &lchan->conn;
+			return lchan->conn;
 	}
 
 	return NULL;
@@ -471,3 +478,38 @@
 	llist_for_each_entry(bts, &net->bts_list, list)
 		bts_chan_load(pl, bts);
 }
+
+struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
+{
+	struct gsm_subscriber_connection *conn;
+
+	conn = talloc_zero(lchan->ts->trx->bts, struct gsm_subscriber_connection);
+	if (!conn)
+		return NULL;
+
+	/* Configure the time and start it so it will be closed */
+	conn->lchan = lchan;
+	conn->bts = lchan->ts->trx->bts;
+	conn->release_timer.cb = auto_release_channel;
+	conn->release_timer.data = lchan;
+	bsc_schedule_timer(&conn->release_timer, LCHAN_RELEASE_TIMEOUT);
+
+	lchan->conn = conn;
+	return conn;
+}
+
+/* TODO: move subscriber put here... */
+void subscr_con_free(struct gsm_subscriber_connection *conn)
+{
+	struct gsm_lchan *lchan;
+
+
+	if (!conn)
+		return;
+
+	lchan = conn->lchan;
+	talloc_free(conn);
+
+	if (lchan)
+		lchan->conn = NULL;
+}
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c
index b2ffe46..b75dc98 100644
--- a/openbsc/src/handover_logic.c
+++ b/openbsc/src/handover_logic.c
@@ -122,7 +122,7 @@
 	new_lchan->bs_power = old_lchan->bs_power;
 	new_lchan->rsl_cmode = old_lchan->rsl_cmode;
 	new_lchan->tch_mode = old_lchan->tch_mode;
-	new_lchan->conn.subscr = subscr_get(old_lchan->conn.subscr);
+	new_lchan->conn->subscr = subscr_get(old_lchan->conn->subscr);
 
 	/* FIXME: do we have a better idea of the timing advance? */
 	rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0,
@@ -219,7 +219,7 @@
 	}
 
 	LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN "
-	     "%u->%u\n", subscr_name(ho->old_lchan->conn.subscr),
+	     "%u->%u\n", subscr_name(ho->old_lchan->conn->subscr),
 	     ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr,
 	     ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn);
 
@@ -228,7 +228,7 @@
 	bsc_del_timer(&ho->T3103);
 
 	/* update lchan pointer of transaction */
-	trans_lchan_change(&ho->old_lchan->conn, &new_lchan->conn);
+	trans_lchan_change(ho->old_lchan->conn, new_lchan->conn);
 
 	rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE);
 	lchan_auto_release(ho->old_lchan);
@@ -258,7 +258,7 @@
 
 	bsc_del_timer(&ho->T3103);
 	llist_del(&ho->list);
-	conn = &ho->new_lchan->conn;
+	conn = ho->new_lchan->conn;
 	put_subscr_con(conn);
 	talloc_free(ho);