From 7026b85b58b6cba1d14b37afda8ff2126f995655 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 23 Jun 2012 21:58:41 +0200 Subject: initial skeleton for accepting UMA/GAN connections --- openbsc/src/Makefile.am | 2 +- openbsc/src/osmo-ganc/Makefile.am | 11 ++ openbsc/src/osmo-ganc/conn.c | 145 ++++++++++++++++++++++ openbsc/src/osmo-ganc/conn.h | 44 +++++++ openbsc/src/osmo-ganc/ganc_data.h | 12 ++ openbsc/src/osmo-ganc/ganc_server.c | 151 +++++++++++++++++++++++ openbsc/src/osmo-ganc/main.c | 232 ++++++++++++++++++++++++++++++++++++ 7 files changed, 596 insertions(+), 1 deletion(-) create mode 100644 openbsc/src/osmo-ganc/Makefile.am create mode 100644 openbsc/src/osmo-ganc/conn.c create mode 100644 openbsc/src/osmo-ganc/conn.h create mode 100644 openbsc/src/osmo-ganc/ganc_data.h create mode 100644 openbsc/src/osmo-ganc/ganc_server.c create mode 100644 openbsc/src/osmo-ganc/main.c (limited to 'openbsc/src') diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index cf34c4c13..852c442ab 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 000000000..1b8545107 --- /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 000000000..1c252757f --- /dev/null +++ b/openbsc/src/osmo-ganc/conn.c @@ -0,0 +1,145 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 000000000..3e00c4559 --- /dev/null +++ b/openbsc/src/osmo-ganc/conn.h @@ -0,0 +1,44 @@ +#ifndef _OSMO_CONN_H +#define _OSMO_CONN_H + +#include +#include +#include +#include + +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 000000000..f67969c36 --- /dev/null +++ b/openbsc/src/osmo-ganc/ganc_data.h @@ -0,0 +1,12 @@ +#ifndef _GANC_DATA_H +#define _GANC_DATA_H + +#include +#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 000000000..b8153c9e5 --- /dev/null +++ b/openbsc/src/osmo-ganc/ganc_server.c @@ -0,0 +1,151 @@ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#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 000000000..882df6ab0 --- /dev/null +++ b/openbsc/src/osmo-ganc/main.c @@ -0,0 +1,232 @@ +/* (C) 2012 by Harald Welte + * 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 . + * + */ + +#define _GNU_SOURCE +#include + +#include +#include +#include +#include +#include +#include + +#include "../../bscconfig.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include + + +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; +} -- cgit v1.2.3