aboutsummaryrefslogtreecommitdiffstats
path: root/src/gprs
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2017-07-13 02:03:50 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2017-08-30 14:14:58 +0200
commitee6cfdc0d9710e3a69c8e1939eb21c8f2b759885 (patch)
treeed5aeb0979a1838778649078847a1ed6caa6b1a4 /src/gprs
parent6c809185ee86d318d10205756bb6d91914d11fdf (diff)
split off osmo-sgsn: remove files, apply build1.1.0
Diffstat (limited to 'src/gprs')
-rw-r--r--src/gprs/Makefile.am5
-rw-r--r--src/gprs/gb_proxy.c3
-rw-r--r--src/gprs/gb_proxy_main.c35
-rw-r--r--src/gprs/gb_proxy_patch.c3
-rw-r--r--src/gprs/gb_proxy_peer.c5
-rw-r--r--src/gprs/gb_proxy_vty.c2
-rw-r--r--src/gprs/gprs_gmm.c7
-rw-r--r--src/gprs/gprs_llc.c3
-rw-r--r--src/gprs/gprs_llc_parse.c1
-rw-r--r--src/gprs/gprs_llc_vty.c1
-rw-r--r--src/gprs/gprs_sgsn.c2
-rw-r--r--src/gprs/gprs_sndcp.c1
-rw-r--r--src/gprs/gprs_sndcp_vty.c1
-rw-r--r--src/gprs/gsup_client.c355
-rw-r--r--src/gprs/gtphub_main.c35
-rw-r--r--src/gprs/gtphub_vty.c1
-rw-r--r--src/gprs/oap_client.c280
-rw-r--r--src/gprs/sgsn_ares.c2
-rw-r--r--src/gprs/sgsn_ctrl.c1
-rw-r--r--src/gprs/sgsn_main.c54
-rw-r--r--src/gprs/sgsn_vty.c2
21 files changed, 759 insertions, 40 deletions
diff --git a/src/gprs/Makefile.am b/src/gprs/Makefile.am
index 39a4c12a7..654604b80 100644
--- a/src/gprs/Makefile.am
+++ b/src/gprs/Makefile.am
@@ -62,7 +62,6 @@ osmo_gbproxy_SOURCES = \
gprs_utils.c \
$(NULL)
osmo_gbproxy_LDADD = \
- $(top_builddir)/src/libcommon/libcommon.a \
$(OSMO_LIBS) \
$(LIBCRYPTO_LIBS) \
-lrt \
@@ -93,9 +92,10 @@ osmo_sgsn_SOURCES = \
slhc.c \
gprs_llc_xid.c \
v42bis.c \
+ gsup_client.c \
+ oap_client.c \
$(NULL)
osmo_sgsn_LDADD = \
- $(top_builddir)/src/libcommon/libcommon.a \
$(OSMO_LIBS) \
$(LIBOSMOABIS_LIBS) \
$(LIBCARES_LIBS) \
@@ -122,7 +122,6 @@ osmo_gtphub_SOURCES = \
gprs_utils.c \
$(NULL)
osmo_gtphub_LDADD = \
- $(top_builddir)/src/libcommon/libcommon.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
diff --git a/src/gprs/gb_proxy.c b/src/gprs/gb_proxy.c
index cd38d23bf..d288cb314 100644
--- a/src/gprs/gb_proxy.c
+++ b/src/gprs/gb_proxy.c
@@ -47,12 +47,13 @@
#include <openbsc/gb_proxy.h>
#include <openbsc/gprs_llc.h>
-#include <openbsc/gsm_04_08.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <openbsc/gprs_utils.h>
#include <openssl/rand.h>
+extern void *tall_bsc_ctx;
+
static const struct rate_ctr_desc global_ctr_description[] = {
{ "inv-bvci", "Invalid BVC Identifier " },
{ "inv-lai", "Invalid Location Area Identifier" },
diff --git a/src/gprs/gb_proxy_main.c b/src/gprs/gb_proxy_main.c
index caff27f6f..853a763a2 100644
--- a/src/gprs/gb_proxy_main.c
+++ b/src/gprs/gb_proxy_main.c
@@ -190,13 +190,39 @@ static void handle_options(int argc, char **argv)
}
}
-extern int bsc_vty_go_parent(struct vty *vty);
+int gbproxy_vty_is_config_node(struct vty *vty, int node)
+{
+ switch (node) {
+ /* add items that are not config */
+ case CONFIG_NODE:
+ return 0;
+
+ default:
+ return 1;
+ }
+}
+
+int gbproxy_vty_go_parent(struct vty *vty)
+{
+ switch (vty->node) {
+ case GBPROXY_NODE:
+ default:
+ if (gbproxy_vty_is_config_node(vty, vty->node))
+ vty->node = CONFIG_NODE;
+ else
+ vty->node = ENABLE_NODE;
+
+ vty->index = NULL;
+ }
+
+ return vty->node;
+}
static struct vty_app_info vty_info = {
.name = "OsmoGbProxy",
.version = PACKAGE_VERSION,
- .go_parent_cb = bsc_vty_go_parent,
- .is_config_node = bsc_vty_is_config_node,
+ .go_parent_cb = gbproxy_vty_go_parent,
+ .is_config_node = gbproxy_vty_is_config_node,
};
/* default categories */
@@ -226,7 +252,6 @@ static const struct log_info gprs_log_info = {
int main(int argc, char **argv)
{
- struct gsm_network dummy_network;
int rc;
tall_bsc_ctx = talloc_named_const(NULL, 0, "nsip_proxy");
@@ -271,7 +296,7 @@ int main(int argc, char **argv)
}
/* start telnet after reading config for vty_get_bind_addr() */
- rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network,
+ rc = telnet_init_dynif(tall_bsc_ctx, NULL,
vty_get_bind_addr(), OSMO_VTY_PORT_GBPROXY);
if (rc < 0)
exit(1);
diff --git a/src/gprs/gb_proxy_patch.c b/src/gprs/gb_proxy_patch.c
index 210fb2b96..bee315036 100644
--- a/src/gprs/gb_proxy_patch.c
+++ b/src/gprs/gb_proxy_patch.c
@@ -23,13 +23,14 @@
#include <openbsc/gprs_utils.h>
#include <openbsc/gprs_gb_parse.h>
-#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gsm/apn.h>
+extern void *tall_bsc_ctx;
+
/* patch RA identifier in place */
static void gbproxy_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer,
int to_bss, const char *log_text)
diff --git a/src/gprs/gb_proxy_peer.c b/src/gprs/gb_proxy_peer.c
index 890968717..a83630bc1 100644
--- a/src/gprs/gb_proxy_peer.c
+++ b/src/gprs/gb_proxy_peer.c
@@ -22,17 +22,18 @@
#include <openbsc/gb_proxy.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_data_shared.h>
#include <openbsc/debug.h>
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>
#include <osmocom/core/talloc.h>
+#include <osmocom/gsm/tlv.h>
#include <string.h>
+extern void *tall_bsc_ctx;
+
static const struct rate_ctr_desc peer_ctr_description[] = {
{ "blocked", "BVC Block " },
{ "unblocked", "BVC Unblock " },
diff --git a/src/gprs/gb_proxy_vty.c b/src/gprs/gb_proxy_vty.c
index 86d65a8e3..bd5bb1b5b 100644
--- a/src/gprs/gb_proxy_vty.c
+++ b/src/gprs/gb_proxy_vty.c
@@ -26,8 +26,8 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/rate_ctr.h>
+#include <osmocom/gsm/gsm48.h>
-#include <openbsc/gsm_04_08.h>
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gsm/apn.h>
diff --git a/src/gprs/gprs_gmm.c b/src/gprs/gprs_gmm.c
index 032137f0b..7301bf1c2 100644
--- a/src/gprs/gprs_gmm.c
+++ b/src/gprs/gprs_gmm.c
@@ -35,7 +35,6 @@
#include "bscconfig.h"
-#include <openbsc/db.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/gsm/gsm_utils.h>
@@ -56,11 +55,6 @@
#endif
#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/paging.h>
-#include <openbsc/transaction.h>
#include <openbsc/gprs_llc.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
@@ -75,6 +69,7 @@
#define PTMSI_ALLOC
extern struct sgsn_instance *sgsn;
+extern void *tall_bsc_ctx;
static const struct tlv_definition gsm48_gmm_att_tlvdef = {
.def = {
diff --git a/src/gprs/gprs_llc.c b/src/gprs/gprs_llc.c
index 2be663f98..904ec7e07 100644
--- a/src/gprs/gprs_llc.c
+++ b/src/gprs/gprs_llc.c
@@ -31,15 +31,14 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/gsm/gsm_utils.h>
-#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
#include <openbsc/gprs_llc.h>
#include <openbsc/crc24.h>
#include <openbsc/sgsn.h>
-#include <openbsc/gsm_subscriber.h>
#include <openbsc/gprs_llc_xid.h>
#include <openbsc/gprs_sndcp_comp.h>
#include <openbsc/gprs_sndcp.h>
diff --git a/src/gprs/gprs_llc_parse.c b/src/gprs/gprs_llc_parse.c
index a5a7a7122..be634974a 100644
--- a/src/gprs/gprs_llc_parse.c
+++ b/src/gprs/gprs_llc_parse.c
@@ -28,7 +28,6 @@
#include <osmocom/core/talloc.h>
#include <osmocom/gprs/gprs_bssgp.h>
-#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
diff --git a/src/gprs/gprs_llc_vty.c b/src/gprs/gprs_llc_vty.c
index bf34e9782..626d6ef1b 100644
--- a/src/gprs/gprs_llc_vty.c
+++ b/src/gprs/gprs_llc_vty.c
@@ -27,7 +27,6 @@
#include <arpa/inet.h>
-#include <openbsc/gsm_data.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/core/talloc.h>
diff --git a/src/gprs/gprs_sgsn.c b/src/gprs/gprs_sgsn.c
index de79afb1a..560485de5 100644
--- a/src/gprs/gprs_sgsn.c
+++ b/src/gprs/gprs_sgsn.c
@@ -31,6 +31,7 @@
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gsm/apn.h>
+#include <osmocom/gsm/gsm_utils.h>
#include <openbsc/gprs_subscriber.h>
#include <openbsc/debug.h>
@@ -56,6 +57,7 @@
#define GPRS_LLME_CHECK_TICK 30
extern struct sgsn_instance *sgsn;
+extern void *tall_bsc_ctx;
LLIST_HEAD(sgsn_mm_ctxts);
LLIST_HEAD(sgsn_ggsn_ctxts);
diff --git a/src/gprs/gprs_sndcp.c b/src/gprs/gprs_sndcp.c
index a18998f9e..05dad6603 100644
--- a/src/gprs/gprs_sndcp.c
+++ b/src/gprs/gprs_sndcp.c
@@ -30,7 +30,6 @@
#include <osmocom/core/talloc.h>
#include <osmocom/gprs/gprs_bssgp.h>
-#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <openbsc/gprs_llc.h>
#include <openbsc/sgsn.h>
diff --git a/src/gprs/gprs_sndcp_vty.c b/src/gprs/gprs_sndcp_vty.c
index 430881fc8..4bad8b040 100644
--- a/src/gprs/gprs_sndcp_vty.c
+++ b/src/gprs/gprs_sndcp_vty.c
@@ -26,7 +26,6 @@
#include <arpa/inet.h>
-#include <openbsc/gsm_data.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/core/talloc.h>
diff --git a/src/gprs/gsup_client.c b/src/gprs/gsup_client.c
new file mode 100644
index 000000000..258f230cb
--- /dev/null
+++ b/src/gprs/gsup_client.c
@@ -0,0 +1,355 @@
+/* Generic Subscriber Update Protocol client */
+
+/* (C) 2014-2016 by Sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Jacob Erlbeck
+ * Author: Neels Hofmeyr
+ *
+ * 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/gsup_client.h>
+
+#include <osmocom/abis/ipa.h>
+#include <osmocom/gsm/protocol/ipaccess.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/logging.h>
+
+#include <openbsc/debug.h>
+
+#include <errno.h>
+#include <string.h>
+
+extern void *tall_bsc_ctx;
+
+static void start_test_procedure(struct gsup_client *gsupc);
+
+static void gsup_client_send_ping(struct gsup_client *gsupc)
+{
+ struct msgb *msg = gsup_client_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 gsup_client_connect(struct gsup_client *gsupc)
+{
+ int rc;
+
+ if (gsupc->is_connected)
+ return 0;
+
+ if (osmo_timer_pending(&gsupc->connect_timer)) {
+ LOGP(DLGSUP, LOGL_DEBUG,
+ "GSUP connect: connect timer already running\n");
+ osmo_timer_del(&gsupc->connect_timer);
+ }
+
+ if (osmo_timer_pending(&gsupc->ping_timer)) {
+ LOGP(DLGSUP, LOGL_DEBUG,
+ "GSUP connect: ping timer already running\n");
+ osmo_timer_del(&gsupc->ping_timer);
+ }
+
+ if (ipa_client_conn_clear_queue(gsupc->link) > 0)
+ LOGP(DLGSUP, LOGL_DEBUG, "GSUP connect: discarded stored messages\n");
+
+ rc = ipa_client_conn_open(gsupc->link);
+
+ if (rc >= 0) {
+ LOGP(DLGSUP, LOGL_NOTICE, "GSUP connecting to %s:%d\n",
+ gsupc->link->addr, gsupc->link->port);
+ return 0;
+ }
+
+ LOGP(DLGSUP, LOGL_ERROR, "GSUP failed to connect to %s:%d: %s\n",
+ gsupc->link->addr, gsupc->link->port, strerror(-rc));
+
+ if (rc == -EBADF || rc == -ENOTSOCK || rc == -EAFNOSUPPORT ||
+ rc == -EINVAL)
+ return rc;
+
+ osmo_timer_schedule(&gsupc->connect_timer,
+ GSUP_CLIENT_RECONNECT_INTERVAL, 0);
+
+ LOGP(DLGSUP, LOGL_INFO, "Scheduled timer to retry GSUP connect to %s:%d\n",
+ gsupc->link->addr, gsupc->link->port);
+
+ return 0;
+}
+
+static void connect_timer_cb(void *gsupc_)
+{
+ struct gsup_client *gsupc = gsupc_;
+
+ if (gsupc->is_connected)
+ return;
+
+ gsup_client_connect(gsupc);
+}
+
+static void client_send(struct gsup_client *gsupc, int proto_ext,
+ struct msgb *msg_tx)
+{
+ ipa_prepend_header_ext(msg_tx, proto_ext);
+ ipa_msg_push_header(msg_tx, IPAC_PROTO_OSMO);
+ ipa_client_conn_send(gsupc->link, msg_tx);
+ /* msg_tx is now queued and will be freed. */
+}
+
+static void gsup_client_oap_register(struct gsup_client *gsupc)
+{
+ struct msgb *msg_tx;
+ int rc;
+ rc = oap_client_register(&gsupc->oap_state, &msg_tx);
+
+ if ((rc < 0) || (!msg_tx)) {
+ LOGP(DLGSUP, LOGL_ERROR, "GSUP OAP set up, but cannot register.\n");
+ return;
+ }
+
+ client_send(gsupc, IPAC_PROTO_EXT_OAP, msg_tx);
+}
+
+static void gsup_client_updown_cb(struct ipa_client_conn *link, int up)
+{
+ struct gsup_client *gsupc = link->data;
+
+ LOGP(DLGSUP, LOGL_INFO, "GSUP link to %s:%d %s\n",
+ link->addr, link->port, up ? "UP" : "DOWN");
+
+ gsupc->is_connected = up;
+
+ if (up) {
+ start_test_procedure(gsupc);
+
+ if (gsupc->oap_state.state == OAP_INITIALIZED)
+ gsup_client_oap_register(gsupc);
+
+ osmo_timer_del(&gsupc->connect_timer);
+ } else {
+ osmo_timer_del(&gsupc->ping_timer);
+
+ osmo_timer_schedule(&gsupc->connect_timer,
+ GSUP_CLIENT_RECONNECT_INTERVAL, 0);
+ }
+}
+
+static int gsup_client_oap_handle(struct gsup_client *gsupc, struct msgb *msg_rx)
+{
+ int rc;
+ struct msgb *msg_tx;
+
+ /* If the oap_state is disabled, this will reject the messages. */
+ rc = oap_client_handle(&gsupc->oap_state, msg_rx, &msg_tx);
+ msgb_free(msg_rx);
+ if (rc < 0)
+ return rc;
+
+ if (msg_tx)
+ client_send(gsupc, IPAC_PROTO_EXT_OAP, msg_tx);
+
+ return 0;
+}
+
+static int gsup_client_read_cb(struct ipa_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);
+ struct gsup_client *gsupc = (struct gsup_client *)link->data;
+ int rc;
+ struct ipaccess_unit ipa_dev = {
+ /* see gsup_client_create() on const vs non-const */
+ .unit_name = (char*)gsupc->unit_name,
+ };
+
+ OSMO_ASSERT(ipa_dev.unit_name);
+
+ msg->l2h = &hh->data[0];
+
+ rc = ipaccess_bts_handle_ccm(link, &ipa_dev, msg);
+
+ if (rc < 0) {
+ LOGP(DLGSUP, LOGL_NOTICE,
+ "GSUP received an invalid IPA/CCM message from %s:%d\n",
+ link->addr, link->port);
+ /* Link has been closed */
+ gsupc->is_connected = 0;
+ msgb_free(msg);
+ return -1;
+ }
+
+ if (rc == 1) {
+ uint8_t msg_type = *(msg->l2h);
+ /* CCM message */
+ if (msg_type == IPAC_MSGT_PONG) {
+ LOGP(DLGSUP, LOGL_DEBUG, "GSUP receiving PONG\n");
+ gsupc->got_ipa_pong = 1;
+ }
+
+ msgb_free(msg);
+ return 0;
+ }
+
+ if (hh->proto != IPAC_PROTO_OSMO)
+ goto invalid;
+
+ if (!he || msgb_l2len(msg) < sizeof(*he))
+ goto invalid;
+
+ msg->l2h = &he->data[0];
+
+ if (he->proto == IPAC_PROTO_EXT_GSUP) {
+ OSMO_ASSERT(gsupc->read_cb != NULL);
+ gsupc->read_cb(gsupc, msg);
+ /* expecting read_cb() to free msg */
+ } else if (he->proto == IPAC_PROTO_EXT_OAP) {
+ return gsup_client_oap_handle(gsupc, msg);
+ /* gsup_client_oap_handle frees msg */
+ } else
+ goto invalid;
+
+ return 0;
+
+invalid:
+ LOGP(DLGSUP, LOGL_NOTICE,
+ "GSUP received an invalid IPA message from %s:%d, size = %d\n",
+ link->addr, link->port, msgb_length(msg));
+
+ msgb_free(msg);
+ return -1;
+}
+
+static void ping_timer_cb(void *gsupc_)
+{
+ struct gsup_client *gsupc = gsupc_;
+
+ LOGP(DLGSUP, 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(DLGSUP, 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 gsup_client *gsupc)
+{
+ osmo_timer_setup(&gsupc->ping_timer, ping_timer_cb, gsupc);
+
+ gsupc->got_ipa_pong = 0;
+ osmo_timer_schedule(&gsupc->ping_timer, GSUP_CLIENT_PING_INTERVAL, 0);
+ LOGP(DLGSUP, LOGL_DEBUG, "GSUP sending PING\n");
+ gsup_client_send_ping(gsupc);
+}
+
+struct gsup_client *gsup_client_create(const char *unit_name,
+ const char *ip_addr,
+ unsigned int tcp_port,
+ gsup_client_read_cb_t read_cb,
+ struct oap_client_config *oapc_config)
+{
+ struct gsup_client *gsupc;
+ int rc;
+
+ gsupc = talloc_zero(tall_bsc_ctx, struct gsup_client);
+ OSMO_ASSERT(gsupc);
+
+ /* struct ipaccess_unit has a non-const unit_name, so let's copy to be
+ * able to have a non-const unit_name here as well. To not taint the
+ * public gsup_client API, let's store it in a const char* anyway. */
+ gsupc->unit_name = talloc_strdup(gsupc, unit_name);
+ OSMO_ASSERT(gsupc->unit_name);
+
+ /* a NULL oapc_config will mark oap_state disabled. */
+ rc = oap_client_init(oapc_config, &gsupc->oap_state);
+ if (rc != 0)
+ goto failed;
+
+ gsupc->link = ipa_client_conn_create(gsupc,
+ /* no e1inp */ NULL,
+ 0,
+ ip_addr, tcp_port,
+ gsup_client_updown_cb,
+ gsup_client_read_cb,
+ /* default write_cb */ NULL,
+ gsupc);
+ if (!gsupc->link)
+ goto failed;
+
+ osmo_timer_setup(&gsupc->connect_timer, connect_timer_cb, gsupc);
+
+ rc = gsup_client_connect(gsupc);
+
+ if (rc < 0)
+ goto failed;
+
+ gsupc->read_cb = read_cb;
+
+ return gsupc;
+
+failed:
+ gsup_client_destroy(gsupc);
+ return NULL;
+}
+
+void gsup_client_destroy(struct gsup_client *gsupc)
+{
+ osmo_timer_del(&gsupc->connect_timer);
+ osmo_timer_del(&gsupc->ping_timer);
+
+ if (gsupc->link) {
+ ipa_client_conn_close(gsupc->link);
+ ipa_client_conn_destroy(gsupc->link);
+ gsupc->link = NULL;
+ }
+ talloc_free(gsupc);
+}
+
+int gsup_client_send(struct gsup_client *gsupc, struct msgb *msg)
+{
+ if (!gsupc) {
+ LOGP(DGPRS, LOGL_NOTICE, "No GSUP client, unable to "
+ "send %s\n", msgb_hexdump(msg));
+ msgb_free(msg);
+ return -ENOTCONN;
+ }
+
+ if (!gsupc->is_connected) {
+ LOGP(DGPRS, LOGL_NOTICE, "GSUP not connected, unable to "
+ "send %s\n", msgb_hexdump(msg));
+ msgb_free(msg);
+ return -EAGAIN;
+ }
+
+ client_send(gsupc, IPAC_PROTO_EXT_GSUP, msg);
+
+ return 0;
+}
+
+struct msgb *gsup_client_msgb_alloc(void)
+{
+ return msgb_alloc_headroom(4000, 64, __func__);
+}
diff --git a/src/gprs/gtphub_main.c b/src/gprs/gtphub_main.c
index 2b87d19ef..d7b3ba74b 100644
--- a/src/gprs/gtphub_main.c
+++ b/src/gprs/gtphub_main.c
@@ -39,6 +39,8 @@
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/ports.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+
#include <openbsc/debug.h>
#include <openbsc/gtphub.h>
#include <openbsc/vty.h>
@@ -46,7 +48,7 @@
#include "../../bscconfig.h"
extern void *osmo_gtphub_ctx;
-
+void *tall_bsc_ctx;
const char *gtphub_copyright =
"Copyright (C) 2015 sysmocom s.f.m.c GmbH <info@sysmocom.de>\r\n"
@@ -113,13 +115,38 @@ static void signal_handler(int signal)
}
}
-extern int bsc_vty_go_parent(struct vty *vty);
+int gtphub_vty_go_parent(struct vty *vty)
+{
+ switch (vty->node) {
+ default:
+ osmo_ss7_vty_go_parent(vty);
+ }
+
+ return vty->node;
+}
+
+int gtphub_vty_is_config_node(struct vty *vty, int node)
+{
+ /* Check if libosmo-sccp declares the node in
+ * question as config node */
+ if (osmo_ss7_is_config_node(vty, node))
+ return 1;
+
+ switch (node) {
+ /* add items that are not config */
+ case CONFIG_NODE:
+ return 0;
+
+ default:
+ return 1;
+ }
+}
static struct vty_app_info vty_info = {
.name = "OsmoGTPhub",
.version = PACKAGE_VERSION,
- .go_parent_cb = bsc_vty_go_parent,
- .is_config_node = bsc_vty_is_config_node,
+ .go_parent_cb = gtphub_vty_go_parent,
+ .is_config_node = gtphub_vty_is_config_node,
};
struct cmdline_cfg {
diff --git a/src/gprs/gtphub_vty.c b/src/gprs/gtphub_vty.c
index a30ad2a54..d611b1f9a 100644
--- a/src/gprs/gtphub_vty.c
+++ b/src/gprs/gtphub_vty.c
@@ -37,6 +37,7 @@
* globals. */
#include <openbsc/sgsn.h>
extern struct sgsn_instance *sgsn;
+extern void *tall_bsc_ctx;
static struct gtphub *g_hub = 0;
static struct gtphub_cfg *g_cfg = 0;
diff --git a/src/gprs/oap_client.c b/src/gprs/oap_client.c
new file mode 100644
index 000000000..5128ac119
--- /dev/null
+++ b/src/gprs/oap_client.c
@@ -0,0 +1,280 @@
+/* Osmocom Authentication Protocol API */
+
+/* (C) 2015 by Sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr
+ *
+ * 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 <string.h>
+#include <errno.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/crypt/auth.h>
+#include <osmocom/gsm/oap.h>
+
+#include <openbsc/oap_client.h>
+#include <openbsc/debug.h>
+
+int oap_client_init(struct oap_client_config *config,
+ struct oap_client_state *state)
+{
+ OSMO_ASSERT(state->state == OAP_UNINITIALIZED);
+
+ if (!config)
+ goto disable;
+
+ if (config->client_id == 0)
+ goto disable;
+
+ if (config->secret_k_present == 0) {
+ LOGP(DLOAP, LOGL_NOTICE, "OAP: client ID set, but secret K missing.\n");
+ goto disable;
+ }
+
+ if (config->secret_opc_present == 0) {
+ LOGP(DLOAP, LOGL_NOTICE, "OAP: client ID set, but secret OPC missing.\n");
+ goto disable;
+ }
+
+ state->client_id = config->client_id;
+ memcpy(state->secret_k, config->secret_k, sizeof(state->secret_k));
+ memcpy(state->secret_opc, config->secret_opc, sizeof(state->secret_opc));
+ state->state = OAP_INITIALIZED;
+ return 0;
+
+disable:
+ state->state = OAP_DISABLED;
+ return 0;
+}
+
+/* From the given state and received RAND and AUTN octets, validate the
+ * server's authenticity and formulate the matching milenage reply octets in
+ * *tx_xres. The state is not modified.
+ * On success, and if tx_res is not NULL, exactly 8 octets will be written to
+ * *tx_res. If not NULL, tx_res must point at allocated memory of at least 8
+ * octets. The caller will want to send XRES back to the server in a challenge
+ * response message and update the state.
+ * Return 0 on success; -1 if OAP is disabled; -2 if rx_random and rx_autn fail
+ * the authentication check; -3 for any other errors. */
+static int oap_evaluate_challenge(const struct oap_client_state *state,
+ const uint8_t *rx_random,
+ const uint8_t *rx_autn,
+ uint8_t *tx_xres)
+{
+ struct osmo_auth_vector vec;
+
+ struct osmo_sub_auth_data auth = {
+ .type = OSMO_AUTH_TYPE_UMTS,
+ .algo = OSMO_AUTH_ALG_MILENAGE,
+ };
+
+ osmo_static_assert(sizeof(((struct osmo_sub_auth_data*)0)->u.umts.k)
+ == sizeof(state->secret_k), _secret_k_size_match);
+ osmo_static_assert(sizeof(((struct osmo_sub_auth_data*)0)->u.umts.opc)
+ == sizeof(state->secret_opc), _secret_opc_size_match);
+
+ switch (state->state) {
+ case OAP_UNINITIALIZED:
+ case OAP_DISABLED:
+ return -1;
+ default:
+ break;
+ }
+
+ memcpy(auth.u.umts.k, state->secret_k, sizeof(auth.u.umts.k));
+ memcpy(auth.u.umts.opc, state->secret_opc, sizeof(auth.u.umts.opc));
+ memset(auth.u.umts.amf, '\0', sizeof(auth.u.umts.amf));
+ auth.u.umts.sqn = 41; /* TODO use incrementing sequence nr */
+
+ memset(&vec, 0, sizeof(vec));
+ osmo_auth_gen_vec(&vec, &auth, rx_random);
+
+ if (vec.res_len != 8) {
+ LOGP(DLOAP, LOGL_ERROR, "OAP: Expected XRES to be 8 octets, got %d\n",
+ vec.res_len);
+ return -3;
+ }
+
+ if (osmo_constant_time_cmp(vec.autn, rx_autn, sizeof(vec.autn)) != 0) {
+ LOGP(DLOAP, LOGL_ERROR, "OAP: AUTN mismatch!\n");
+ LOGP(DLOAP, LOGL_INFO, "OAP: AUTN from server: %s\n",
+ osmo_hexdump_nospc(rx_autn, sizeof(vec.autn)));
+ LOGP(DLOAP, LOGL_INFO, "OAP: AUTN expected: %s\n",
+ osmo_hexdump_nospc(vec.autn, sizeof(vec.autn)));
+ return -2;
+ }
+
+ if (tx_xres != NULL)
+ memcpy(tx_xres, vec.res, 8);
+ return 0;
+}
+
+struct msgb *oap_client_encoded(const struct osmo_oap_message *oap_msg)
+{
+ struct msgb *msg = msgb_alloc_headroom(1000, 64, __func__);
+ OSMO_ASSERT(msg);
+ osmo_oap_encode(msg, oap_msg);
+ return msg;
+}
+
+/* Create a new msgb containing an OAP registration message.
+ * On error, return NULL. */
+static struct msgb* oap_msg_register(uint16_t client_id)
+{
+ struct osmo_oap_message oap_msg = {0};
+
+ if (client_id < 1) {
+ LOGP(DLOAP, LOGL_ERROR, "OAP: Invalid client ID: %d\n", client_id);
+ return NULL;
+ }
+
+ oap_msg.message_type = OAP_MSGT_REGISTER_REQUEST;
+ oap_msg.client_id = client_id;
+ return oap_client_encoded(&oap_msg);
+}
+
+int oap_client_register(struct oap_client_state *state, struct msgb **msg_tx)
+{
+ *msg_tx = oap_msg_register(state->client_id);
+ if (!(*msg_tx))
+ return -1;
+
+ state->state = OAP_REQUESTED_CHALLENGE;
+ return 0;
+}
+
+/* Create a new msgb containing an OAP challenge response message.
+ * xres must point at 8 octets to return as challenge response.
+ * On error, return NULL. */
+static struct msgb* oap_msg_challenge_response(uint8_t *xres)
+{
+ struct osmo_oap_message oap_reply = {0};
+
+ oap_reply.message_type = OAP_MSGT_CHALLENGE_RESULT;
+ memcpy(oap_reply.xres, xres, sizeof(oap_reply.xres));
+ oap_reply.xres_present = 1;
+ return oap_client_encoded(&oap_reply);
+}
+
+static int handle_challenge(struct oap_client_state *state,
+ struct osmo_oap_message *oap_rx,
+ struct msgb **msg_tx)
+{
+ int rc;
+ uint8_t xres[8];
+
+ if (!(oap_rx->rand_present && oap_rx->autn_present)) {
+ LOGP(DLOAP, LOGL_ERROR,
+ "OAP challenge incomplete (rand_present: %d, autn_present: %d)\n",
+ oap_rx->rand_present, oap_rx->autn_present);
+ rc = -2;
+ goto failure;
+ }
+
+ rc = oap_evaluate_challenge(state,
+ oap_rx->rand,
+ oap_rx->autn,
+ xres);
+ if (rc < 0)
+ goto failure;
+
+ *msg_tx = oap_msg_challenge_response(xres);
+ if ((*msg_tx) == NULL) {
+ rc = -1;
+ goto failure;
+ }
+
+ state->state = OAP_SENT_CHALLENGE_RESULT;
+ return 0;
+
+failure:
+ OSMO_ASSERT(rc < 0);
+ state->state = OAP_INITIALIZED;
+ return rc;
+}
+
+int oap_client_handle(struct oap_client_state *state,
+ const struct msgb *msg_rx, struct msgb **msg_tx)
+{
+ uint8_t *data = msgb_l2(msg_rx);
+ size_t data_len = msgb_l2len(msg_rx);
+ struct osmo_oap_message oap_msg = {0};
+ int rc = 0;
+
+ *msg_tx = NULL;
+
+ OSMO_ASSERT(data);
+
+ rc = osmo_oap_decode(&oap_msg, data, data_len);
+ if (rc < 0) {
+ LOGP(DLOAP, LOGL_ERROR,
+ "Decoding OAP message failed with error '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, -rc), -rc);
+ return -10;
+ }
+
+ switch (state->state) {
+ case OAP_UNINITIALIZED:
+ LOGP(DLOAP, LOGL_ERROR,
+ "Received OAP message %d, but the OAP client is"
+ " not initialized\n", oap_msg.message_type);
+ return -ENOTCONN;
+ case OAP_DISABLED:
+ LOGP(DLOAP, LOGL_ERROR,
+ "Received OAP message %d, but the OAP client is"
+ " disabled\n", oap_msg.message_type);
+ return -ENOTCONN;
+ default:
+ break;
+ }
+
+ switch (oap_msg.message_type) {
+ case OAP_MSGT_CHALLENGE_REQUEST:
+ return handle_challenge(state, &oap_msg, msg_tx);
+
+ case OAP_MSGT_REGISTER_RESULT:
+ /* successfully registered */
+ state->state = OAP_REGISTERED;
+ break;
+
+ case OAP_MSGT_REGISTER_ERROR:
+ LOGP(DLOAP, LOGL_ERROR,
+ "OAP registration failed\n");
+ state->state = OAP_INITIALIZED;
+ if (state->registration_failures < 3) {
+ state->registration_failures ++;
+ return oap_client_register(state, msg_tx);
+ }
+ return -11;
+
+ case OAP_MSGT_REGISTER_REQUEST:
+ case OAP_MSGT_CHALLENGE_RESULT:
+ LOGP(DLOAP, LOGL_ERROR,
+ "Received invalid OAP message type for OAP client side: %d\n",
+ (int)oap_msg.message_type);
+ return -12;
+
+ default:
+ LOGP(DLOAP, LOGL_ERROR,
+ "Unknown OAP message type: %d\n",
+ (int)oap_msg.message_type);
+ return -13;
+ }
+
+ return 0;
+}
diff --git a/src/gprs/sgsn_ares.c b/src/gprs/sgsn_ares.c
index d94d184a3..623809911 100644
--- a/src/gprs/sgsn_ares.c
+++ b/src/gprs/sgsn_ares.c
@@ -24,6 +24,8 @@
#include <netdb.h>
+extern void *tall_bsc_ctx;
+
struct cares_event_fd {
struct llist_head head;
struct osmo_fd fd;
diff --git a/src/gprs/sgsn_ctrl.c b/src/gprs/sgsn_ctrl.c
index 31ac74f1f..f7b1180be 100644
--- a/src/gprs/sgsn_ctrl.c
+++ b/src/gprs/sgsn_ctrl.c
@@ -21,7 +21,6 @@
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/control_cmd.h>
-#include <openbsc/gsm_data.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/sgsn.h>
#include <openbsc/debug.h>
diff --git a/src/gprs/sgsn_main.c b/src/gprs/sgsn_main.c
index 25ee632cc..e24a57ba2 100644
--- a/src/gprs/sgsn_main.c
+++ b/src/gprs/sgsn_main.c
@@ -62,13 +62,13 @@
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
-#include <osmocom/sigtran/protocol/m3ua.h>
-
#include <gtp.h>
#include "../../bscconfig.h"
#if BUILD_IU
+#include <osmocom/sigtran/osmo_ss7.h>
+#include <osmocom/sigtran/protocol/m3ua.h>
#include <osmocom/ranap/iu_client.h>
#endif
@@ -173,13 +173,40 @@ static void signal_handler(int signal)
/* NSI that BSSGP uses when transmitting on NS */
extern struct gprs_ns_inst *bssgp_nsi;
-extern int bsc_vty_go_parent(struct vty *vty);
+int sgsn_vty_is_config_node(struct vty *vty, int node)
+{
+ /* So far the SGSN has no nested nodes that need parent node
+ * declaration, except for the ss7 vty nodes. */
+ switch (node) {
+ case SGSN_NODE:
+ return 1;
+ default:
+#if BUILD_IU
+ return osmo_ss7_is_config_node(vty, node);
+#else
+ return 0;
+#endif
+ }
+}
+
+int sgsn_vty_go_parent(struct vty *vty)
+{
+ /* So far the SGSN has no nested nodes that need parent node
+ * declaration, except for the ss7 vty nodes. */
+#if BUILD_IU
+ return osmo_ss7_vty_go_parent(vty);
+#else
+ vty->node = CONFIG_NODE;
+ vty->index = NULL;
+ return 0;
+#endif
+}
static struct vty_app_info vty_info = {
.name = "OsmoSGSN",
.version = PACKAGE_VERSION,
- .go_parent_cb = bsc_vty_go_parent,
- .is_config_node = bsc_vty_is_config_node,
+ .go_parent_cb = sgsn_vty_go_parent,
+ .is_config_node = sgsn_vty_is_config_node,
};
static void print_help(void)
@@ -325,14 +352,17 @@ static const struct log_info gprs_log_info = {
.num_cat = ARRAY_SIZE(gprs_categories),
};
-int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data);
+#if BUILD_IU
+int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data);
+#endif
int main(int argc, char **argv)
{
struct ctrl_handle *ctrl;
- struct gsm_network dummy_network;
- struct osmo_sccp_instance *sccp;
int rc;
+#if BUILD_IU
+ struct osmo_sccp_instance *sccp;
+#endif
srand(time(NULL));
tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn");
@@ -354,7 +384,11 @@ int main(int argc, char **argv)
osmo_stats_vty_add_cmds(&gprs_log_info);
sgsn_vty_init(&sgsn_inst.cfg);
ctrl_vty_init(tall_bsc_ctx);
+
+#if BUILD_IU
osmo_ss7_init();
+ osmo_ss7_vty_init_asp(tall_bsc_ctx);
+#endif
handle_options(argc, argv);
@@ -389,7 +423,7 @@ int main(int argc, char **argv)
}
/* start telnet after reading config for vty_get_bind_addr() */
- rc = telnet_init_dynif(tall_bsc_ctx, &dummy_network,
+ rc = telnet_init_dynif(tall_bsc_ctx, NULL,
vty_get_bind_addr(), OSMO_VTY_PORT_SGSN);
if (rc < 0)
exit(1);
@@ -442,7 +476,7 @@ int main(int argc, char **argv)
}
}
-#ifdef BUILD_IU
+#if BUILD_IU
sccp = osmo_sccp_simple_client(tall_bsc_ctx, "OsmoSGSN",
2 /* FIXME: configurable */,
OSMO_SS7_ASP_PROT_M3UA, 0,
diff --git a/src/gprs/sgsn_vty.c b/src/gprs/sgsn_vty.c
index 3a5b2ca64..fce251885 100644
--- a/src/gprs/sgsn_vty.c
+++ b/src/gprs/sgsn_vty.c
@@ -51,6 +51,8 @@
#include <osmocom/ranap/iu_client.h>
#endif
+extern void *tall_bsc_ctx;
+
static struct sgsn_config *g_cfg = NULL;
const struct value_string sgsn_auth_pol_strs[] = {