ipaccess: initial works to get BTS mode working

This patch adds the initial support to get BTS mode working with
the ipaccess driver.

Now, the driver handles IPA ping, pong and id_ack messages
internally in BTS modes, and it passes the signalling messages
to the client application by invoking the callback line operations.

Moreover, with this patch, each IPA link object always has one
E1 line object associated.

Still HSL BTS-mode remains unimplemented.
diff --git a/src/input/hsl.c b/src/input/hsl.c
index cb1aa51..f8c009e 100644
--- a/src/input/hsl.c
+++ b/src/input/hsl.c
@@ -302,6 +302,12 @@
         return ret;
 }
 
+static int hsl_bts_process(struct ipa_link *link, struct msgb *msg)
+{
+	/* XXX: not implemented yet. */
+	return 0;
+}
+
 static int hsl_line_update(struct e1inp_line *line,
 			   enum e1inp_line_role role, const char *addr)
 {
@@ -331,7 +337,8 @@
 
 		LOGP(DINP, LOGL_NOTICE, "enabling hsl BTS mode\n");
 
-		link = ipa_client_link_create(tall_hsl_ctx, addr, HSL_TCP_PORT);
+		link = ipa_client_link_create(tall_hsl_ctx, line, addr,
+						HSL_TCP_PORT, hsl_bts_process);
 		if (link == NULL) {
 			LOGP(DINP, LOGL_ERROR, "cannot create BTS link: %s\n",
 				strerror(errno));
diff --git a/src/input/ipa.c b/src/input/ipa.c
index 7318e07..536490e 100644
--- a/src/input/ipa.c
+++ b/src/input/ipa.c
@@ -113,8 +113,8 @@
 		ipa_client_retry(link);
 		return;
 	}
-	if (link->process)
-		link->process(link, msg);
+	if (link->cb)
+		link->cb(link, msg);
 }
 
 static void ipa_client_write(struct ipa_link *link)
@@ -177,7 +177,9 @@
 static void ipa_link_timer_cb(void *data);
 
 struct ipa_link *
-ipa_client_link_create(void *ctx, const char *addr, uint16_t port)
+ipa_client_link_create(void *ctx, struct e1inp_line *line,
+		       const char *addr, uint16_t port,
+		       int (*cb)(struct ipa_link *link, struct msgb *msgb))
 {
 	struct ipa_link *ipa_link;
 
@@ -193,6 +195,8 @@
 	ipa_link->timer.data = ipa_link;
 	ipa_link->addr = talloc_strdup(ipa_link, addr);
 	ipa_link->port = port;
+	ipa_link->cb = cb;
+	ipa_link->line = line;
 
 	return ipa_link;
 }
diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c
index 71db51d..19e5a53 100644
--- a/src/input/ipaccess.c
+++ b/src/input/ipaccess.c
@@ -428,6 +428,56 @@
 	return 0;
 }
 
+static int ipaccess_bts_cb(struct ipa_link *link, struct msgb *msg)
+{
+	struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
+	struct e1inp_ts *e1i_ts = NULL;
+	struct e1inp_sign_link *sign_link;
+
+	/* special handling for IPA CCM. */
+	if (hh->proto == IPAC_PROTO_IPACCESS) {
+		uint8_t msg_type = *(msg->l2h);
+
+		/* ping, pong and acknowledgment cases. */
+		ipaccess_rcvmsg_base(msg, &link->ofd);
+
+		/* this is a request for identification from the BSC. */
+		if (msg_type == IPAC_MSGT_ID_GET) {
+			LOGP(DINP, LOGL_NOTICE, "received ID get\n");
+			if (!link->line->ops.sign_link_up) {
+				LOGP(DINP, LOGL_ERROR, "Fix your application, "
+					"no action set if the signalling link "
+					"becomes ready\n");
+				return -EINVAL;
+			}
+			link->line->ops.sign_link_up(msg, link->line);
+		}
+		return 0;
+	} else if (link->port == IPA_TCP_PORT_OML)
+		e1i_ts = &link->line->ts[0];
+	else if (link->port == IPA_TCP_PORT_RSL)
+		e1i_ts = &link->line->ts[1];
+
+	/* look up for some existing signaling link. */
+	sign_link = e1inp_lookup_sign_link(e1i_ts, hh->proto, 0);
+	if (sign_link == NULL) {
+		LOGP(DINP, LOGL_ERROR, "no matching signalling link for "
+			"hh->proto=0x%02x\n", hh->proto);
+		msgb_free(msg);
+		return -EIO;
+	}
+	msg->dst = sign_link;
+
+	/* XXX better use e1inp_ts_rx? */
+	if (!link->line->ops.sign_link) {
+		LOGP(DINP, LOGL_ERROR, "Fix your application, "
+			"no action set for signalling messages.\n");
+		return -ENOENT;
+	}
+	link->line->ops.sign_link(msg, sign_link);
+	return 0;
+}
+
 static int ipaccess_line_update(struct e1inp_line *line,
 				enum e1inp_line_role role, const char *addr)
 {
@@ -473,8 +523,9 @@
 
 		LOGP(DINP, LOGL_NOTICE, "enabling ipaccess BTS mode\n");
 
-		link = ipa_client_link_create(tall_ipa_ctx,
-						addr, IPA_TCP_PORT_OML);
+		link = ipa_client_link_create(tall_ipa_ctx, line,
+					      addr, IPA_TCP_PORT_OML,
+					      ipaccess_bts_cb);
 		if (link == NULL) {
 			LOGP(DINP, LOGL_ERROR, "cannot create OML "
 				"BTS link: %s\n", strerror(errno));
@@ -487,8 +538,9 @@
 			ipa_client_link_destroy(link);
 			return -EIO;
 		}
-		rsl_link = ipa_client_link_create(tall_ipa_ctx,
-						  addr, IPA_TCP_PORT_RSL);
+		rsl_link = ipa_client_link_create(tall_ipa_ctx, line,
+						  addr, IPA_TCP_PORT_RSL,
+						  ipaccess_bts_cb);
 		if (rsl_link == NULL) {
 			LOGP(DINP, LOGL_ERROR, "cannot create RSL "
 				"BTS link: %s\n", strerror(errno));