aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2015-12-23 20:16:36 +0100
committerHarald Welte <laforge@gnumonks.org>2015-12-23 22:13:53 +0100
commit90256bad581a77069e0e9232927111f677a15272 (patch)
treedac0f9134f411ed410f114ec585f1749314fe943 /src
parentf42317ba9caa170fb7f1ae1145c40ecc0af46e4f (diff)
Add a context mapper to map RUA ContextIDs <-> SUA Connection IDs
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/context_map.c164
-rw-r--r--src/context_map.h43
-rw-r--r--src/hnbgw.c57
-rw-r--r--src/hnbgw.h41
5 files changed, 294 insertions, 13 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d609445..13cdac9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,7 +8,7 @@ COMMON_LDADD = -lsctp
bin_PROGRAMS = hnbgw
-hnbgw_SOURCES = hnbap_encoder.c hnbap_decoder.c rua_encoder.c rua_decoder.c ranap_common.c rua_common.c hnbap_common.c iu_helpers.c asn1helpers.c hnbgw.c hnbgw_hnbap.c hnbgw_rua.c hnbgw_ranap.c ranap_decoder.c ranap_encoder.c ranap_msg_factory.c
+hnbgw_SOURCES = hnbap_encoder.c hnbap_decoder.c rua_encoder.c rua_decoder.c ranap_common.c rua_common.c hnbap_common.c iu_helpers.c asn1helpers.c hnbgw.c hnbgw_hnbap.c hnbgw_rua.c hnbgw_ranap.c ranap_decoder.c ranap_encoder.c ranap_msg_factory.c context_map.c
hnbgw_LDADD = $(OSMOCORE_LIBS) $(OSMOVTY_LIBS) $(OSMOGSM_LIBS) $(ASN1C_LIBS) $(OSMOSIGTRAN_LIBS) $(COMMON_LDADD) hnbap/libosmo-asn1-hnbap.a rua/libosmo-asn1-rua.a ranap/libosmo-asn1-ranap.a
BUILT_SOURCES = hnbap_decoder.c hnbap_encoder.c rua_decoder.c rua_encoder.c ranap_decoder.c ranap_encoder.c
diff --git a/src/context_map.c b/src/context_map.c
new file mode 100644
index 0000000..8fc48ba
--- /dev/null
+++ b/src/context_map.c
@@ -0,0 +1,164 @@
+/* Mapper between RUA ContextID (24 bit, per HNB) and the SUA/SCCP
+ * Connection ID (32bit, per signalling link) */
+
+/* (C) 2015 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/>.
+ *
+ */
+
+/* an expired mapping is destroyed after 1..2 * EXPIRY_TIMER_SECS */
+#define EXPIRY_TIMER_SECS 23
+
+#include <osmocom/core/timer.h>
+
+#include "hnbgw.h"
+#include "context_map.h"
+
+/* is a given SCCP USER SAP Connection ID in use for a given CN link? */
+static int cn_id_in_use(struct hnbgw_cnlink *cn, uint32_t id)
+{
+ struct hnbgw_context_map *map;
+
+ llist_for_each_entry(map, &cn->map_list, cn_list) {
+ if (map->scu_conn_id == id)
+ return 1;
+ }
+ return 0;
+}
+
+/* try to allocate a new SCCP User SAP Connection ID */
+static int alloc_cn_conn_id(struct hnbgw_cnlink *cn, uint32_t *id_out)
+{
+ uint32_t i;
+ uint32_t id;
+
+ for (i = 0; i < 0xffffffff; i++) {
+ id = cn->next_conn_id++;
+ if (!cn_id_in_use(cn, id)) {
+ *id_out = id;
+ return 1;
+ }
+ }
+ return -1;
+}
+
+/* Map from a HNB + ContextID to the SCCP-side Connection ID */
+struct hnbgw_context_map *
+context_map_alloc_by_hnb(struct hnb_context *hnb, uint32_t rua_ctx_id,
+ struct hnbgw_cnlink *cn_if_new)
+{
+ struct hnbgw_context_map *map;
+ uint32_t new_scu_conn_id;
+
+ llist_for_each_entry(map, &hnb->map_list, hnb_list) {
+ if (map->state != MAP_S_ACTIVE)
+ continue;
+ if (map->rua_ctx_id == rua_ctx_id) {
+ return map;
+ }
+ }
+
+ /* FIXME: allocated CN side ID! */
+ if (alloc_cn_conn_id(cn_if_new, &new_scu_conn_id) < 0)
+ return NULL;
+
+ /* alloate a new map entry */
+ map = talloc_zero(hnb, struct hnbgw_context_map);
+ map->state = MAP_S_NULL;
+ map->cn_link = cn_if_new;
+ map->hnb_ctx = hnb;
+ map->rua_ctx_id = rua_ctx_id;
+
+ /* put it into both lists */
+ llist_add_tail(&map->hnb_list, &hnb->map_list);
+ llist_add_tail(&map->cn_list, &cn_if_new->map_list);
+ map->state = MAP_S_ACTIVE;
+
+ return map;
+}
+
+/* Map from a CN + Connection ID to HNB + Context ID */
+struct hnbgw_context_map *
+context_map_by_cn(struct hnbgw_cnlink *cn, uint32_t scu_conn_id)
+{
+ struct hnbgw_context_map *map;
+
+ /* FIXME: allocated HNB side ID! */
+
+ llist_for_each_entry(map, &cn->map_list, cn_list) {
+ if (map->state != MAP_S_ACTIVE)
+ continue;
+ if (map->scu_conn_id == scu_conn_id) {
+ return map;
+ }
+ }
+ /* we don't allocate new mappings in the CN->HNB
+ * direction, as the RUA=SCCP=SUA connections are always
+ * established from HNB towards CN. */
+ return NULL;
+}
+
+void context_map_deactivate(struct hnbgw_context_map *map)
+{
+ /* set the state to reserved. We still show up in the list and
+ * avoid re-allocation of the context-id until we are cleaned up
+ * by the context_map garbage collector timer */
+
+ if (map->state != MAP_S_RESERVED2)
+ map->state = MAP_S_RESERVED1;
+}
+
+static struct osmo_timer_list context_map_tmr;
+
+static void context_map_tmr_cb(void *data)
+{
+ struct hnb_gw *gw = data;
+ struct hnbgw_cnlink *cn;
+
+ /* iterate over list of core network (links) */
+ llist_for_each_entry(cn, &gw->cn_list, list) {
+ struct hnbgw_context_map *map;
+
+ llist_for_each_entry(map, &cn->map_list, cn_list) {
+ switch (map->state) {
+ case MAP_S_RESERVED1:
+ /* first time we see this reserved
+ * entry: mark it for stage 2 */
+ map->state = MAP_S_RESERVED2;
+ break;
+ case MAP_S_RESERVED2:
+ /* first time we see this reserved
+ * entry: remove it */
+ map->state = MAP_S_NULL;
+ llist_del(&map->cn_list);
+ llist_del(&map->hnb_list);
+ talloc_free(map);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ /* re-schedule this timer */
+ osmo_timer_schedule(&context_map_tmr, EXPIRY_TIMER_SECS, 0);
+}
+
+int context_map_init(struct hnb_gw *gw)
+{
+ context_map_tmr.cb = context_map_tmr_cb;
+ context_map_tmr.data = gw;
+ osmo_timer_schedule(&context_map_tmr, EXPIRY_TIMER_SECS, 0);
+}
diff --git a/src/context_map.h b/src/context_map.h
new file mode 100644
index 0000000..c1a4495
--- /dev/null
+++ b/src/context_map.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <stdint.h>
+#include <osmocom/core/linuxlist.h>
+
+enum hnbgw_context_map_state {
+ MAP_S_NULL,
+ MAP_S_ACTIVE, /* currently active map */
+ MAP_S_RESERVED1, /* just disconnected, still resrved */
+ MAP_S_RESERVED2, /* still reserved */
+};
+
+struct hnb_context;
+struct hnbgw_cnlink;
+
+struct hnbgw_context_map {
+ /* entry in the per-CN list of mappings */
+ struct llist_head cn_list;
+ /* entry in the per-HNB list of mappings */
+ struct llist_head hnb_list;
+ /* pointer to HNB */
+ struct hnb_context *hnb_ctx;
+ /* pointer to CN */
+ struct hnbgw_cnlink *cn_link;
+ /* RUA contxt ID */
+ uint32_t rua_ctx_id;
+ /* SCCP User SAP connection ID */
+ uint32_t scu_conn_id;
+
+ enum hnbgw_context_map_state state;
+};
+
+
+struct hnbgw_context_map *
+context_map_alloc_by_hnb(struct hnb_context *hnb, uint32_t rua_ctx_id,
+ struct hnbgw_cnlink *cn_if_new);
+
+struct hnbgw_context_map *
+context_map_by_cn(struct hnbgw_cnlink *cn, uint32_t scu_conn_id);
+
+void context_map_deactivate(struct hnbgw_context_map *map);
+
+int context_map_init(struct hnb_gw *gw);
diff --git a/src/hnbgw.c b/src/hnbgw.c
index 0dbe37d..bc8be99 100644
--- a/src/hnbgw.c
+++ b/src/hnbgw.c
@@ -53,6 +53,7 @@
#include "hnbgw.h"
#include "hnbgw_hnbap.h"
#include "hnbgw_rua.h"
+#include "context_map.h"
static void *tall_hnb_ctx;
static void *tall_ue_ctx;
@@ -210,6 +211,47 @@ static int hnb_write_cb(struct osmo_fd *fd, struct msgb *msg)
return rc;
}
+struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, int new_fd)
+{
+ struct hnb_context *ctx;
+
+ ctx = talloc_zero(tall_hnb_ctx, struct hnb_context);
+ if (!ctx)
+ return NULL;
+
+ ctx->gw = gw;
+ osmo_wqueue_init(&ctx->wqueue, 16);
+ ctx->wqueue.bfd.data = ctx;
+ ctx->wqueue.bfd.fd = new_fd;
+ ctx->wqueue.bfd.when = BSC_FD_READ;
+ ctx->wqueue.read_cb = hnb_read_cb;
+ ctx->wqueue.write_cb = hnb_write_cb;
+ osmo_fd_register(&ctx->wqueue.bfd);
+
+ llist_add_tail(&ctx->list, &gw->hnb_list);
+}
+
+void hnb_context_release(struct hnb_context *ctx)
+{
+ struct hnbgw_context_map *map, *map2;
+
+ /* remove from the list of HNB contexts */
+ llist_del(&ctx->list);
+
+ /* deactivate all context maps */
+ llist_for_each_entry_safe(map, map2, &ctx->map_list, hnb_list) {
+ /* remove it from list, as HNB context will soon be
+ * gone. Let's hope the seccond osmo_llist_del in the
+ * map garbage collector wors fine? */
+ llist_del(&map->hnb_list);
+ context_map_deactivate(map);
+ }
+ /* FIXME: flush write queue items */
+ osmo_fd_unregister(&ctx->wqueue.bfd);
+
+ talloc_free(ctx);
+}
+
/*! call-back when the listen FD has something to read */
static int listen_fd_cb(struct osmo_fd *fd, unsigned int what)
{
@@ -226,21 +268,10 @@ static int listen_fd_cb(struct osmo_fd *fd, unsigned int what)
LOGP(DMAIN, LOGL_INFO, "SCTP Connection accept()ed\n");
- ctx = talloc_zero(tall_hnb_ctx, struct hnb_context);
+ ctx = hnb_context_alloc(gw, new_fd);
if (!ctx)
return -ENOMEM;
- ctx->gw = gw;
- osmo_wqueue_init(&ctx->wqueue, 16);
- ctx->wqueue.bfd.data = ctx;
- ctx->wqueue.bfd.fd = new_fd;
- ctx->wqueue.bfd.when = BSC_FD_READ;
- ctx->wqueue.read_cb = hnb_read_cb;
- ctx->wqueue.write_cb = hnb_write_cb;
- osmo_fd_register(&ctx->wqueue.bfd);
-
- llist_add_tail(&ctx->list, &gw->hnb_list);
-
return 0;
}
@@ -380,6 +411,8 @@ int main(int argc, char **argv)
INIT_LLIST_HEAD(&g_hnb_gw.hnb_list);
INIT_LLIST_HEAD(&g_hnb_gw.ue_list);
+ context_map_init(&g_hnb_gw);
+
rc = osmo_init_logging(&hnbgw_log_info);
if (rc < 0)
exit(1);
diff --git a/src/hnbgw.h b/src/hnbgw.h
index fede5ee..0509415 100644
--- a/src/hnbgw.h
+++ b/src/hnbgw.h
@@ -3,10 +3,13 @@
#include <osmocom/core/select.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/write_queue.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/sigtran/sccp_sap.h>
#define DEBUG
#include <osmocom/core/logging.h>
+
enum {
DMAIN,
DHNBAP,
@@ -39,6 +42,37 @@ struct umts_cell_id {
struct hnb_gw;
+enum hnbgw_cnlink_state {
+ /* we have just been initialized or were disconnected */
+ CNLINK_S_NULL,
+ /* establishment of the SUA/SCCP link is pending */
+ CNLINK_S_EST_PEND,
+ /* establishment of the SUA/SCCP link was confirmed */
+ CNLINK_S_EST_CONF,
+ /* we have esnt the RANAP RESET and wait for the ACK */
+ CNLINK_S_EST_RST_TX_WAIT_ACK,
+ /* we have received the RANAP RESET ACK and are active */
+ CNLINK_S_EST_ACTIVE,
+};
+
+struct hnbgw_cnlink {
+ struct llist_head list;
+ enum hnbgw_cnlink_state state;
+ struct hnb_gw *gw;
+ /* are we a PS connection (1) or CS (0) */
+ int is_ps;
+ /* timer for re-transmitting the RANAP Reset */
+ struct osmo_timer_list T_RafC;
+ /* reference to the SCCP User SAP by which we communicate */
+ struct osmo_sua_link *sua_link;
+ struct osmo_sccp_addr local_addr;
+ struct osmo_sccp_addr remote_addr;
+ uint32_t next_conn_id;
+
+ /* linked list of hnbgw_context_map */
+ struct llist_head map_list;
+};
+
struct hnb_context {
/*! Entry in HNB-global list of HNB */
struct llist_head list;
@@ -55,6 +89,9 @@ struct hnb_context {
uint16_t hnbap_stream;
/*! SCTP stream ID for RUA */
uint16_t rua_stream;
+
+ /* linked list of hnbgw_context_map */
+ struct llist_head map_list;
};
struct ue_context {
@@ -80,6 +117,7 @@ struct hnb_gw {
struct osmo_fd listen_fd;
struct llist_head hnb_list;
struct llist_head ue_list;
+ struct llist_head cn_list;
uint32_t next_ue_ctx_id;
};
@@ -89,3 +127,6 @@ struct ue_context *ue_context_by_id(uint32_t id);
struct ue_context *ue_context_by_imsi(const char *imsi);
struct ue_context *ue_context_alloc(struct hnb_context *hnb, const char *imsi);
void ue_context_free(struct ue_context *ue);
+
+struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, int new_fd);
+void hnb_context_release(struct hnb_context *ctx);