reg-proxy: add application which allows translate SUP to SIP and SIP to SUP
diff --git a/openbsc/configure.ac b/openbsc/configure.ac
index 7e244bc..c31d36e 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -234,6 +234,7 @@
     src/ipaccess/Makefile
     src/utils/Makefile
     src/gprs/Makefile
+    src/reg-proxy/Makefile
     tests/Makefile
     tests/atlocal
     tests/gsm0408/Makefile
diff --git a/openbsc/include/openbsc/reg_proxy.h b/openbsc/include/openbsc/reg_proxy.h
new file mode 100644
index 0000000..03c0195
--- /dev/null
+++ b/openbsc/include/openbsc/reg_proxy.h
@@ -0,0 +1,15 @@
+#ifndef _REG_PROXY_H
+#define _REG_PROXY_H
+
+#include <openbsc/sup_server.h>
+#include <openbsc/sip_client.h>
+#include <osip2/osip.h>
+void *tall_reg_ctx;
+
+struct reg_proxy {
+	struct gsm_sup_server *sup_server;
+	struct sip_client *sip_client;
+	osip_t *osip;
+};
+
+#endif /* _REG_PROXY_H */
diff --git a/openbsc/include/openbsc/sip.h b/openbsc/include/openbsc/sip.h
new file mode 100644
index 0000000..8a7a562
--- /dev/null
+++ b/openbsc/include/openbsc/sip.h
@@ -0,0 +1,12 @@
+#ifndef _SIP_H
+#define _SIP_H
+
+#include <openbsc/sip_client.h>
+#include <openbsc/reg_proxy.h>
+#include <osip2/osip.h>
+
+int tx_sip_register(struct sip_client *sip_client, osip_t *osip, char *imsi);
+
+int sip_client_init(struct reg_proxy *reg, const char *src_ip, u_int16_t src_port,
+                                           const char *dst_ip, u_int16_t dst_port);
+#endif /* _SIP_H */
diff --git a/openbsc/include/openbsc/sip_client.h b/openbsc/include/openbsc/sip_client.h
new file mode 100644
index 0000000..23eaa7f
--- /dev/null
+++ b/openbsc/include/openbsc/sip_client.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <osmocom/core/timer.h>
+
+#define SIP_RECONNECT_INTERVAL 10
+
+struct msgb;
+struct ipa_client_conn;
+struct sip_client;
+
+/* Expects message in msg->l2h */
+typedef int (*sip_read_cb_t)(struct sip_client *sip_client, struct msgb *msg);
+
+struct sip_client {
+	struct tcp_client_conn	*link;
+	sip_read_cb_t	read_cb;
+	void			*data;
+
+	struct osmo_timer_list	connect_timer;
+	int			is_connected;
+
+	char *src_ip;
+	char *dst_ip;
+	u_int16_t src_port;
+	u_int16_t dst_port;
+};
+
+struct sip_client *sip_client_create(const char *src_ip, u_int16_t src_port,
+                                     const char *dst_ip, u_int16_t dst_port,
+                                          sip_read_cb_t read_cb, void *data);
+
+void sip_client_destroy(struct sip_client *sip_client);
+int sip_client_send(struct sip_client *sip_client, struct msgb *msg);
+struct msgb *sip_msgb_alloc(void);
diff --git a/openbsc/include/openbsc/sup.h b/openbsc/include/openbsc/sup.h
new file mode 100644
index 0000000..29518f3
--- /dev/null
+++ b/openbsc/include/openbsc/sup.h
@@ -0,0 +1,16 @@
+#ifndef _SUP_H
+#define _SUP_H
+
+#include <openbsc/reg_proxy.h>
+
+#define LOGGSUPP(level, sup, fmt, args...) \
+	LOGP(DGPRS, level, "SUP(%s) " fmt, \
+	     (sup)->imsi, \
+	     ## args)
+
+int sup_server_init(struct reg_proxy *reg);
+
+int handle_location_update_result(struct gsm_sup_server *sup_server,
+								 char *imsi, char *msisdn);
+
+#endif /* _SUP_H */
diff --git a/openbsc/include/openbsc/sup_server.h b/openbsc/include/openbsc/sup_server.h
new file mode 100644
index 0000000..5261e63
--- /dev/null
+++ b/openbsc/include/openbsc/sup_server.h
@@ -0,0 +1,29 @@
+#ifndef _SUP_SERVER_H
+#define _SUP_SERVER_H
+
+#include <osmocom/abis/ipa.h>
+
+//struct msgb;
+struct ipa_server_conn;
+struct gsm_sup_server;
+
+/* Expects message in msg->l2h */
+typedef int (*sup_read_cb_t)(struct gsm_sup_server *sup_server, struct msgb *msg);
+
+struct gsm_sup_server {
+	struct ipa_server_link	*link;
+	sup_read_cb_t	read_cb;
+	void			*data;
+	struct osmo_fd fd;
+	struct ipa_server_conn *server_conn;
+	void *app;
+};
+
+struct gsm_sup_server *sup_server_create(const char *ip_addr,
+						 unsigned int tcp_port,
+						 sup_read_cb_t read_cb,
+						 void *app);
+
+int sup_server_send(struct gsm_sup_server *sup_server, struct msgb *msg);
+
+#endif /* _SUP_SERVER_H */
diff --git a/openbsc/include/openbsc/tcp_client.h b/openbsc/include/openbsc/tcp_client.h
new file mode 100644
index 0000000..f815a3c
--- /dev/null
+++ b/openbsc/include/openbsc/tcp_client.h
@@ -0,0 +1,51 @@
+#ifndef _TCP_CLIENT_H_
+#define _TCP_CLIENT_H_
+
+#include <stdint.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/select.h>
+
+
+struct msgb;
+
+enum tcp_client_conn_state {
+	TCP_CLIENT_LINK_STATE_NONE         = 0,
+	TCP_CLIENT_LINK_STATE_CONNECTING   = 1,
+	TCP_CLIENT_LINK_STATE_CONNECTED    = 2,
+	TCP_CLIENT_LINK_STATE_MAX
+};
+
+struct tcp_client_conn {
+	struct osmo_fd			*ofd;
+	struct llist_head		tx_queue;
+	struct osmo_timer_list		timer;
+	enum tcp_client_conn_state	state;
+	const char			*src_addr;
+	uint16_t			src_port;
+	const char			*dst_addr;
+	uint16_t			dst_port;
+	void (*updown_cb)(struct tcp_client_conn *link, int up);
+	int (*read_cb)(struct tcp_client_conn *link, struct msgb *msg);
+	int (*write_cb)(struct tcp_client_conn *link);
+	void				*data;
+	struct msgb			*pending_msg;
+};
+
+struct tcp_client_conn *
+tcp_client_conn_create(void *ctx, int priv_nr,
+			const char *dst_addr, uint16_t dst_port,
+			const char *src_addr, uint16_t src_port,
+			void (*updown)(struct tcp_client_conn *link, int),
+			int (*read_cb)(struct tcp_client_conn *link, struct msgb *msgb),
+			int (*write_cb)(struct tcp_client_conn *link),
+			void *data);
+void tcp_client_conn_destroy(struct tcp_client_conn *link);
+
+int tcp_client_conn_open(struct tcp_client_conn *link);
+void tcp_client_conn_close(struct tcp_client_conn *link);
+
+void tcp_client_conn_send(struct tcp_client_conn *link, struct msgb *msg);
+size_t tcp_client_conn_clear_queue(struct tcp_client_conn *link);
+
+#endif
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index cfad7df..cb6041c 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -44,6 +44,7 @@
 	utils \
 	ipaccess \
 	gprs \
+	reg-proxy \
 	$(NULL)
 
 # Conditional Programs
diff --git a/openbsc/src/libmsc/gsm_04_08_gprs.c b/openbsc/src/libmsc/gsm_04_08_gprs.c
new file mode 100644
index 0000000..3ae50e2
--- /dev/null
+++ b/openbsc/src/libmsc/gsm_04_08_gprs.c
@@ -0,0 +1,141 @@
+/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010      by On-Waves
+ * (C) 2014-2015 by Sysmocom s.f.m.c. GmbH
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include <openbsc/gsm_04_08_gprs.h>
+
+#include <osmocom/core/utils.h>
+
+/* Protocol related stuff, should go into libosmocore */
+
+/* 10.5.5.14 GPRS MM Cause / Table 10.5.147 */
+const struct value_string gsm48_gmm_cause_names_[] = {
+	{ GMM_CAUSE_IMSI_UNKNOWN,	"IMSI unknown in HLR" },
+	{ GMM_CAUSE_ILLEGAL_MS,		"Illegal MS" },
+	{ GMM_CAUSE_ILLEGAL_ME,		"Illegal ME" },
+	{ GMM_CAUSE_GPRS_NOTALLOWED,	"GPRS services not allowed" },
+	{ GMM_CAUSE_GPRS_OTHER_NOTALLOWED,
+			"GPRS services and non-GPRS services not allowed" },
+	{ GMM_CAUSE_MS_ID_NOT_DERIVED,
+			"MS identity cannot be derived by the network" },
+	{ GMM_CAUSE_IMPL_DETACHED,	"Implicitly detached" },
+	{ GMM_CAUSE_PLMN_NOTALLOWED,	"PLMN not allowed" },
+	{ GMM_CAUSE_LA_NOTALLOWED,	"Location Area not allowed" },
+	{ GMM_CAUSE_ROAMING_NOTALLOWED,
+			"Roaming not allowed in this location area" },
+	{ GMM_CAUSE_NO_GPRS_PLMN,
+				"GPRS services not allowed in this PLMN" },
+	{ GMM_CAUSE_MSC_TEMP_NOTREACH,	"MSC temporarily not reachable" },
+	{ GMM_CAUSE_NET_FAIL,		"Network failure" },
+	{ GMM_CAUSE_CONGESTION,		"Congestion" },
+	{ GMM_CAUSE_SEM_INCORR_MSG,	"Semantically incorrect message" },
+	{ GMM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" },
+	{ GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL,
+			"Message type non-existant or not implemented" },
+	{ GMM_CAUSE_MSGT_INCOMP_P_STATE,
+			"Message type not compatible with protocol state" },
+	{ GMM_CAUSE_IE_NOTEXIST_NOTIMPL,
+			"Information element non-existent or not implemented" },
+	{ GMM_CAUSE_COND_IE_ERR,	"Conditional IE error" },
+	{ GMM_CAUSE_MSG_INCOMP_P_STATE,
+				"Message not compatible with protocol state " },
+	{ GMM_CAUSE_PROTO_ERR_UNSPEC,	"Protocol error, unspecified" },
+	{ 0, NULL }
+};
+
+const struct value_string *gsm48_gmm_cause_names = gsm48_gmm_cause_names_;
+
+/* 10.5.6.6 SM Cause / Table 10.5.157 */
+const struct value_string gsm48_gsm_cause_names_[] = {
+	{ GSM_CAUSE_INSUFF_RSRC, "Insufficient resources" },
+	{ GSM_CAUSE_MISSING_APN, "Missing or unknown APN" },
+	{ GSM_CAUSE_UNKNOWN_PDP, "Unknown PDP address or PDP type" },
+	{ GSM_CAUSE_AUTH_FAILED, "User Authentication failed" },
+	{ GSM_CAUSE_ACT_REJ_GGSN, "Activation rejected by GGSN" },
+	{ GSM_CAUSE_ACT_REJ_UNSPEC, "Activation rejected, unspecified" },
+	{ GSM_CAUSE_SERV_OPT_NOTSUPP, "Service option not supported" },
+	{ GSM_CAUSE_REQ_SERV_OPT_NOTSUB,
+				"Requested service option not subscribed" },
+	{ GSM_CAUSE_SERV_OPT_TEMP_OOO,
+				"Service option temporarily out of order" },
+	{ GSM_CAUSE_NSAPI_IN_USE, "NSAPI already used" },
+	{ GSM_CAUSE_DEACT_REGULAR, "Regular deactivation" },
+	{ GSM_CAUSE_QOS_NOT_ACCEPTED, "QoS not accepted" },
+	{ GSM_CAUSE_NET_FAIL, "Network Failure" },
+	{ GSM_CAUSE_REACT_RQD, "Reactivation required" },
+	{ GSM_CAUSE_FEATURE_NOTSUPP, "Feature not supported " },
+	{ GSM_CAUSE_INVALID_TRANS_ID, "Invalid transaction identifier" },
+	{ GSM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" },
+	{ GSM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" },
+	{ GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL,
+			"Message type non-existant or not implemented" },
+	{ GSM_CAUSE_MSGT_INCOMP_P_STATE,
+			"Message type not compatible with protocol state" },
+	{ GSM_CAUSE_IE_NOTEXIST_NOTIMPL,
+			"Information element non-existent or not implemented" },
+	{ GSM_CAUSE_COND_IE_ERR, "Conditional IE error" },
+	{ GSM_CAUSE_MSG_INCOMP_P_STATE,
+				"Message not compatible with protocol state " },
+	{ GSM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" },
+	{ 0, NULL }
+};
+
+const struct value_string *gsm48_gsm_cause_names = gsm48_gsm_cause_names_;
+
+/* 10.5.5.2 */
+const struct value_string gprs_att_t_strs_[] = {
+	{ GPRS_ATT_T_ATTACH,		"GPRS attach" },
+	{ GPRS_ATT_T_ATT_WHILE_IMSI,	"GPRS attach while IMSI attached" },
+	{ GPRS_ATT_T_COMBINED,		"Combined GPRS/IMSI attach" },
+	{ 0, NULL }
+};
+
+const struct value_string *gprs_att_t_strs = gprs_att_t_strs_;
+
+const struct value_string gprs_upd_t_strs_[] = {
+	{ GPRS_UPD_T_RA,		"RA updating" },
+	{ GPRS_UPD_T_RA_LA,		"combined RA/LA updating" },
+	{ GPRS_UPD_T_RA_LA_IMSI_ATT,	"combined RA/LA updating + IMSI attach" },
+	{ GPRS_UPD_T_PERIODIC,		"periodic updating" },
+	{ 0, NULL }
+};
+
+const struct value_string *gprs_upd_t_strs = gprs_upd_t_strs_;
+
+/* 10.5.5.5 */
+const struct value_string gprs_det_t_mo_strs_[] = {
+	{ GPRS_DET_T_MO_GPRS,		"GPRS detach" },
+	{ GPRS_DET_T_MO_IMSI,		"IMSI detach" },
+	{ GPRS_DET_T_MO_COMBINED,	"Combined GPRS/IMSI detach" },
+	{ 0, NULL }
+};
+
+const struct value_string *gprs_det_t_mo_strs = gprs_det_t_mo_strs_;
+
+const struct value_string gprs_det_t_mt_strs_[] = {
+	{ GPRS_DET_T_MT_REATT_REQ,	"re-attach required" },
+	{ GPRS_DET_T_MT_REATT_NOTREQ,	"re-attach not required" },
+	{ GPRS_DET_T_MT_IMSI,		"IMSI detach (after VLR failure)" },
+	{ 0, NULL }
+};
+
+const struct value_string *gprs_det_t_mt_strs = gprs_det_t_mt_strs_;
+
diff --git a/openbsc/src/reg-proxy/Makefile.am b/openbsc/src/reg-proxy/Makefile.am
new file mode 100644
index 0000000..57d6fd5
--- /dev/null
+++ b/openbsc/src/reg-proxy/Makefile.am
@@ -0,0 +1,21 @@
+AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS=-Wall	$(COVERAGE_CFLAGS)			\
+  	$(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
+	$(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS)
+
+AM_LDFLAGS = $(COVERAGE_LDFLAGS)
+
+bin_PROGRAMS = reg-proxy
+
+reg_proxy_SOURCES = \
+		../gprs/gsm_04_08_gprs.c \
+		../gprs/gprs_utils.c \
+		../gprs/gprs_gsup_messages.c ../gprs/gprs_gsup_client.c \
+		tcp_client.c sup_server.c sup.c sip.c sip_client.c reg_proxy.c
+
+reg_proxy_LDADD = \
+		-losipparser2 -losip2 \
+		$(top_builddir)/src/libcommon/libcommon.a \
+		-ldbi $(LIBCRYPT)				   \
+		$(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS)  \
+		$(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS)
diff --git a/openbsc/src/reg-proxy/reg_proxy.c b/openbsc/src/reg-proxy/reg_proxy.c
new file mode 100644
index 0000000..3ad9f0c
--- /dev/null
+++ b/openbsc/src/reg-proxy/reg_proxy.c
@@ -0,0 +1,302 @@
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#define ENABLE_TRACE
+#include <osip2/osip.h>
+
+//#define _GNU_SOURCE
+//#include <getopt.h>
+
+//#include <openbsc/db.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/select.h>
+#include <openbsc/debug.h>
+//#include <osmocom/abis/abis.h>
+//#include <osmocom/abis/e1_input.h>
+#include <osmocom/core/talloc.h>
+#include <openbsc/signal.h>
+//#include <openbsc/osmo_msc.h>
+//#include <openbsc/osmo_msc_data.h>
+//#include <openbsc/sms_queue.h>
+//#include <openbsc/vty.h>
+//#include <openbsc/bss.h>
+//#include <openbsc/mncc.h>
+//#include <openbsc/token_auth.h>
+//#include <openbsc/handover_decision.h>
+//#include <openbsc/rrlp.h>
+//#include <osmocom/ctrl/control_if.h>
+//#include <osmocom/ctrl/ports.h>
+//#include <openbsc/ctrl.h>
+//#include <openbsc/osmo_bsc_rf.h>
+//#include <openbsc/smpp.h>
+#include <openbsc/reg_proxy.h>
+#include <openbsc/sup.h>
+#include <openbsc/sip.h>
+
+#define DIPA_PROXY_TEST 0
+
+static const char *sip_src_ip = "127.0.0.1";
+static const char *sip_dst_ip = "127.0.0.1";
+static u_int16_t src_port = 5050;
+static u_int16_t dst_port = 5060;
+
+struct log_info_cat ipa_proxy_test_cat[] = {
+	[DIPA_PROXY_TEST] = {
+		.name = "DLINP_IPA_PROXY_TEST",
+		.description = "IPA proxy test",
+		.color = "\033[1;35m",
+		.enabled = 1, .loglevel = LOGL_DEBUG,
+	},
+};
+
+const struct log_info ipa_proxy_test_log_info = {
+	.filter_fn = NULL,
+	.cat = ipa_proxy_test_cat,
+	.num_cat = ARRAY_SIZE(ipa_proxy_test_cat),
+};
+
+
+static void print_usage()
+{
+	printf("Usage: reg-proxy\n");
+}
+
+static void print_help()
+{
+	printf("  Some useful help...\n");
+	printf("  -h --help this text\n");
+	printf("  -S --sip-src-ip ip-addr Sip client IP address (source).\n");
+	printf("  -s --src-port port Sip client port (source).\n");
+	printf("  -D --sip-dst-ip ip-addr Sip server IP address (destination).\n");
+	printf("  -d --dst-port port Sip server port (destination).\n");
+}
+
+static void handle_options(int argc, char **argv)
+{
+	while (1) {
+		int option_index = 0, c;
+		static struct option long_options[] = {
+			{"help", 0, 0, 'h'},
+			{"sip-src-ip", 1, 0, 'S'},
+			{"src-port", 1, 0, 's'},
+			{"sip-dst-ip", 1, 0, 'D'},
+			{"dst-port", 1, 0, 'd'},
+			{0, 0, 0, 0}
+		};
+
+		c = getopt_long(argc, argv, "hS:s:D:d:",
+				long_options, &option_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'h':
+			print_usage();
+			print_help();
+			exit(0);
+		case 'S':
+			sip_src_ip = optarg;
+			break;
+		case 's':
+			src_port = atoi(optarg);
+			break;
+		case 'D':
+			sip_dst_ip = optarg;
+			break;
+		case 'd':
+			dst_port = atoi(optarg);
+			break;
+		default:
+			/* ignore */
+			break;
+		}
+	}
+}
+
+
+struct reg_proxy *reg_proxy_init()
+{
+	struct reg_proxy *reg;
+
+	reg = talloc_zero(tall_reg_ctx, struct reg_proxy);
+	if (!reg)
+		return NULL;
+	return reg;
+}
+
+static void signal_handler(int signal)
+{
+	fprintf(stdout, "signal %u received\n", signal);
+
+	switch (signal) {
+	case SIGINT:
+		//bsc_shutdown_net(bsc_gsmnet);
+		//osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
+		sleep(3);
+		exit(0);
+		break;
+	case SIGABRT:
+		/* in case of abort, we want to obtain a talloc report
+		 * and then return to the caller, who will abort the process */
+	case SIGUSR1:
+		talloc_report(tall_reg_ctx, stderr);
+		talloc_report_full(tall_reg_ctx, stderr);
+		break;
+	case SIGUSR2:
+		talloc_report_full(tall_reg_ctx, stderr);
+		break;
+	default:
+		break;
+	}
+}
+
+void printf_trace_func (char *fi, int li, osip_trace_level_t level, char *chfr, va_list ap)
+{
+    const char* desc = "       ";
+    switch(level)
+    {
+    case OSIP_FATAL:
+        desc = " FATAL ";
+        break;
+    case OSIP_BUG:
+        desc = "  BUG  ";
+        break;
+    case OSIP_ERROR:
+        desc = " ERROR ";
+        break;
+    case OSIP_WARNING:
+        desc = "WARNING";
+        break;
+    case OSIP_INFO1:
+        desc = " INFO1 ";
+        break;
+    case OSIP_INFO2:
+        desc = " INFO2 ";
+        break;
+    case OSIP_INFO3:
+        desc = " INFO3 ";
+        break;
+    case OSIP_INFO4:
+        desc = " INFO4 ";
+        break;
+    default:
+        desc = "       ";
+    }
+    
+    printf ("|%s| <%s: %i> | ", desc, fi, li);
+    vprintf(chfr, ap);
+    printf ("\n");
+}
+
+
+int main(int argc, char **argv)
+{
+	int rc;
+	struct reg_proxy *reg;
+
+	tall_reg_ctx = talloc_named_const(NULL, 1, "reg_proxy");
+	//talloc_ctx_init();
+
+	//libosmo_abis_init(tall_reg_ctx);
+	osmo_init_logging(&log_info);
+	printf("Initializing OSIP\n");
+	
+	// use custom function
+	osip_trace_initialize_func(END_TRACE_LEVEL, &printf_trace_func);
+
+
+	//osmo_init_logging(&ipa_proxy_test_log_info);
+
+	/* seed the PRNG */
+	//srand(time(NULL));
+
+/*
+	if (db_init(database_name)) {
+		printf("DB: Failed to init database. Please check the option settings.\n");
+		return -1;
+	}
+	printf("DB: Database initialized.\n");
+
+	if (db_prepare()) {
+		printf("DB: Failed to prepare database.\n");
+		return -1;
+	}
+	printf("DB: Database prepared.\n");
+*/
+	/* parse options */
+	handle_options(argc, argv);
+
+	reg = reg_proxy_init();
+	if (!reg) {
+		LOGP(DSUP, LOGL_FATAL, "Cannot create reg_proxy struck\n");
+		exit(2);
+	}
+	rc = sup_server_init(reg);
+	if (rc < 0) {
+		LOGP(DSUP, LOGL_FATAL, "Cannot set up subscriber management\n");
+		exit(2);
+	}
+
+////////////////////////////////
+
+	rc = sip_client_init(reg, sip_src_ip, src_port, sip_dst_ip, dst_port);
+	if (rc < 0) {
+		LOGP(DSUP, LOGL_FATAL, "Cannot set up SIP\n");
+		exit(2);
+	}
+
+
+
+
+	/* setup the timer */
+/*
+	db_sync_timer.cb = db_sync_timer_cb;
+	db_sync_timer.data = NULL;
+	if (use_db_counter)
+		osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL);
+
+	bsc_gsmnet->subscr_expire_timer.cb = subscr_expire_cb;
+	bsc_gsmnet->subscr_expire_timer.data = NULL;
+	osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL);
+*/
+	signal(SIGINT, &signal_handler);
+	signal(SIGABRT, &signal_handler);
+	signal(SIGUSR1, &signal_handler);
+	signal(SIGUSR2, &signal_handler);
+	osmo_init_ignore_signals();
+
+/*
+	if (daemonize) {
+		rc = osmo_daemonize();
+		if (rc < 0) {
+			perror("Error during daemonize");
+			exit(1);
+		}
+	}
+*/
+	printf("Entering Main loop 1\n");
+	OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Check OSIP_TRACE init\n"));
+
+	while (1) {
+		log_reset_context();
+		osmo_select_main(0);
+		osip_nict_execute(reg->osip);
+		osip_timers_nict_execute(reg->osip);
+
+	}
+}
diff --git a/openbsc/src/reg-proxy/sip.c b/openbsc/src/reg-proxy/sip.c
new file mode 100644
index 0000000..6b52aa5
--- /dev/null
+++ b/openbsc/src/reg-proxy/sip.c
@@ -0,0 +1,308 @@
+#include <openbsc/sip_client.h>
+#include <openbsc/reg_proxy.h>
+#include <openbsc/sup.h>
+#include <osip2/osip.h>
+
+
+#define MESSAGE_MAX_LENGTH 4000
+#define MAX_ADDR_STR 128
+#define MESSAGE_ENTRY_MAX_LENGTH 256
+#define SIP_URI_SCHEME "sip"
+#define SIP_VERSION "SIP/2.0"
+#define EXPIRES_TIME_INSECS 3600
+#define SIP_ALLOW "REGISTER, INVITE, INFO, ACK, CANCEL, BYE"
+
+
+
+
+int sip_send(struct sip_client *sip_client, osip_t *osip,
+             osip_message_t *msg, osip_fsm_type_t transaction_type)
+{
+	int status;
+	osip_transaction_t *transaction;
+	osip_event_t *sip_event;
+
+	status = osip_transaction_init(&transaction, transaction_type, osip, msg);
+	if (status) {
+		printf("Failed to init transaction %d",status);
+		return -1;
+	}
+
+	osip_transaction_set_your_instance(transaction, sip_client);
+
+	sip_event = osip_new_outgoing_sipmessage(msg);
+	if (!sip_event) {
+		printf("Can't allocate message");
+		osip_message_free(msg);
+		return -1;
+	}
+
+	sip_event->transactionid = transaction->transactionid;
+
+	status = osip_message_force_update(msg);
+
+	if (status) {
+		printf("Failed force update %d",status);
+		osip_message_free(msg);
+		return -1;
+	}
+	
+	status = osip_transaction_add_event(transaction, sip_event);
+
+	if (status) {
+		printf("Can't add event %d",status);
+		osip_message_free(msg);
+		return -1;
+	}
+
+	printf("Event added, waiting message to send ..... %d\n",status);
+
+	return 0;
+
+}
+
+int tx_sip_register(struct sip_client *sip_client, osip_t *osip, char *imsi)
+{
+	osip_message_t *reg_msg;
+
+	static int seq_num = 1;
+	char *call_id_num = NULL;
+	char *seq_num_str = NULL;
+	osip_call_id_t *call_id;
+	char tmp[MESSAGE_ENTRY_MAX_LENGTH];
+	osip_cseq_t *cseq;
+	char src_port[6];
+
+	if (osip_message_init(&reg_msg)) {
+		OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"Can't init message!\n"));
+		return -1;
+	}
+	osip_message_set_method(reg_msg, osip_strdup("REGISTER"));
+
+	/////
+	osip_uri_init(&(reg_msg->req_uri));
+	osip_uri_set_scheme(reg_msg->req_uri, SIP_URI_SCHEME);
+	osip_uri_set_host (reg_msg->req_uri, sip_client->dst_ip);
+	//if (osip_uri_parse(reg_msg->req_uri, SIP_SERVER)) {
+	//	OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"uri parse failed!\n"));
+	//	osip_message_free(reg_msg);
+	//	return -1;
+	//}
+	////////
+	osip_message_set_version(reg_msg, osip_strdup(SIP_VERSION));
+	//osip_message_set_status_code(reg_msg, 0);
+	//osip_message_set_reason_phrase(reg_msg, NULL);
+
+	sprintf(tmp, "<sip:%s@%s>", imsi, sip_client->dst_ip);
+	osip_message_set_to(reg_msg, tmp);
+	sprintf(tmp, "<sip:%s@%s>;tag=%u", imsi, sip_client->dst_ip, osip_build_random_number());
+	osip_message_set_from(reg_msg, tmp);
+
+	if (osip_call_id_init(&call_id)) {
+		OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"call id failed!\n"));
+		osip_message_free(reg_msg);
+		return -1;
+	}
+	call_id_num = (char *)osip_malloc(MAX_ADDR_STR);
+	sprintf(call_id_num, "%u", osip_build_random_number());
+	osip_call_id_set_number(call_id, call_id_num);
+	reg_msg->call_id = call_id;
+
+	if (osip_cseq_init(&cseq)) {
+		OSIP_TRACE(osip_trace(__FILE__,__LINE__,OSIP_BUG,NULL,"seq init failed!\n"));
+		osip_message_free(reg_msg);
+		return -1;
+	}
+
+	if (seq_num < (1<<30)) {
+		seq_num++;
+	}
+	else {
+		seq_num = 1;
+	}
+
+	seq_num_str = (char *)osip_malloc(11);
+	sprintf(seq_num_str,"%i", seq_num);
+	osip_cseq_set_number(cseq, seq_num_str);
+	osip_cseq_set_method(cseq, osip_strdup("REGISTER"));
+	reg_msg->cseq = cseq;
+
+	osip_message_set_max_forwards(reg_msg, "70");
+
+	sprintf(src_port, "%u", sip_client->src_port);
+	sprintf(tmp, "SIP/2.0/%s %s:%s;branch=z9hG4bK%u", "TCP", sip_client->src_ip,
+                                          src_port, osip_build_random_number());
+	osip_message_set_via(reg_msg, tmp);
+
+	sprintf(tmp, "<sip:%s@%s:%s>", imsi, sip_client->src_ip, src_port);
+	osip_message_set_contact(reg_msg, tmp);
+
+	sprintf(tmp, "%i", EXPIRES_TIME_INSECS);
+	osip_message_set_expires(reg_msg, tmp);
+
+	osip_message_set_content_length(reg_msg, "0");
+
+	osip_message_set_allow(reg_msg, SIP_ALLOW);
+
+	printf("REG message ready, try to send\n");
+
+	if (sip_send(sip_client, osip, reg_msg, NICT)) {
+		printf("Error sending message!");
+		return -1;
+	}
+
+	return 0;
+}
+
+int rx_sip_message(struct sip_client *sip_client, struct msgb *msg)
+{
+	char sip_msg[MESSAGE_MAX_LENGTH];
+	osip_event_t *sipevent;
+	struct reg_proxy *reg = sip_client->data;
+
+	printf("processSipMsg: RECEIVED MSG\n");
+	strncpy(sip_msg, (char*)msg->data,msg->data_len);
+	printf("processSipMsg: sip_msg = %s\n", sip_msg);
+
+	sipevent= osip_parse(sip_msg,msg->data_len);
+	if((sipevent==NULL)||(sipevent->sip==NULL)) {
+		printf("Could not parse SIP message\n");
+		osip_event_free(sipevent);
+		return -1;
+	}
+
+	if (osip_find_transaction_and_add_event(reg->osip,sipevent)) {
+		printf("New transaction!\n");
+		if (MSG_IS_REQUEST(sipevent->sip)) {
+			printf("Got New Request:%s\n",sip_msg);
+		} else if (MSG_IS_RESPONSE(sipevent->sip)) {
+			printf("Got New Response:%s\n",sip_msg);
+		} else {
+			printf("Unsupported message:%s\n",sip_msg);
+			osip_event_free(sipevent);
+		}
+	}
+	return 0;
+}
+
+static int sip_read_cb(struct sip_client *sip_client, struct msgb *msg)
+{
+	int rc;
+	rc = rx_sip_message(sip_client, msg);
+	msgb_free(msg);
+	return rc;
+}
+
+
+int sip_cb_send(osip_transaction_t *tr, osip_message_t *sip_msg, char *host, int port, int out_socket)
+{
+
+	size_t msg_len;
+	char *msg_p;
+	struct msgb *msg = sip_msgb_alloc();
+
+	struct sip_client *sip_client = osip_transaction_get_your_instance(tr);
+	printf("SIP Send Msg\n");
+	
+	if(osip_message_to_str(sip_msg, &msg_p, &msg_len) != 0){
+		printf("SIP failed to convert message\n");
+		return -1;
+	}
+	printf("SIP convert message ok\n");
+
+	if (!msg_p) {
+		printf("SIP msg_p = NULL fail!\n");
+		return -1;
+	}
+
+	printf("SIP msg_p != NULL OK!, msg_len = %d\n", msg_len);
+	memcpy(msg->data, (uint8_t*)msg_p, msg_len);
+	msg->data_len = msg_len;
+	msg->len += msg_len;
+	printf("SIP ready to send msg via IPA\n");
+	return sip_client_send(sip_client, msg);
+}
+
+
+void sip_cb_rcv1xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
+{
+	printf("OSIP_NICT_STATUS_1XX_RECEIVED\n");
+}
+
+void sip_cb_rcv2xx(int type, osip_transaction_t *tr, osip_message_t *sip_msg)
+{
+	printf("OSIP_NICT_STATUS_2XX_RECEIVED\n");
+	osip_contact_t *contact;
+	osip_to_t* to;
+	struct sip_client *sip_client = osip_transaction_get_your_instance(tr);
+	struct reg_proxy *reg = sip_client->data;
+	char imsi[17];
+	char msisdn[15];
+	osip_message_get_contact(sip_msg, 0, &contact);
+	memcpy(msisdn, contact->url->username, 15);
+	
+	to = osip_message_get_to(sip_msg);
+	memcpy(imsi, to->url->username, 17);
+
+	printf("OSIP_NICT_STATUS_2XX_RECEIVED imsi = %s \n", imsi);
+	printf("OSIP_NICT_STATUS_2XX_RECEIVED msisdn = %d \n", msisdn);
+	printf("OSIP_NICT_STATUS_2XX_RECEIVED msisdn = %s \n", msisdn);
+
+
+	handle_location_update_result(reg->sup_server, imsi, msisdn);
+
+}
+
+void sip_cb_rcv2xx_again(int type, osip_transaction_t *pott,osip_message_t *pomt)
+{
+	printf("OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN\n");
+}
+
+void sip_cb_rcv3xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
+{
+	printf("OSIP_NICT_STATUS_3XX_RECEIVED\n");
+}
+
+void sip_cb_rcv4xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
+{
+	printf("OSIP_NICT_STATUS_4XX_RECEIVED\n");
+}
+void sip_cb_rcv5xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
+{
+	printf("OSIP_NICT_STATUS_5XX_RECEIVED\n");
+}
+void sip_cb_rcv6xx(int type, osip_transaction_t *pott,osip_message_t *pomt)
+{
+	printf("OSIP_NICT_STATUS_6XX_RECEIVED\n");
+}
+
+
+void sip_set_cbs(osip_t *osip)
+{
+	osip_set_cb_send_message(osip, sip_cb_send);
+	osip_set_message_callback (osip, OSIP_NICT_STATUS_1XX_RECEIVED, sip_cb_rcv1xx);
+	osip_set_message_callback (osip, OSIP_NICT_STATUS_2XX_RECEIVED, sip_cb_rcv2xx);
+	osip_set_message_callback (osip, OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN, sip_cb_rcv2xx_again);
+	osip_set_message_callback (osip, OSIP_NICT_STATUS_3XX_RECEIVED, sip_cb_rcv3xx);
+	osip_set_message_callback (osip, OSIP_NICT_STATUS_4XX_RECEIVED, sip_cb_rcv4xx);
+	osip_set_message_callback (osip, OSIP_NICT_STATUS_5XX_RECEIVED, sip_cb_rcv5xx);
+	osip_set_message_callback (osip, OSIP_NICT_STATUS_6XX_RECEIVED, sip_cb_rcv6xx);
+}
+
+
+int sip_client_init(struct reg_proxy *reg, const char *src_ip, u_int16_t src_port,
+                                           const char *dst_ip, u_int16_t dst_port)
+{
+
+	reg->sip_client = sip_client_create(src_ip, src_port, dst_ip, dst_port,
+                                                        &sip_read_cb, reg);
+	if (!reg->sip_client)
+		return -1;
+
+	if (osip_init(&reg->osip)!=0)
+		return -1;
+
+	sip_set_cbs(reg->osip);
+
+	return 1;
+}
diff --git a/openbsc/src/reg-proxy/sip_client.c b/openbsc/src/reg-proxy/sip_client.c
new file mode 100644
index 0000000..c470fa0
--- /dev/null
+++ b/openbsc/src/reg-proxy/sip_client.c
@@ -0,0 +1,273 @@
+#include <openbsc/reg_proxy.h>
+#include <openbsc/sip_client.h>
+
+//#include <osmocom/abis/ipa.h>
+//#include <osmocom/gsm/protocol/ipaccess.h>
+#include <osmocom/core/msgb.h>
+
+#include <openbsc/debug.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+
+#include <openbsc/tcp_client.h>
+
+//extern void *tall_reg_ctx;
+
+//static void start_test_procedure(struct gprs_gsup_client *gsupc);
+
+/*
+static void gsup_client_send_ping(struct gprs_gsup_client *gsupc)
+{
+	struct msgb *msg = gprs_gsup_msgb_alloc();
+
+	msg->l2h = msgb_put(msg, 1);
+	msg->l2h[0] = IPAC_MSGT_PING;
+	ipa_msg_push_header(msg, IPAC_PROTO_IPACCESS);
+	ipa_client_conn_send(gsupc->link, msg);
+}
+*/
+
+static int sip_client_connect(struct sip_client *sip_client)
+{
+	int rc;
+
+	if (sip_client->is_connected)
+		return 0;
+
+	if (osmo_timer_pending(&sip_client->connect_timer)) {
+		LOGP(DSUP, LOGL_DEBUG,
+		     "SIP connect: connect timer already running\n");
+		osmo_timer_del(&sip_client->connect_timer);
+	}
+
+	if (tcp_client_conn_clear_queue(sip_client->link) > 0)
+		LOGP(DSUP, LOGL_DEBUG, "SIP connect: discarded stored messages\n");
+
+	rc = tcp_client_conn_open(sip_client->link);
+
+	if (rc >= 0) {
+		LOGP(DSUP, LOGL_INFO, "SIP connecting to %s:%d\n",
+		     sip_client->link->dst_addr, sip_client->link->dst_port);
+		return 0;
+	}
+
+	LOGP(DSUP, LOGL_INFO, "SIP failed to connect to %s:%d: %s\n",
+	     sip_client->link->dst_addr, sip_client->link->dst_port, strerror(-rc));
+
+	if (rc == -EBADF || rc == -ENOTSOCK || rc == -EAFNOSUPPORT ||
+	    rc == -EINVAL)
+		return rc;
+
+	osmo_timer_schedule(&sip_client->connect_timer, SIP_RECONNECT_INTERVAL, 0);
+
+	LOGP(DSUP, LOGL_INFO, "Scheduled timer to retry SIP connect to %s:%d\n",
+	     sip_client->link->dst_addr, sip_client->link->dst_port);
+
+	return 0;
+}
+
+static void connect_timer_cb(void *sip_client_)
+{
+	struct sip_client *sip_client = sip_client_;
+
+	if (sip_client->is_connected)
+		return;
+
+	sip_client_connect(sip_client);
+}
+
+static void sip_client_updown_cb(struct tcp_client_conn *link, int up)
+{
+	struct sip_client *sip_client = link->data;
+
+	LOGP(DSUP, LOGL_INFO, "SIP link to %s:%d %s\n",
+		     link->dst_addr, link->dst_port, up ? "UP" : "DOWN");
+
+	sip_client->is_connected = up;
+
+	if (up) {
+		osmo_timer_del(&sip_client->connect_timer);
+	} else {
+		osmo_timer_schedule(&sip_client->connect_timer,
+				    SIP_RECONNECT_INTERVAL, 0);
+	}
+}
+
+static int sip_client_read_cb(struct tcp_client_conn *link, struct msgb *msg)
+{
+	//struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
+	//struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg);
+	printf("Recv sip message! len = %d\n", msg->data_len);
+    struct sip_client *sip_client = (struct sip_client *)link->data;
+	//int rc;
+
+	//msg->l2h = &hh->data[0];
+
+    OSMO_ASSERT(sip_client->read_cb != NULL);
+    sip_client->read_cb(sip_client, msg);
+
+	/* Not freeing msg here, because that must be done by the read_cb. */
+	return 0;
+}
+
+/*
+static void ping_timer_cb(void *gsupc_)
+{
+	struct gprs_gsup_client *gsupc = gsupc_;
+
+	LOGP(DGPRS, LOGL_INFO, "GSUP ping callback (%s, %s PONG)\n",
+	     gsupc->is_connected ? "connected" : "not connected",
+	     gsupc->got_ipa_pong ? "got" : "didn't get");
+
+	if (gsupc->got_ipa_pong) {
+		start_test_procedure(gsupc);
+		return;
+	}
+
+	LOGP(DGPRS, LOGL_NOTICE, "GSUP ping timed out, reconnecting\n");
+	ipa_client_conn_close(gsupc->link);
+	gsupc->is_connected = 0;
+
+	gsup_client_connect(gsupc);
+}
+*/
+/*
+static void start_test_procedure(struct gprs_gsup_client *gsupc)
+{
+	gsupc->ping_timer.data = gsupc;
+	gsupc->ping_timer.cb = &ping_timer_cb;
+
+	gsupc->got_ipa_pong = 0;
+	osmo_timer_schedule(&gsupc->ping_timer, GPRS_GSUP_PING_INTERVAL, 0);
+	LOGP(DGPRS, LOGL_DEBUG, "GSUP sending PING\n");
+	gsup_client_send_ping(gsupc);
+}
+*/
+/*
+int ipa_client_write_cb(struct ipa_client_conn *link)
+{
+	struct osmo_fd *ofd = link->ofd;
+	struct msgb *msg;
+	struct llist_head *lh;
+	int ret;
+
+	LOGP(DLINP, LOGL_DEBUG, "sending data\n");
+
+
+	if (llist_empty(&link->tx_queue)) {
+		ofd->when &= ~BSC_FD_WRITE;
+		return 0;
+	}
+	lh = link->tx_queue.next;
+	llist_del(lh);
+	msg = llist_entry(lh, struct msgb, list);
+
+	printf("ipa_client_write_cb sending data... msg->len= %d\n",  msg->len);
+
+	ret = send(link->ofd->fd, msg->data, msg->len, 0);
+	if (ret < 0) {
+		if (errno == EPIPE || errno == ENOTCONN) {
+			ipa_client_conn_close(link);
+			if (link->updown_cb)
+				link->updown_cb(link, 0);
+		}
+		LOGP(DLINP, LOGL_ERROR, "error to send\n");
+		printf("ipa_client_write_cb error to send!!!! ret = %d errno = %d\n", ret, errno);
+	}
+	msgb_free(msg);
+	printf("ipa_client_write_cb send OK ret = %d\n", ret);
+	return 0;
+}
+*/
+struct sip_client *sip_client_create(const char *src_ip, u_int16_t src_port,
+                                     const char *dst_ip, u_int16_t dst_port,
+                                          sip_read_cb_t read_cb, void *data)
+{
+	struct sip_client *sip_client;
+	int rc;
+
+	sip_client = talloc_zero(tall_reg_ctx, struct sip_client);
+	OSMO_ASSERT(sip_client);
+
+	sip_client->link = tcp_client_conn_create(sip_client,
+					     0,
+					     dst_ip, dst_port,
+					     src_ip, src_port,
+					     sip_client_updown_cb,
+					     sip_client_read_cb,
+					     NULL,
+					     sip_client);
+	if (!sip_client->link)
+		goto failed;
+
+	sip_client->connect_timer.data = sip_client;
+	sip_client->connect_timer.cb = &connect_timer_cb;
+	sip_client->dst_ip = dst_ip;
+	sip_client->src_ip = src_ip;
+	sip_client->dst_port = dst_port;
+	sip_client->src_port = src_port;
+
+	rc = sip_client_connect(sip_client);
+
+	if (rc < 0)
+		goto failed;
+
+	sip_client->read_cb = read_cb;
+	sip_client->data = data;
+
+	return sip_client;
+
+failed:
+	sip_client_destroy(sip_client);
+	return NULL;
+}
+
+void sip_client_destroy(struct sip_client *sip_client)
+{
+	osmo_timer_del(&sip_client->connect_timer);
+
+	if (sip_client->link) {
+		tcp_client_conn_close(sip_client->link);
+		tcp_client_conn_destroy(sip_client->link);
+		sip_client->link = NULL;
+	}
+	talloc_free(sip_client);
+}
+
+int sip_client_send(struct sip_client *sip_client, struct msgb *msg)
+{
+	if (!sip_client) {
+		msgb_free(msg);
+		return -ENOTCONN;
+	}
+
+	if (!sip_client->is_connected) {
+		msgb_free(msg);
+		return -EAGAIN;
+	}
+
+	//ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_GSUP);
+	//ipa_msg_push_header(msg, IPAC_PROTO_OSMO);
+	printf(" TRY tcp_client_conn_send\n");
+
+	tcp_client_conn_send(sip_client->link, msg);
+	
+	printf(" DONE tcp_client_conn_send\n");
+
+	return 0;
+}
+
+struct msgb *sip_msgb_alloc(void)
+{
+	return msgb_alloc_headroom(400000, 64, __func__);
+}
diff --git a/openbsc/src/reg-proxy/sup.c b/openbsc/src/reg-proxy/sup.c
new file mode 100644
index 0000000..de08d94
--- /dev/null
+++ b/openbsc/src/reg-proxy/sup.c
@@ -0,0 +1,168 @@
+#include <openbsc/sup_server.h>
+#include <openbsc/reg_proxy.h>
+#include <openbsc/debug.h>
+#include <openbsc/gprs_gsup_messages.h>
+#include <openbsc/sip.h>
+#include <openbsc/sup.h>
+
+static int handle_sup_upd_loc_req(struct gsm_sup_server *sup_server,
+									struct gprs_gsup_message *sup_msg)
+{
+	int rc = 0;
+	struct reg_proxy *reg = sup_server->app;
+	struct sip_client *sip_client = reg->sip_client;
+	osip_t *osip = reg->osip;
+	LOGGSUPP(LOGL_INFO, sup_msg,
+		"Try to send sip_register 0x%02x\n", sup_msg->message_type);
+	rc = tx_sip_register(sip_client, osip, sup_msg->imsi);
+	LOGGSUPP(LOGL_INFO, sup_msg,
+		"Sip_register was send 0x%02x\n", sup_msg->message_type);
+	return rc;
+}
+
+int rx_sup_message(struct gsm_sup_server *sup_server, struct msgb *msg)
+{
+	uint8_t *data = msgb_l2(msg);
+	size_t data_len = msgb_l2len(msg);
+	int rc = 0;
+
+	struct gprs_gsup_message sup_msg = {0};
+	//struct gsm_subscriber *subscr;
+
+	rc = gprs_gsup_decode(data, data_len, &sup_msg);
+	if (rc < 0) {
+		LOGP(DSUP, LOGL_ERROR,
+		     "decoding SUP message fails with error '%s' (%d)\n",
+		     get_value_string(gsm48_gmm_cause_names, -rc), -rc);
+		return rc;
+	}
+
+	if (!sup_msg.imsi[0]) {
+		LOGP(DSUP, LOGL_ERROR, "Missing IMSI in SUP message\n");
+
+//		if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
+//			subscr_tx_sup_error_reply(sup_client, NULL, &gsup_msg,
+//							GMM_CAUSE_INV_MAND_INFO);
+		return -GMM_CAUSE_INV_MAND_INFO;
+	}
+
+//	if (!gsup_msg.cause && GPRS_GSUP_IS_MSGT_ERROR(gsup_msg.message_type))
+//		gsup_msg.cause = GMM_CAUSE_NET_FAIL;
+
+//	subscr = subscr_get_by_imsi(NULL, gsup_msg.imsi);
+
+//	if (!subscr) {
+//		return subscr_handle_unknown_imsi(sup_client, &gsup_msg);
+//	}
+
+	LOGGSUPP(LOGL_INFO, &sup_msg,
+		"Received SUP message of type 0x%02x\n", sup_msg.message_type);
+
+	switch (sup_msg.message_type) {
+	case GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST:
+		rc = handle_sup_upd_loc_req(sup_server, &sup_msg);
+		break;
+
+	case GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
+		//FIXME!!!!
+		//rc = subscr_handle_sup_auth_req(sup_server, &sup_msg);
+		rc = handle_sup_upd_loc_req(sup_server, &sup_msg);
+		break;
+		
+	case GPRS_GSUP_MSGT_LOCATION_CANCEL_ERROR:
+	case GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT:
+	case GPRS_GSUP_MSGT_PURGE_MS_REQUEST:
+	case GPRS_GSUP_MSGT_INSERT_DATA_ERROR:
+	case GPRS_GSUP_MSGT_INSERT_DATA_RESULT:
+		LOGGSUPP(LOGL_ERROR, &sup_msg,
+			"Rx SUP message type %d not yet implemented\n",
+			sup_msg.message_type);
+		//tx_sup_error_reply(sup_server, &sup_msg,
+		//				GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
+		rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
+		break;
+
+	default:
+		LOGGSUPP(LOGL_ERROR, &sup_msg,
+			"Rx SUP message type %d not valid\n",
+			sup_msg.message_type);
+		rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
+		break;
+	};
+
+	//subscr_put(subscr);
+
+	return
+	
+	
+	 rc;
+}
+
+static int tx_sup_message(struct gsm_sup_server *sup_server,
+								 struct gprs_gsup_message *sup_msg)
+{
+	struct msgb *msg = gprs_gsup_msgb_alloc();
+	printf("tx_sup_message \n");
+
+	gprs_gsup_encode(msg, sup_msg);
+	
+	printf("tx_sup_message encoded\n");
+
+
+	LOGGSUPP(LOGL_INFO, sup_msg,
+		    "Sending SUP, will send: %s\n", msgb_hexdump(msg));
+
+	if (!sup_server) {
+		msgb_free(msg);
+		return -ENOTSUP;
+	}
+	printf("tx_sup_message lets try to send\n");
+	return sup_server_send(sup_server, msg);
+}
+
+int handle_location_update_result(struct gsm_sup_server *sup_server,
+								 char *imsi, char *msisdn)
+{
+	struct gprs_gsup_message gsup_msg = {0};
+	u_int8_t msisdn_enc[9];
+
+	gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT;
+	printf("handle_location_update_result 1\n");
+
+	memcpy(gsup_msg.imsi, imsi, 17);
+	printf("handle_location_update_result %d  len = %d 2\n", gsup_msg.msisdn_enc, strlen(msisdn));
+
+	gsm48_encode_bcd_number(msisdn_enc, 9, 0, msisdn);
+	gsup_msg.msisdn_enc = msisdn_enc + 1;
+	gsup_msg.msisdn_enc_len = msisdn_enc[0];
+	printf("handle_location_update_result %d %d\n", gsup_msg.msisdn_enc_len, gsup_msg.msisdn_enc);
+	return tx_sup_message(sup_server, &gsup_msg);
+}
+
+static int sup_read_cb(struct gsm_sup_server *sup_server, struct msgb *msg)
+{
+	int rc;
+
+	printf("Got message from nitb!\n");
+
+	rc = rx_sup_message(sup_server, msg);
+	msgb_free(msg);
+	if (rc < 0)
+		return -1;
+
+	return rc;
+}
+
+int sup_server_init(struct reg_proxy *reg)
+{
+	const char *addr_str;
+
+	addr_str = "127.0.0.1";
+
+	reg->sup_server = sup_server_create(addr_str, 8183, &sup_read_cb, reg);
+
+	if (!reg->sup_server)
+		return -1;
+
+	return 1;
+}
diff --git a/openbsc/src/reg-proxy/sup_server.c b/openbsc/src/reg-proxy/sup_server.c
new file mode 100644
index 0000000..0bc1fc1
--- /dev/null
+++ b/openbsc/src/reg-proxy/sup_server.c
@@ -0,0 +1,163 @@
+/* GSM Subscriber Update Protocol server */
+
+/* (C) 2015 by Ivan Klyuchnikov <kluchnikovi@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/abis/ipa.h>
+#include <osmocom/gsm/protocol/ipaccess.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/utils.h>
+
+#include <openbsc/debug.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openbsc/sup_server.h>
+#include <openbsc/reg_proxy.h>
+
+static int ipa_sock_server_cb(struct ipa_server_conn *conn, struct msgb *msg)
+{
+	struct gsm_sup_server *sup_server = conn->data;
+	struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
+	struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg);
+	int ret;
+
+	msg->l2h = &hh->data[0];	/* Handle IPA PING, PONG and ID_ACK messages. */
+	ret = ipa_ccm_rcvmsg_base(msg, &conn->ofd);
+	switch(ret) {
+	case -1:
+		/* error in IPA control message handling */
+		goto invalid;
+	case 1:
+		/* this is an IPA control message, skip further processing */
+		return 0;
+	case 0:
+		/* this is not an IPA control message, continue */
+		break;
+	default:
+		LOGP(DSUP, LOGL_ERROR, "Unexpected return from "
+					"ipa_ccm_rcvmsg_base "
+					"(ret=%d)\n", ret);
+		goto invalid;
+	}
+
+	if (hh->proto != IPAC_PROTO_OSMO)
+		goto invalid;
+
+	if (!he || msgb_l2len(msg) < sizeof(*he) ||
+	    he->proto != IPAC_PROTO_EXT_GSUP)
+		goto invalid;
+
+	msg->l2h = &he->data[0];
+
+	OSMO_ASSERT(sup_server->read_cb != NULL);
+	sup_server->read_cb(sup_server, msg);
+
+	/* Not freeing msg here, because that must be done by the read_cb. */
+	return 0;
+
+invalid:
+	LOGP(DSUP, LOGL_NOTICE,
+	     "SUP received an invalid IPA message from %s:%d, size = %d\n",
+	     sup_server->link->addr, sup_server->link->port, msgb_length(msg));
+
+	msgb_free(msg);
+	return -1;
+
+}
+
+static int sup_accept_cb(struct ipa_server_link *link, int fd)
+{
+	struct gsm_sup_server *sup_server = link->data;
+	struct ipa_server_conn *server_conn;
+
+
+	server_conn = talloc_zero(tall_reg_ctx, struct ipa_server_conn);
+	if (server_conn == NULL) {
+		LOGP(DSUP, LOGL_ERROR, "cannot allocate memory for "
+				       "origin IPA\n");
+		close(fd);
+		return -ENOMEM;
+	}
+
+	server_conn = ipa_server_conn_create(tall_reg_ctx, link, fd,
+					   ipa_sock_server_cb, NULL, sup_server);
+	if (server_conn == NULL) {
+		LOGP(DSUP, LOGL_ERROR, "could not create server peer: %s\n",
+			strerror(errno));
+		return -ENOMEM;
+	}
+	sup_server->server_conn = server_conn;
+	return 0;
+}
+
+
+struct gsm_sup_server *sup_server_create(const char *ip_addr,
+						 unsigned int tcp_port,
+						 sup_read_cb_t read_cb,
+						 void *app)
+{
+	struct gsm_sup_server *sup_server;
+
+	sup_server = talloc_zero(tall_reg_ctx, struct gsm_sup_server);
+	OSMO_ASSERT(sup_server);
+
+	sup_server->app = app;
+	sup_server->read_cb = read_cb;
+	sup_server->link = ipa_server_link_create(tall_reg_ctx, NULL,
+					          ip_addr, tcp_port,
+						  sup_accept_cb, sup_server);
+	if (sup_server->link == NULL) {
+		LOGP(DSUP, LOGL_ERROR, "cannot create OML "
+			"BSC link: %s\n", strerror(errno));
+		return NULL;
+	}
+	if (ipa_server_link_open(sup_server->link) < 0) {
+		LOGP(DSUP, LOGL_ERROR, "cannot open OML BSC link: %s\n",
+			strerror(errno));
+		ipa_server_link_destroy(sup_server->link);
+		return NULL;
+	}
+	return sup_server;
+}
+
+int sup_server_send(struct gsm_sup_server *sup_server, struct msgb *msg)
+{
+	if (!sup_server) {
+		msgb_free(msg);
+		return -ENOTCONN;
+	}
+
+	if (!sup_server->link) {
+		msgb_free(msg);
+		return -EAGAIN;
+	}
+
+	ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_GSUP);
+	ipa_msg_push_header(msg, IPAC_PROTO_OSMO);
+	ipa_server_conn_send(sup_server->server_conn, msg);
+
+	return 0;
+}
+
+struct msgb *sup_msgb_alloc(void)
+{
+	return msgb_alloc_headroom(4000, 64, __func__);
+}
+
diff --git a/openbsc/src/reg-proxy/tcp_client.c b/openbsc/src/reg-proxy/tcp_client.c
new file mode 100644
index 0000000..c1e4b9b
--- /dev/null
+++ b/openbsc/src/reg-proxy/tcp_client.c
@@ -0,0 +1,303 @@
+//#include "internal.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <sys/types.h>
+#include <netdb.h>
+
+#include <osmocom/core/select.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/talloc.h>
+//#include <osmocom/abis/e1_input.h>
+//#include <osmocom/abis/ipaccess.h>
+//#include <osmocom/core/socket.h>
+#include <osmocom/core/backtrace.h>
+#include <openbsc/tcp_client.h>
+
+void tcp_client_conn_close(struct tcp_client_conn *link)
+{
+	/* be safe against multiple calls */
+	if (link->ofd->fd != -1) {
+		osmo_fd_unregister(link->ofd);
+		close(link->ofd->fd);
+		link->ofd->fd = -1;
+	}
+	msgb_free(link->pending_msg);
+	link->pending_msg = NULL;
+}
+
+static void tcp_client_read(struct tcp_client_conn *link)
+{
+	struct osmo_fd *ofd = link->ofd;
+	struct msgb *msg;
+	int ret;
+
+	LOGP(DLINP, LOGL_DEBUG, "message received\n");
+
+	// FIX 1500
+	msg = msgb_alloc(1500, "TCP");
+	if (!msg)
+		return;
+
+	printf("try to recv data msg->data = %d msg->data_len = %d \n", msg->data, msg->data_len);
+	ret = recv(ofd->fd, msg->data, msg->data_len, 0);
+	if (ret < 0) {
+		if (ret == -EAGAIN)
+			return;
+		if (ret == -EPIPE || ret == -ECONNRESET)
+			LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
+		tcp_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");
+		tcp_client_conn_close(link);
+		if (link->updown_cb)
+			link->updown_cb(link, 0);
+		return;
+	}
+	// TODO set len = ret
+	msg->data_len = ret;
+	printf("RECV SIP LEN = %d \n", ret);
+	if (link->read_cb)
+		link->read_cb(link, msg);
+}
+
+static void tcp_client_write(struct tcp_client_conn *link)
+{
+	if (link->write_cb)
+		link->write_cb(link);
+}
+
+static int tcp_client_write_default_cb(struct tcp_client_conn *link)
+{
+	struct osmo_fd *ofd = link->ofd;
+	struct msgb *msg;
+	struct llist_head *lh;
+	int ret;
+
+	LOGP(DLINP, LOGL_DEBUG, "sending data\n");
+
+	if (llist_empty(&link->tx_queue)) {
+		ofd->when &= ~BSC_FD_WRITE;
+		return 0;
+	}
+	lh = link->tx_queue.next;
+	llist_del(lh);
+	msg = llist_entry(lh, struct msgb, list);
+
+	ret = send(link->ofd->fd, msg->data, msg->len, 0);
+	if (ret < 0) {
+		if (errno == EPIPE || errno == ENOTCONN) {
+			tcp_client_conn_close(link);
+			if (link->updown_cb)
+				link->updown_cb(link, 0);
+		}
+		LOGP(DLINP, LOGL_ERROR, "error to send\n");
+	}
+	msgb_free(msg);
+	return 0;
+}
+
+static int tcp_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
+{
+	struct tcp_client_conn *link = ofd->data;
+	int error, ret;
+	socklen_t len = sizeof(error);
+
+	switch(link->state) {
+	case TCP_CLIENT_LINK_STATE_CONNECTING:
+		ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
+		if (ret >= 0 && error > 0) {
+			tcp_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 = TCP_CLIENT_LINK_STATE_CONNECTED;
+		if (link->updown_cb)
+			link->updown_cb(link, 1);
+		break;
+	case TCP_CLIENT_LINK_STATE_CONNECTED:
+		if (what & BSC_FD_READ) {
+			LOGP(DLINP, LOGL_DEBUG, "connected read\n");
+			tcp_client_read(link);
+		}
+		if (what & BSC_FD_WRITE) {
+			LOGP(DLINP, LOGL_DEBUG, "connected write\n");
+			tcp_client_write(link);
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+struct tcp_client_conn * tcp_client_conn_create(void *ctx, int priv_nr,
+		       const char *dst_addr, uint16_t dst_port,
+		       const char *src_addr, uint16_t src_port,
+		       void (*updown_cb)(struct tcp_client_conn *link, int up),
+		       int (*read_cb)(struct tcp_client_conn *link,
+				      struct msgb *msgb),
+		       int (*write_cb)(struct tcp_client_conn *link),
+		       void *data)
+{
+	struct tcp_client_conn *tcp_link;
+
+	tcp_link = talloc_zero(ctx, struct tcp_client_conn);
+	if (!tcp_link)
+		return NULL;
+
+	tcp_link->ofd = talloc_zero(ctx, struct osmo_fd);
+	if (tcp_link->ofd == NULL) {
+		talloc_free(tcp_link);
+		return NULL;
+	}
+
+	tcp_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
+	tcp_link->ofd->priv_nr = priv_nr;
+	tcp_link->ofd->cb = tcp_client_fd_cb;
+	tcp_link->ofd->data = tcp_link;
+	tcp_link->ofd->fd = -1;
+	tcp_link->state = TCP_CLIENT_LINK_STATE_CONNECTING;
+	tcp_link->src_addr = talloc_strdup(tcp_link, src_addr);
+	tcp_link->src_port = src_port;
+	tcp_link->dst_addr = talloc_strdup(tcp_link, dst_addr);
+	tcp_link->dst_port = dst_port;
+	tcp_link->updown_cb = updown_cb;
+	tcp_link->read_cb = read_cb;
+	/* default to generic write callback if not set. */
+	if (write_cb == NULL)
+		tcp_link->write_cb = tcp_client_write_default_cb;
+	else
+		tcp_link->write_cb = write_cb;
+
+	tcp_link->data = data;
+	INIT_LLIST_HEAD(&tcp_link->tx_queue);
+
+	return tcp_link;
+}
+
+void tcp_client_conn_destroy(struct tcp_client_conn *link)
+{
+	talloc_free(link);
+}
+
+int tcp_client_conn_open(struct tcp_client_conn *link)
+{
+	int ret;
+	struct addrinfo hints, *bind_addr, *connect_addr;
+	int sfd, rc, on = 1;
+	char src_port_buf[16];
+	char dst_port_buf[16];
+
+
+	link->state = TCP_CLIENT_LINK_STATE_CONNECTING;
+//	ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
+//			     link->addr, link->port,
+//			     OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
+			     
+	sprintf(src_port_buf, "%u", link->src_port);		     
+	sprintf(dst_port_buf, "%u", link->dst_port);		     
+
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_family = AF_INET;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_protocol = IPPROTO_TCP;
+
+	rc = getaddrinfo(link->dst_addr, dst_port_buf, &hints, &connect_addr);
+	if (rc != 0) {
+		perror("getaddrinfo returned NULL");
+		return -EINVAL;
+	}
+
+	hints.ai_flags |= AI_PASSIVE;
+
+	rc = getaddrinfo(link->src_addr, src_port_buf, &hints, &bind_addr);
+	if (rc != 0) {
+		perror("getaddrinfo returned NULL");
+		return -EINVAL;
+	}
+
+	sfd = socket(connect_addr->ai_family, connect_addr->ai_socktype, connect_addr->ai_protocol);
+	if (sfd < 0) {
+		perror("cannot create socket");
+        return sfd;
+	}
+	if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) {
+		perror("cannot set this socket unblocking");
+		close(sfd);
+		return -EINVAL;
+	}
+
+	rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+	if (rc < 0) {
+		perror("cannot setsockopt socket");
+		close(sfd);
+		return -EINVAL;
+	}
+
+	rc = bind(sfd, bind_addr->ai_addr, bind_addr->ai_addrlen);
+	if (rc < 0) {
+		perror("cannot bind socket");
+		close(sfd);
+		return -ENODEV;
+	}
+
+	rc = connect(sfd, connect_addr->ai_addr, connect_addr->ai_addrlen);
+	if (rc <0 && errno != EINPROGRESS) {
+		perror("cannot connect socket");
+		close(sfd);
+		return -ENODEV;
+	}
+
+	freeaddrinfo(bind_addr);
+	freeaddrinfo(connect_addr);
+
+	listen(sfd, 10);
+
+	link->ofd->fd = sfd;
+	link->ofd->when |= BSC_FD_WRITE;
+	if (osmo_fd_register(link->ofd) < 0) {
+		close(sfd);
+		link->ofd->fd = -1;
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void tcp_client_conn_send(struct tcp_client_conn *link, struct msgb *msg)
+{
+	msgb_enqueue(&link->tx_queue, msg);
+	link->ofd->when |= BSC_FD_WRITE;
+}
+
+size_t tcp_client_conn_clear_queue(struct tcp_client_conn *link)
+{
+	size_t deleted = 0;
+
+	while (!llist_empty(&link->tx_queue)) {
+		struct msgb *msg = msgb_dequeue(&link->tx_queue);
+		msgb_free(msg);
+		deleted += 1;
+	}
+
+	link->ofd->when &= ~BSC_FD_WRITE;
+	return deleted;
+}