IPA: remove automatic reconnect logic

When an IPA link is in client (BTS) mode, we should not automatically
re-connect in the lowest (ipa) layer.  Instead, we properly close the
socket if the link is dead, and we call link->updown_cb() to notify
the user that the link is down.

The e1inp/ipaccess layer translates this into a line->sign_link_down()
callback that propagates up to the user.
diff --git a/include/osmocom/abis/ipa.h b/include/osmocom/abis/ipa.h
index 397cf9c..d577d74 100644
--- a/include/osmocom/abis/ipa.h
+++ b/include/osmocom/abis/ipa.h
@@ -49,13 +49,13 @@
 	enum ipa_client_conn_state	state;
 	const char			*addr;
 	uint16_t			port;
-	int (*connect_cb)(struct ipa_client_conn *link);
+	void (*updown_cb)(struct ipa_client_conn *link, int up);
 	int (*read_cb)(struct ipa_client_conn *link, struct msgb *msg);
 	int (*write_cb)(struct ipa_client_conn *link);
 	void				*data;
 };
 
-struct ipa_client_conn *ipa_client_conn_create(void *ctx, struct e1inp_ts *ts, int priv_nr, const char *addr, uint16_t port, int (*connect)(struct ipa_client_conn *link), int (*read_cb)(struct ipa_client_conn *link, struct msgb *msgb), int (*write_cb)(struct ipa_client_conn *link), void *data);
+struct ipa_client_conn *ipa_client_conn_create(void *ctx, struct e1inp_ts *ts, int priv_nr, const char *addr, uint16_t port, void (*updown)(struct ipa_client_conn *link, int), int (*read_cb)(struct ipa_client_conn *link, struct msgb *msgb), int (*write_cb)(struct ipa_client_conn *link), void *data);
 void ipa_client_conn_destroy(struct ipa_client_conn *link);
 
 int ipa_client_conn_open(struct ipa_client_conn *link);
diff --git a/src/input/ipa.c b/src/input/ipa.c
index 8c6f603..ba92163 100644
--- a/src/input/ipa.c
+++ b/src/input/ipa.c
@@ -95,17 +95,6 @@
 	return ret;
 }
 
-void ipa_client_conn_close(struct ipa_client_conn *link);
-
-static void ipa_client_retry(struct ipa_client_conn *link)
-{
-	LOGP(DLINP, LOGL_NOTICE, "connection closed\n");
-	ipa_client_conn_close(link);
-	LOGP(DLINP, LOGL_NOTICE, "retrying in 5 seconds...\n");
-	osmo_timer_schedule(&link->timer, 5, 0);
-	link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
-}
-
 void ipa_client_conn_close(struct ipa_client_conn *link)
 {
 	/* be safe against multiple calls */
@@ -129,11 +118,15 @@
 		if (errno == EPIPE || errno == ECONNRESET) {
 			LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
 		}
-		ipa_client_retry(link);
+		ipa_client_conn_close(link);
+		if (link->updown_cb)
+			link->updown_cb(link, 0);
 		return;
 	} else if (ret == 0) {
 		LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
-		ipa_client_retry(link);
+		ipa_client_conn_close(link);
+		if (link->updown_cb)
+			link->updown_cb(link, 0);
 		return;
 	}
 	if (link->read_cb)
@@ -166,7 +159,9 @@
 	ret = send(link->ofd->fd, msg->data, msg->len, 0);
 	if (ret < 0) {
 		if (errno == EPIPE || errno == ENOTCONN) {
-			ipa_client_retry(link);
+			ipa_client_conn_close(link);
+			if (link->updown_cb)
+				link->updown_cb(link, 0);
 		}
 		LOGP(DLINP, LOGL_ERROR, "error to send\n");
 	}
