Add a context mapper to map RUA ContextIDs <-> SUA Connection IDs

This commit is contained in:
Harald Welte 2015-12-23 20:16:36 +01:00
parent f42317ba9c
commit 90256bad58
5 changed files with 294 additions and 13 deletions

View File

@ -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

164
src/context_map.c Normal file
View File

@ -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);
}

43
src/context_map.h Normal file
View File

@ -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);

View File

@ -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);

View File

@ -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);