Add a context mapper to map RUA ContextIDs <-> SUA Connection IDs
This commit is contained in:
parent
f42317ba9c
commit
90256bad58
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
57
src/hnbgw.c
57
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);
|
||||
|
|
41
src/hnbgw.h
41
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);
|
||||
|
|
Loading…
Reference in New Issue