@@ -184,14 +179,16 @@
 	case IPA_CLIENT_LINK_STATE_CONNECTING:
 		ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
 		if (ret >= 0 && error > 0) {
-			ipa_client_retry(link);
+			ipa_client_conn_close(link);
+			if (link->updown_cb)
+				link->updown_cb(link, 0);
 			return 0;
 		}
 		ofd->when &= ~BSC_FD_WRITE;
 		LOGP(DLINP, LOGL_NOTICE, "connection done.\n");
 		link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
-		if (link->connect_cb)
-			link->connect_cb(link);
+		if (link->updown_cb)
+			link->updown_cb(link, 1);
 		break;
 	case IPA_CLIENT_LINK_STATE_CONNECTED:
 		if (what & BSC_FD_READ) {
@@ -209,12 +206,10 @@
         return 0;
 }
 
-static void ipa_link_timer_cb(void *data);
-
 struct ipa_client_conn *
 ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
 		       int priv_nr, const char *addr, uint16_t port,
-		       int (*connect_cb)(struct ipa_client_conn *link),
+		       void (*updown_cb)(struct ipa_client_conn *link, int up),
 		       int (*read_cb)(struct ipa_client_conn *link,
 				      struct msgb *msgb),
 		       int (*write_cb)(struct ipa_client_conn *link),
@@ -244,12 +239,11 @@
 	ipa_link->ofd->priv_nr = priv_nr;
 	ipa_link->ofd->cb = ipa_client_fd_cb;
 	ipa_link->ofd->data = ipa_link;
+	ipa_link->ofd->fd = -1;
 	ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
-	ipa_link->timer.cb = ipa_link_timer_cb;
-	ipa_link->timer.data = ipa_link;
 	ipa_link->addr = talloc_strdup(ipa_link, addr);
 	ipa_link->port = port;
-	ipa_link->connect_cb = connect_cb;
+	ipa_link->updown_cb = updown_cb;
 	ipa_link->read_cb = read_cb;
 	/* default to generic write callback if not set. */
 	if (write_cb == NULL)
@@ -284,26 +278,13 @@
 	link->ofd->fd = ret;
 	if (osmo_fd_register(link->ofd) < 0) {
 		close(ret);
+		link->ofd->fd = -1;
 		return -EIO;
 	}
+
 	return 0;
 }
 
-static void ipa_link_timer_cb(void *data)
-{
-	struct ipa_client_conn *link = data;
-
-	LOGP(DLINP, LOGL_NOTICE, "reconnecting.\n");
-
-	switch(link->state) {
-	case IPA_CLIENT_LINK_STATE_CONNECTING:
-		ipa_client_conn_open(link);
-	        break;
-	default:
-		break;
-	}
-}
-
 void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
 {
 	msgb_enqueue(&link->tx_queue, msg);
diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c
index 6663b9f..cf0cc15 100644
--- a/src/input/ipaccess.c
+++ b/src/input/ipaccess.c
@@ -800,6 +800,17 @@
 	return nmsg2;
 }
 
+static void ipaccess_bts_updown_cb(struct ipa_client_conn *link, int up)
+{
+	struct e1inp_line *line = link->line;
+
+	if (up)
+		return;
+
+	if (line->ops->sign_link_down)
+		line->ops->sign_link_down(line);
+}
+
 static int ipaccess_bts_read_cb(struct ipa_client_conn *link, struct msgb *msg)
 {
 	struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
@@ -973,7 +984,7 @@
 					      E1INP_SIGN_OML,
 					      line->ops->cfg.ipa.addr,
 					      IPA_TCP_PORT_OML,
-					      NULL,
+					      ipaccess_bts_updown_cb,
 					      ipaccess_bts_read_cb,
 					      ipaccess_bts_write_cb,
 					      line);
@@ -1007,7 +1018,7 @@
 					  &line->ts[E1INP_SIGN_RSL-1],
 					  E1INP_SIGN_RSL,
 					  rem_addr, rem_port,
-					  NULL,
+					  ipaccess_bts_updown_cb,
 					  ipaccess_bts_read_cb,
 					  ipaccess_bts_write_cb,
 					  line);