sgsn: Integrate the GSUP client into the SGSN

This commit adds GSUP client configuration (via VTY), connection set
up, and real message sending.

The following configuration commands are added:

 - gsup remote-ip A.B.C.D            set server IP address
 - gsup remote-port PORT             set server TCP port

Ticket: OW#1338
Sponsored-by: On-Waves ehf
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index 8019ad1..84307a5 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -305,7 +305,7 @@
 		GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING  \
 )
 
-void gprs_subscr_init(struct sgsn_instance *sgi);
+int gprs_subscr_init(struct sgsn_instance *sgi);
 int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx);
 int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx);
 void gprs_subscr_delete(struct gsm_subscriber *subscr);
diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h
index 6b83337..71be1ce 100644
--- a/openbsc/include/openbsc/sgsn.h
+++ b/openbsc/include/openbsc/sgsn.h
@@ -7,6 +7,8 @@
 #include <osmocom/gprs/gprs_ns.h>
 #include <openbsc/gprs_sgsn.h>
 
+struct gprs_gsup_client;
+
 enum sgsn_auth_policy {
 	SGSN_AUTH_POLICY_OPEN,
 	SGSN_AUTH_POLICY_CLOSED,
@@ -25,6 +27,9 @@
 
 	enum sgsn_auth_policy auth_policy;
 	struct llist_head imsi_acl;
+
+	struct sockaddr_in gsup_server_addr;
+	int gsup_server_port;
 };
 
 struct sgsn_instance {
@@ -38,6 +43,8 @@
 	struct osmo_timer_list gtp_timer;
 	/* GSN instance for libgtp */
 	struct gsn_t *gsn;
+	/* Subscriber */
+	struct gprs_gsup_client *gsup_client;
 };
 
 extern struct sgsn_instance *sgsn;
diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c
index 461b3a5..04debff 100644
--- a/openbsc/src/gprs/gprs_subscriber.c
+++ b/openbsc/src/gprs/gprs_subscriber.c
@@ -20,6 +20,7 @@
  */
 
 #include <openbsc/gsm_subscriber.h>
+#include <openbsc/gprs_gsup_client.h>
 
 #include <openbsc/sgsn.h>
 #include <openbsc/gprs_sgsn.h>
@@ -28,10 +29,47 @@
 
 #include <openbsc/debug.h>
 
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
 extern void *tall_bsc_ctx;
 
-void gprs_subscr_init(struct sgsn_instance *sgi)
+static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg);
+
+/* TODO: Some functions are specific to the SGSN, but this file is more general
+ * (it has gprs_* name). Either move these functions elsewhere, split them and
+ * move a part, or replace the gprs_ prefix by sgsn_. The applies to
+ * gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message.
+ */
+
+int gprs_subscr_init(struct sgsn_instance *sgi)
 {
+	const char *addr_str;
+
+	if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr)
+		return 0;
+
+	addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
+
+	sgi->gsup_client = gprs_gsup_client_create(
+		addr_str, sgi->cfg.gsup_server_port,
+		&gsup_read_cb);
+
+	if (!sgi->gsup_client)
+		return -1;
+
+	return 1;
+}
+
+static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg)
+{
+	int rc;
+
+	rc = gprs_subscr_rx_gsup_message(msg);
+	if (rc < 0)
+		return -1;
+
+	return rc;
 }
 
 static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
@@ -96,17 +134,21 @@
 static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
 				       struct gprs_gsup_message *gsup_msg)
 {
-	struct msgb *msg = msgb_alloc(4096, __func__);
+	struct msgb *msg = gprs_gsup_msgb_alloc();
 
 	strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
 
 	gprs_gsup_encode(msg, gsup_msg);
 
 	LOGMMCTXP(LOGL_INFO, subscr->sgsn_data->mm,
-		  "Sending GSUP NYI, would send: %s\n", msgb_hexdump(msg));
-	msgb_free(msg);
+		  "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
 
-	return -ENOTSUP;
+	if (!sgsn->gsup_client) {
+		msgb_free(msg);
+		return -ENOTSUP;
+	}
+
+	return gprs_gsup_client_send(sgsn->gsup_client, msg);
 }
 
 static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
index 141eacf..f26b812 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -357,6 +357,12 @@
 		exit(2);
 	}
 
+	rc = gprs_subscr_init(&sgsn_inst);
+	if (rc < 0) {
+		LOGP(DGPRS, LOGL_FATAL, "Cannot set up subscriber management\n");
+		exit(2);
+	}
+
 	rc = gprs_ns_nsip_listen(sgsn_nsi);
 	if (rc < 0) {
 		LOGP(DGPRS, LOGL_FATAL, "Cannot bind/listen on NSIP socket\n");
diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c
index b15de75..e9333f5 100644
--- a/openbsc/src/gprs/sgsn_vty.c
+++ b/openbsc/src/gprs/sgsn_vty.c
@@ -139,6 +139,12 @@
 	vty_out(vty, " auth-policy %s%s",
 		get_value_string(sgsn_auth_pol_strs, g_cfg->auth_policy),
 		VTY_NEWLINE);
+	if (g_cfg->gsup_server_addr.sin_addr.s_addr)
+		vty_out(vty, " gsup remote-ip %s%s",
+			inet_ntoa(g_cfg->gsup_server_addr.sin_addr), VTY_NEWLINE);
+	if (g_cfg->gsup_server_port)
+		vty_out(vty, " gsup remote-port %d%s",
+			g_cfg->gsup_server_port, VTY_NEWLINE);
 	llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
 		vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
 
@@ -650,6 +656,29 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_gsup_remote_ip, cfg_gsup_remote_ip_cmd,
+	"gsup remote-ip A.B.C.D",
+	"GSUP Parameters\n"
+	"Set the IP address of the remote GSUP server\n"
+	"IPv4 Address\n")
+{
+	inet_aton(argv[0], &g_cfg->gsup_server_addr.sin_addr);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_gsup_remote_port, cfg_gsup_remote_port_cmd,
+	"gsup remote-port <0-65535>",
+	"GSUP Parameters\n"
+	"Set the TCP port of the remote GSUP server\n"
+	"Remote TCP port\n")
+{
+	g_cfg->gsup_server_port = atoi(argv[0]);
+
+	return CMD_SUCCESS;
+}
+
+
 
 int sgsn_vty_init(void)
 {
@@ -676,6 +705,8 @@
 	install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
 	install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
 	install_element(SGSN_NODE, &cfg_auth_policy_cmd);
+	install_element(SGSN_NODE, &cfg_gsup_remote_ip_cmd);
+	install_element(SGSN_NODE, &cfg_gsup_remote_port_cmd);
 
 	return 0;
 }
diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am
index c8dccfe..70e0924 100644
--- a/openbsc/tests/sgsn/Makefile.am
+++ b/openbsc/tests/sgsn/Makefile.am
@@ -22,9 +22,11 @@
 	$(top_builddir)/src/gprs/sgsn_libgtp.o \
 	$(top_builddir)/src/gprs/sgsn_auth.o \
 	$(top_builddir)/src/gprs/gprs_gsup_messages.o \
+	$(top_builddir)/src/gprs/gprs_gsup_client.o \
 	$(top_builddir)/src/gprs/gprs_utils.o \
 	$(top_builddir)/src/gprs/gprs_subscriber.o \
 	$(top_builddir)/src/libcommon/libcommon.a \
+	$(LIBOSMOABIS_LIBS) \
 	$(LIBOSMOCORE_LIBS) \
 	$(LIBOSMOGSM_LIBS) \
 	$(LIBOSMOGB_LIBS) \