summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Kluchnikov <kluchnikovi@gmail.com>2015-10-15 17:06:47 +0300
committerIvan Kluchnikov <kluchnikovi@gmail.com>2015-10-24 12:26:15 +0300
commit2a01e0411ad817e21e805d6e29696b111cbfa4a9 (patch)
tree36569715845dc1a4260ec5b428993b6bc320b7ff
parente4fd51d1fc92a27b3294f88c4853e0655e631d75 (diff)
reg-proxy: add application which allows translate SUP to SIP and SIP to SUP
-rw-r--r--openbsc/configure.ac1
-rw-r--r--openbsc/include/openbsc/gprs_gsup_messages.h2
-rw-r--r--openbsc/include/openbsc/reg_proxy.h15
-rw-r--r--openbsc/include/openbsc/sip.h12
-rw-r--r--openbsc/include/openbsc/sip_client.h34
-rw-r--r--openbsc/include/openbsc/sup.h16
-rw-r--r--openbsc/include/openbsc/sup_server.h29
-rw-r--r--openbsc/include/openbsc/tcp_client.h51
-rw-r--r--openbsc/src/Makefile.am2
-rw-r--r--openbsc/src/libmsc/gsm_04_08_gprs.c141
-rw-r--r--openbsc/src/reg-proxy/Makefile.am21
-rw-r--r--openbsc/src/reg-proxy/reg_proxy.c302
-rw-r--r--openbsc/src/reg-proxy/sip.c308
-rw-r--r--openbsc/src/reg-proxy/sip_client.c273
-rw-r--r--openbsc/src/reg-proxy/sup.c168
-rw-r--r--openbsc/src/reg-proxy/sup_server.c163
-rw-r--r--openbsc/src/reg-proxy/tcp_client.c303
17 files changed, 1839 insertions, 2 deletions
diff --git a/openbsc/configure.ac b/openbsc/configure.ac
index 394972f..d00b0ee 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -187,6 +187,7 @@ AC_OUTPUT(
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/gprs_gsup_messages.h b/openbsc/include/openbsc/gprs_gsup_messages.h
index 123e1fc..fb83b25 100644
--- a/openbsc/include/openbsc/gprs_gsup_messages.h
+++ b/openbsc/include/openbsc/gprs_gsup_messages.h
@@ -107,7 +107,7 @@ struct gprs_gsup_message {
size_t num_auth_tuples;
struct gprs_gsup_pdp_info pdp_infos[GPRS_GSUP_MAX_NUM_PDP_INFO];
size_t num_pdp_infos;
- const uint8_t *msisdn_enc;
+ uint8_t *msisdn_enc;
size_t msisdn_enc_len;
};
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 6f6174e..0de5cf0 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -2,7 +2,7 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS)
-SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs
+SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs reg-proxy
# Conditional modules
if BUILD_NAT
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;
+}