fix SCCP conn leak on non-graceful HNB shutdown

Clean up SCCP connections when a HNB disconnects.

When a HNB disconnects, we clean up all RUA <-> SCCP connection state
for that HNB. In that cleanup, discarding the SCCP connection is so far

Add a flag indicating true between SCCP CC and DISCONNECT. Hence we can
tell during context_map_deactivate() whether the cleanup is graceful
(DISCONNECT already sent) or non-graceful (need to DISCONNECT).

Change-Id: Icc2db9f6c0b2d0a814ff1110ffbe5e8f7f629222
Neels Hofmeyr 4 months ago
parent 07d01d50a5
commit 87ecf69b55

@ -43,6 +43,10 @@ struct hnbgw_context_map {
bool is_ps;
/* SCCP User SAP connection ID */
uint32_t scu_conn_id;
/* Set to true on SCCP Conn Conf, set to false when an OSMO_SCU_PRIM_N_DISCONNECT has been sent for the SCCP
* User SAP conn. Useful to avoid leaking SCCP connections: guarantee that an OSMO_SCU_PRIM_N_DISCONNECT gets
* sent, even when RUA fails to gracefully disconnect. */
bool scu_conn_active;
/* Pending data to be sent: when we send an "empty" SCCP CR first, the initial RANAP message will be sent in a
* separate DT once the CR is confirmed. This caches the initial RANAP message. */
struct msgb *cached_msg;

@ -26,6 +26,8 @@
#include <osmocom/core/timer.h>
#include <osmocom/sigtran/sccp_helpers.h>
#include <osmocom/hnbgw/hnbgw.h>
#include <osmocom/hnbgw/hnbgw_rua.h>
#include <osmocom/hnbgw/context_map.h>
@ -174,6 +176,12 @@ void context_map_deactivate(struct hnbgw_context_map *map)
if (map->state != MAP_S_RESERVED2)
map->state = MAP_S_RESERVED1;
/* Is SCCP still active and needs to be disconnected ungracefully? */
if (map->scu_conn_active) {
osmo_sccp_tx_disconn(map->hnb_ctx->gw->sccp.cnlink->sccp_user, map->scu_conn_id, NULL, 0);
map->scu_conn_active = false;
/* a possibly still existing MGW FSM must be terminated when the context
* map is deactivated. (this is a cornercase) */
if (map->mgw_fi) {

@ -337,6 +337,8 @@ static int handle_cn_conn_conf(struct hnbgw_cnlink *cnlink,
struct osmo_prim_hdr *oph)
struct osmo_ss7_instance *ss7 = osmo_sccp_get_ss7(cnlink->gw->sccp.client);
struct hnbgw_context_map *map;
LOGP(DMAIN, LOGL_DEBUG, "handle_cn_conn_conf() conn_id=%d, addrs: called=%s calling=%s responding=%s\n",
osmo_sccp_addr_to_str_c(OTC_SELECT, ss7, &param->called_addr),
@ -346,9 +348,17 @@ static int handle_cn_conn_conf(struct hnbgw_cnlink *cnlink,
/* Nothing needs to happen for RUA, RUA towards the HNB doesn't seem to know any confirmations to its CONNECT
* operation. */
map = context_map_by_cn(cnlink, param->conn_id);
if (!map)
return 0;
/* SCCP connection is confirmed. Mark conn as active, i.e. requires a DISCONNECT to clean up the SCCP
* connection. */
map->scu_conn_active = true;
/* If our initial SCCP CR was sent without data payload, then the initial RANAP message is cached and waiting to
* be sent as soon as the SCCP connection is confirmed. See if that is the case, send cached data. */
context_map_send_cached_msg(context_map_by_cn(cnlink, param->conn_id));
return 0;

@ -252,6 +252,9 @@ int rua_to_scu(struct hnb_context *hnb,
prim->u.disconnect.conn_id = map->scu_conn_id;
prim->u.disconnect.cause = cause;
release_context_map = true;
/* Mark SCCP conn as gracefully disconnected */
if (map)
map->scu_conn_active = false;
prim->u.unitdata.called_addr = *remote_addr;