summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2012-06-23 21:58:41 +0200
committerHarald Welte <laforge@gnumonks.org>2012-06-23 21:58:41 +0200
commit7026b85b58b6cba1d14b37afda8ff2126f995655 (patch)
tree8c384d94d7f1edd3ecbebfbdc59d4d1a7ddc0327
parentedcba4e307fc6d8cf3de5d22982b1317178e7433 (diff)
initial skeleton for accepting UMA/GAN connections
-rw-r--r--openbsc/configure.ac1
-rw-r--r--openbsc/src/Makefile.am2
-rw-r--r--openbsc/src/osmo-ganc/Makefile.am11
-rw-r--r--openbsc/src/osmo-ganc/conn.c145
-rw-r--r--openbsc/src/osmo-ganc/conn.h44
-rw-r--r--openbsc/src/osmo-ganc/ganc_data.h12
-rw-r--r--openbsc/src/osmo-ganc/ganc_server.c151
-rw-r--r--openbsc/src/osmo-ganc/main.c232
8 files changed, 597 insertions, 1 deletions
diff --git a/openbsc/configure.ac b/openbsc/configure.ac
index 3f2d4d4..76a4835 100644
--- a/openbsc/configure.ac
+++ b/openbsc/configure.ac
@@ -127,6 +127,7 @@ AC_OUTPUT(
src/osmo-bsc/Makefile
src/osmo-bsc_nat/Makefile
src/osmo-bsc_mgcp/Makefile
+ src/osmo-ganc/Makefile
src/ipaccess/Makefile
src/utils/Makefile
src/gprs/Makefile
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index cf34c4c..852c442 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -9,5 +9,5 @@ if BUILD_NAT
SUBDIRS += osmo-bsc_nat
endif
if BUILD_BSC
-SUBDIRS += osmo-bsc
+SUBDIRS += osmo-bsc osmo-ganc
endif
diff --git a/openbsc/src/osmo-ganc/Makefile.am b/openbsc/src/osmo-ganc/Makefile.am
new file mode 100644
index 0000000..1b85451
--- /dev/null
+++ b/openbsc/src/osmo-ganc/Makefile.am
@@ -0,0 +1,11 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(COVERAGE_CFLAGS)
+AM_LDFLAGS = $(COVERAGE_LDFLAGS)
+
+bin_PROGRAMS = osmo-ganc
+
+osmo_ganc_SOURCES = conn.c ganc_server.c main.c
+
+osmo_ganc_LDADD = $(top_builddir)/src/libcommon/libcommon.a \
+ $(LIBOSMOSCCP_LIBS) $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(COVERAGE_LDFLAGS)
diff --git a/openbsc/src/osmo-ganc/conn.c b/openbsc/src/osmo-ganc/conn.c
new file mode 100644
index 0000000..1c25275
--- /dev/null
+++ b/openbsc/src/osmo-ganc/conn.c
@@ -0,0 +1,145 @@
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/write_queue.h>
+
+#include "conn.h"
+
+
+static int slave_read_cb(struct osmo_fd *ofd)
+{
+ struct osmo_conn *conn = ofd->data;
+
+ return conn->link->slave_read_cb(conn);
+}
+
+static int slave_write_cb(struct osmo_fd *ofd, struct msgb *msg)
+{
+ int rc;
+
+ rc = send(ofd->fd, msg->data, msg->len, 0);
+ if (rc < 0) {
+ LOGP(DLINP, LOGL_ERROR, "error %d on send()\n", rc);
+ }
+
+ return rc;
+}
+
+static int server_fd_cb(struct osmo_fd *ofd, unsigned int what)
+{
+ int rc;
+ struct sockaddr_in sa;
+ socklen_t sa_len = sizeof(sa);
+ struct osmo_link *link = ofd->data;
+ struct osmo_conn *conn;
+
+ rc = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
+ if (rc < 0)
+ return rc;
+
+ conn = talloc_zero(link, struct osmo_conn);
+ if (!conn) {
+ close(rc);
+ return -ENOMEM;
+ }
+
+ conn->link = link;
+ osmo_wqueue_init(&conn->queue, link->slave_max_qlen);
+ conn->queue.read_cb = slave_read_cb;
+ conn->queue.write_cb = slave_write_cb;
+
+ conn->queue.bfd.when = BSC_FD_READ | BSC_FD_WRITE;
+ conn->queue.bfd.data = conn;
+
+ conn->remote.host = talloc_strdup(conn, inet_ntoa(sa.sin_addr));
+ conn->remote.port = ntohs(sa.sin_port);
+
+ llist_add_tail(&conn->list, &link->conns);
+
+ LOGP(DLINP, LOGL_NOTICE, "accept()ed new UNC link from %s:%u to port %u\n",
+ conn->remote.host, conn->remote.port, link->port);
+
+ if (link->accept_cb)
+ link->accept_cb(conn);
+
+ return 0;
+}
+
+struct osmo_link *osmo_link_create(void *ctx, const char *addr, uint16_t port,
+ int (*read_cb)(struct osmo_conn *),
+ int slave_max_qlen)
+{
+ struct osmo_link *link;
+
+ link = talloc_zero(ctx, struct osmo_link);
+ if (!link)
+ return NULL;
+
+ link->ofd.when = BSC_FD_READ | BSC_FD_WRITE;
+ link->ofd.cb = server_fd_cb;
+ link->ofd.data = link;
+ link->addr = talloc_strdup(link, addr);
+ link->port = port;
+ link->slave_read_cb = read_cb;
+ link->slave_max_qlen = slave_max_qlen;
+ INIT_LLIST_HEAD(&link->conns);
+
+ return link;
+}
+
+
+int osmo_link_listen(struct osmo_link *link,
+ void (*accept_cb)(struct osmo_conn *))
+{
+ int rc;
+
+ rc = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
+ link->addr, link->port, OSMO_SOCK_F_BIND);
+
+ link->ofd.fd = rc;
+
+ if (osmo_fd_register(&link->ofd) < 0) {
+ close(rc);
+ return -EIO;
+ }
+ link->accept_cb = accept_cb;
+
+ return 0;
+}
+
+int osmo_conn_enqueue(struct osmo_conn *conn, struct msgb *msg)
+{
+ return osmo_wqueue_enqueue(&conn->queue, msg);
+}
+
+void osmo_conn_close(struct osmo_conn *conn)
+{
+ close(conn->queue.bfd.fd);
+ osmo_wqueue_clear(&conn->queue);
+ llist_del(&conn->list);
+
+ talloc_free(conn);
+}
+
+int osmo_link_close(struct osmo_link *link)
+{
+ struct osmo_conn *conn, *conn2;
+
+ osmo_fd_unregister(&link->ofd);
+ close(link->ofd.fd);
+
+ llist_for_each_entry_safe(conn, conn2, &link->conns, list)
+ osmo_conn_close(conn);
+
+ return 0;
+}
diff --git a/openbsc/src/osmo-ganc/conn.h b/openbsc/src/osmo-ganc/conn.h
new file mode 100644
index 0000000..3e00c45
--- /dev/null
+++ b/openbsc/src/osmo-ganc/conn.h
@@ -0,0 +1,44 @@
+#ifndef _OSMO_CONN_H
+#define _OSMO_CONN_H
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/write_queue.h>
+
+struct osmo_conn;
+
+struct osmo_link {
+ struct llist_head list;
+ struct osmo_fd ofd;
+ const char *addr;
+ uint16_t port;
+ struct llist_head conns;
+ int slave_max_qlen;
+
+ void (*accept_cb)(struct osmo_conn *conn);
+ int (*slave_read_cb)(struct osmo_conn *conn);
+};
+
+struct osmo_conn {
+ struct llist_head list;
+ struct osmo_link *link;
+ struct osmo_wqueue queue;
+ struct {
+ const char *host;
+ uint16_t port;
+ } remote;
+ void *priv;
+};
+
+int osmo_conn_enqueue(struct osmo_conn *conn, struct msgb *msg);
+void osmo_conn_close(struct osmo_conn *conn);
+
+struct osmo_link *osmo_link_create(void *ctx, const char *addr, uint16_t port,
+ int (*read_cb)(struct osmo_conn *),
+ int slave_max_qlen);
+int osmo_link_listen(struct osmo_link *link,
+ void (*accept_cb)(struct osmo_conn *));
+int osmo_link_close(struct osmo_link *link);
+
+#endif
diff --git a/openbsc/src/osmo-ganc/ganc_data.h b/openbsc/src/osmo-ganc/ganc_data.h
new file mode 100644
index 0000000..f67969c
--- /dev/null
+++ b/openbsc/src/osmo-ganc/ganc_data.h
@@ -0,0 +1,12 @@
+#ifndef _GANC_DATA_H
+#define _GANC_DATA_H
+
+#include <osmocom/core/linuxlist.h>
+#include "conn.h"
+
+struct gan_peer {
+ struct llist_head list;
+ struct osmo_conn *conn;
+};
+
+#endif
diff --git a/openbsc/src/osmo-ganc/ganc_server.c b/openbsc/src/osmo-ganc/ganc_server.c
new file mode 100644
index 0000000..b8153c9
--- /dev/null
+++ b/openbsc/src/osmo-ganc/ganc_server.c
@@ -0,0 +1,151 @@
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+
+#include <osmocom/core/socket.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/protocol/gsm_44_318.h>
+
+#include "conn.h"
+#include "ganc_data.h"
+
+static struct msgb *unc_msgb_alloc(void)
+{
+ return msgb_alloc_headroom(1024+128, 128, "GANC Tx");
+}
+
+static int unc_peer_tx(struct gan_peer *peer, struct msgb *msg)
+{
+ return osmo_conn_enqueue(peer->conn, msg);
+}
+
+static int tx_unc_disco_acc(struct gan_peer *peer, const char *segw_host,
+ const char *ganc_host)
+{
+ struct msgb *msg = unc_msgb_alloc();
+ struct gan_rc_csr_hdr *gh = (struct gan_rc_csr_hdr*) msg->l2h;
+
+ if (!msg)
+ return -ENOMEM;
+
+ gh->pdisc = GA_PDISC_RC;
+ gh->msg_type = GA_MT_RC_DISCOVERY_ACCEPT;
+
+ msgb_tlv_put(msg, GA_IE_DEF_SEGW_FQDN, strlen(segw_host)+1, (uint8_t *) segw_host);
+ msgb_tlv_put(msg, GA_IE_DEF_GANC_FQDN, strlen(ganc_host)+1, (uint8_t *) ganc_host);
+
+ return unc_peer_tx(peer, msg);
+}
+
+static int rx_unc_discovery_req(struct gan_peer *peer, struct msgb *msg,
+ struct gan_rc_csr_hdr *gh)
+{
+ struct tlv_parsed tp;
+
+ tlv_parse(&tp, &tvlv_att_def, gh->data, msg->len - sizeof(*gh), 0, 0);
+
+ if (TLVP_PRESENT(&tp, GA_IE_MI)) {
+ char mi_string[32];
+ gsm48_mi_to_string(&mi_string, sizeof(mi_string),
+ TLVP_VAL(&tp, GA_IE_MI), TLVP_LEN(&tp, GA_IE_MI));
+
+ printf("DISCOVERY from %s\n", mi_string);
+ }
+
+ return tx_unc_disco_acc(peer, "segw.uma.sysmocom.de",
+ "ganc.uma.sysmocom.de");
+}
+
+static int rx_unc_rc(struct gan_peer *peer, struct msgb *msg, struct gan_rc_csr_hdr *gh)
+{
+ switch (gh->msg_type) {
+ case GA_MT_RC_DISCOVERY_REQUEST:
+ return rx_unc_discovery_req(peer, msg, gh);
+ case GA_MT_RC_REGISTER_REQUEST:
+ case GA_MT_RC_DEREGISTER:
+ break;
+ }
+
+ return 0;
+}
+
+static int rx_unc_msg(struct gan_peer *peer, struct msgb *msg)
+{
+ struct gan_rc_csr_hdr *gh = (struct gan_rc_csr_hdr *) msg->l2h;
+
+ printf("PDISC=%u TYPE=%u\n", gh->pdisc, gh->msg_type);
+
+ switch (gh->pdisc) {
+ case GA_PDISC_RC:
+ return rx_unc_rc(peer, msg, gh);
+ case GA_PDISC_CSR:
+ case GA_PDISC_PSR:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int unc_read_cb(struct osmo_conn *conn)
+{
+ struct msgb *msg;
+ struct gan_rc_csr_hdr *gh;
+ int rc;
+
+ msg = msgb_alloc_headroom(1024 + 128, 128, "UNC Read");
+ if (!msg)
+ return -ENOMEM;
+
+ gh = (struct gan_rc_csr_hdr *) msg->data;
+ rc = read(conn->queue.bfd.fd, msg->data, sizeof(gh->len));
+ if (rc <= 0) {
+ msgb_free(msg);
+ return rc;
+ } else if (rc != sizeof(gh->len)) {
+ msgb_free(msg);
+ return -EIO;
+ }
+ msg->l2h = msg->data;
+ msgb_put(msg, rc);
+
+ rc = read(conn->queue.bfd.fd, msg->data, ntohs(gh->len));
+ if (rc <= 0)
+ return rc;
+ else if (rc != ntohs(gh->len)) {
+ msgb_free(msg);
+ return -EIO;
+ }
+
+ msgb_put(msg, rc);
+
+ return rx_unc_msg(conn->priv, msg);
+}
+
+static void unc_accept_cb(struct osmo_conn *conn)
+{
+ struct gan_peer *peer = talloc_zero(conn, struct gan_peer);
+ printf("accepted connection\n");
+
+ peer->conn = conn;
+ conn->priv = peer;
+}
+
+
+int ganc_server_start(const char *host, uint16_t port)
+{
+ struct osmo_link *link;
+
+ link = osmo_link_create(NULL, host, port, unc_read_cb, 10);
+ if (!link)
+ return -ENOMEM;
+
+ osmo_link_listen(link, unc_accept_cb);
+
+ return 0;
+}
diff --git a/openbsc/src/osmo-ganc/main.c b/openbsc/src/osmo-ganc/main.c
new file mode 100644
index 0000000..882df6a
--- /dev/null
+++ b/openbsc/src/osmo-ganc/main.c
@@ -0,0 +1,232 @@
+/* (C) 2012 by Harald Welte <laforge@gnumonks.org>
+ * 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/>.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "../../bscconfig.h"
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/vty/vty.h>
+
+#include <osmocom/sccp/sccp.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/signal.h>
+#include <openbsc/vty.h>
+
+
+static const char *config_file = "osmo-ganc.cfg";
+static const char *rf_ctrl = NULL;
+extern const char *openbsc_copyright;
+static int daemonize = 0;
+
+static void print_usage()
+{
+ printf("Usage: osmo-ganc\n");
+}
+
+static void print_help()
+{
+ printf(" Some useful help...\n");
+ printf(" -h --help this text\n");
+ printf(" -D --daemonize Fork the process into a background daemon\n");
+ printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
+ printf(" -s --disable-color\n");
+ printf(" -T --timestamp. Print a timestamp in the debug output.\n");
+ printf(" -c --config-file filename The config file to use.\n");
+ printf(" -l --local=IP. The local address of the MGCP.\n");
+ printf(" -e --log-level number. Set a global loglevel.\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'},
+ {"debug", 1, 0, 'd'},
+ {"daemonize", 0, 0, 'D'},
+ {"config-file", 1, 0, 'c'},
+ {"disable-color", 0, 0, 's'},
+ {"timestamp", 0, 0, 'T'},
+ {"local", 1, 0, 'l'},
+ {"log-level", 1, 0, 'e'},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long(argc, argv, "hd:DsTc:e:",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_usage();
+ print_help();
+ exit(0);
+ case 's':
+ log_set_use_color(osmo_stderr_target, 0);
+ break;
+ case 'd':
+ log_parse_category_mask(osmo_stderr_target, optarg);
+ break;
+ case 'D':
+ daemonize = 1;
+ break;
+ case 'c':
+ config_file = strdup(optarg);
+ break;
+ case 'T':
+ log_set_print_timestamp(osmo_stderr_target, 1);
+ break;
+ case 'e':
+ log_set_log_level(osmo_stderr_target, atoi(optarg));
+ break;
+ break;
+ default:
+ /* ignore */
+ break;
+ }
+ }
+}
+
+extern enum node_type bsc_vty_go_parent(struct vty *vty);
+
+static struct vty_app_info vty_info = {
+ .name = "OsmoGANC",
+ .version = PACKAGE_VERSION,
+ .go_parent_cb = bsc_vty_go_parent,
+ .is_config_node = bsc_vty_is_config_node,
+};
+
+extern int bsc_shutdown_net(struct gsm_network *net);
+static void signal_handler(int signal)
+{
+ struct osmo_msc_data *msc;
+
+ fprintf(stdout, "signal %u received\n", signal);
+
+ switch (signal) {
+ case SIGINT:
+ 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_vty_ctx, stderr);
+ talloc_report_full(tall_bsc_ctx, stderr);
+ break;
+ case SIGUSR2:
+#if 0
+ if (!bsc_gsmnet->bsc_data)
+ return;
+ llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry)
+ bsc_msc_lost(msc->msc_con);
+#endif
+ break;
+ default:
+ break;
+ }
+}
+
+
+void gsm_net_update_ctype(struct gsm_network *network)
+{
+}
+
+int main(int argc, char **argv)
+{
+ struct osmo_msc_data *msc;
+ struct osmo_bsc_data *data;
+ int rc;
+
+ tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
+
+ osmo_init_logging(&log_info);
+
+ /* enable filters */
+
+ /* This needs to precede handle_options() */
+ vty_info.copyright = openbsc_copyright;
+ vty_init(&vty_info);
+ //bsc_vty_init(&log_info);
+
+ /* parse options */
+ handle_options(argc, argv);
+
+ /* seed the PRNG */
+ srand(time(NULL));
+
+ /* initialize SCCP */
+ sccp_set_log_area(DSCCP);
+
+
+ ganc_server_start(NULL, 14001);
+
+#if 0
+ llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry) {
+ if (osmo_bsc_msc_init(msc) != 0) {
+ LOGP(DNAT, LOGL_ERROR, "Failed to start up. Exiting.\n");
+ exit(1);
+ }
+ }
+
+
+ if (osmo_bsc_sccp_init(bsc_gsmnet) != 0) {
+ LOGP(DNM, LOGL_ERROR, "Failed to register SCCP.\n");
+ exit(1);
+ }
+
+ if (osmo_bsc_audio_init(bsc_gsmnet) != 0) {
+ LOGP(DMSC, LOGL_ERROR, "Failed to register audio support.\n");
+ exit(1);
+ }
+#endif
+ 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);
+ }
+ }
+
+ while (1) {
+ osmo_select_main(0);
+ }
+
+ return 0;
+}