ipa: Allow users closing lower layer tcp/ipa connections

This is useful for users to abort connections which are in "connecting"
state, since the higher layer struct e1inp_sign_link is not provided to
the user until the TCP+IPA handshake in the socket becomes fully
established (sign_link_up() callback).

This is intended for osmo-bts: when something fails and may enter into
SHUTDOWN state, it is desirable to close new RSL links (sockets) which
are in progress to connect, while it waits for a while to complete
shutdown (power ramping down, etc.).

Change-Id: Ia6418321f3b6f1f7274efd414625a4b10a09a362
diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c
index 2c1ae93..1b8d8d0 100644
--- a/src/input/ipaccess.c
+++ b/src/input/ipaccess.c
@@ -1163,6 +1163,7 @@
 	struct ipa_client_conn *rsl_link;
 	struct e1inp_ts *e1i_ts = e1inp_line_ipa_rsl_ts(line, trx_nr);
 	struct ipaccess_line *il;
+	int rc;
 
 	if (E1INP_SIGN_RSL+trx_nr-1 >= NUM_E1_TS) {
 		LOGP(DLINP, LOGL_ERROR, "cannot create RSL BTS link: "
@@ -1170,17 +1171,14 @@
 		return -EINVAL;
 	}
 
+	/* Drop previous line */
+	if ((rc = e1inp_ipa_bts_rsl_close_n(line, trx_nr)) < 0)
+		return rc;
+
 	if (!line->driver_data)
 		line->driver_data = talloc_zero(line, struct ipaccess_line);
 	il = line->driver_data;
 
-	/* Drop previous line */
-	if (il->ipa_cli[1 + trx_nr]) {
-		ipa_client_conn_close(il->ipa_cli[1 + trx_nr]);
-		ipa_client_conn_destroy(il->ipa_cli[1 + trx_nr]);
-		il->ipa_cli[1 + trx_nr] = NULL;
-	}
-
 	rsl_link = ipa_client_conn_create2(tall_ipa_ctx,
 					  e1inp_line_ipa_rsl_ts(line, trx_nr),
 					  E1INP_SIGN_RSL+trx_nr,
@@ -1209,6 +1207,29 @@
 	return 0;
 }
 
+/* Close the underlying IPA TCP socket of an RSL link */
+int e1inp_ipa_bts_rsl_close_n(struct e1inp_line *line, uint8_t trx_nr)
+{
+	struct ipaccess_line *il;
+
+	if (E1INP_SIGN_RSL+trx_nr-1 >= NUM_E1_TS) {
+		LOGP(DLINP, LOGL_ERROR,
+		     "cannot close RSL BTS link: trx_nr (%d) out of range\n", trx_nr);
+		return -EINVAL;
+	}
+
+	il = line->driver_data;
+	if (!il)
+		return 0; /* Nothing to do, no lines created */
+
+	if (il->ipa_cli[1 + trx_nr]) {
+		ipa_client_conn_close(il->ipa_cli[1 + trx_nr]);
+		ipa_client_conn_destroy(il->ipa_cli[1 + trx_nr]);
+		il->ipa_cli[1 + trx_nr] = NULL;
+	}
+	return 0;
+}
+
 void e1inp_ipaccess_init(void)
 {
 	tall_ipa_ctx = talloc_named_const(libosmo_abis_ctx, 1, "ipa");