immediately SCCP RLSD on HNB re-register

The RUA side may disconnect
a) gracefully (RUA Disconnect with RANAP IU Release Complete) or
b) by detecting that the HNB is gone / has restarted

For a), the SCCP side waits for a RLSD from the CN that follows the IU
Release Complete.
For b), we so far also wait for a RLSD from CN, which will never come,
and only after a timeout send an SCCP RLSD to the CN.

Instead, for b), immediately send an SCCP RLSD.

To distinguish between the graceful release (a) and the disruptive
release (b), add new state MAP_RUA_ST_DISRUPTED on the RUA side,
and add new event MAP_SCCP_EV_RAN_LINK_LOST for the SCCP side.

Any non-graceful disconnect of RUA enters ST_DISRUPTED.
disrupted_onenter() dispatches EV_RAN_LINK_LOST to SCCP,
and SCCP directly sends RLSD to the CN without timeout.

These changes are also shown in doc/charts/hnbgw_context_map.msc.

Change-Id: I4e78617ad39bb73fe92097c8a1a8069da6a7f6a1
This commit is contained in:
Neels Hofmeyr 2023-04-15 17:50:05 +02:00
parent e966e73fd2
commit aa99546d23
4 changed files with 65 additions and 15 deletions

View File

@ -65,7 +65,7 @@ msc {
sccp abox sccp [label="MAP_SCCP_ST_DISCONNECTED"];
rua <= sccp [label="MAP_RUA_EV_CN_DISC"];
hnb <= rua [label="RUA Disconnect"];
rua abox rua [label="MAP_RUA_ST_DISCONNECTED"];
rua abox rua [label="MAP_RUA_ST_DISRUPTED"];
rua rbox sccp [label="map_check_released()"];
rua rbox sccp [label="hnbgw_context_map_free()"];
@ -81,10 +81,10 @@ msc {
--- [label="Ungraceful release from HNB"];
hnb -x rua [label="link loss"];
rua rbox rua [label="MAP_RUA_EV_HNB_LINK_LOST"];
rua => sccp [label="MAP_SCCP_EV_RAN_DISC"];
rua abox rua [label="MAP_RUA_ST_DISRUPTED"];
rua => sccp [label="MAP_SCCP_EV_RAN_LINK_LOST"];
sccp => cn [label="SCCP Released"];
sccp abox sccp [label="MAP_SCCP_ST_DISCONNECTED"];
rua abox rua [label="MAP_RUA_ST_DISCONNECTED"];
rua rbox sccp [label="map_check_released()"];
rua rbox sccp [label="hnbgw_context_map_free()"];
@ -98,10 +98,8 @@ msc {
rua rbox rua [label="MAP_RUA_EV_HNB_LINK_LOST"];
hnb <= rua [label="RUA Disconnect"];
hnb note rua [label="TODO: does it make sense to send\nRUA Disconnect per context when HNB is/was gone?\nOr has the HNB implicitly discarded these?"];
rua abox rua [label="MAP_RUA_ST_DISCONNECTED"];
rua => sccp [label="MAP_SCCP_EV_RAN_DISC\nfrom map_rua_disconnected_onenter()"];
sccp abox sccp [label="MAP_SCCP_ST_WAIT_RLSD"];
rua => sccp [label="MAP_SCCP_EV_RAN_DISC\nto skip waiting for SCCP Released from CN"];
rua abox rua [label="MAP_RUA_ST_DISRUPTED"];
rua => sccp [label="MAP_SCCP_EV_RAN_LINK_LOST\nfrom map_rua_disrupted_onenter()"];
sccp => cn [label="SCCP Released"];
sccp abox sccp [label="MAP_SCCP_ST_DISCONNECTED"];
rua rbox sccp [label="map_check_released()"];

View File

@ -51,6 +51,8 @@ enum map_sccp_fsm_event {
* CN should have received an Iu-ReleaseComplete with or before this, give CN a chance to send an SCCP RLSD;
* after a timeout we will send a non-standard RLSD to the CN instead. */
MAP_SCCP_EV_RAN_DISC,
/* The RAN released ungracefully. We will directly disconnect the SCCP connection, too. */
MAP_SCCP_EV_RAN_LINK_LOST,
/* Receiving an SCCP RLSD from CN, or libosmo-sigtran tells us about SCCP connection timeout. All done. */
MAP_SCCP_EV_RX_RELEASED,
};

View File

@ -41,6 +41,7 @@ enum map_rua_fsm_state {
MAP_RUA_ST_INIT,
MAP_RUA_ST_CONNECTED,
MAP_RUA_ST_DISCONNECTED,
MAP_RUA_ST_DISRUPTED,
};
static const struct value_string map_rua_fsm_event_names[] = {
@ -58,6 +59,7 @@ static struct osmo_fsm map_rua_fsm;
static const struct osmo_tdef_state_timeout map_rua_fsm_timeouts[32] = {
[MAP_RUA_ST_INIT] = { .T = -31 },
[MAP_RUA_ST_DISCONNECTED] = { .T = -31 },
[MAP_RUA_ST_DISRUPTED] = { .T = -31 },
};
/* Transition to a state, using the T timer defined in map_rua_fsm_timeouts.
@ -93,6 +95,7 @@ enum hnbgw_context_map_state map_rua_get_state(struct hnbgw_context_map *map)
return MAP_S_ACTIVE;
default:
case MAP_RUA_ST_DISCONNECTED:
case MAP_RUA_ST_DISRUPTED:
return MAP_S_DISCONNECTING;
}
}
@ -103,6 +106,7 @@ bool map_rua_is_active(struct hnbgw_context_map *map)
return false;
switch (map->rua_fi->state) {
case MAP_RUA_ST_DISCONNECTED:
case MAP_RUA_ST_DISRUPTED:
return false;
default:
return true;
@ -114,10 +118,11 @@ static int map_rua_fsm_timer_cb(struct osmo_fsm_inst *fi)
/* Return 1 to terminate FSM instance, 0 to keep running */
switch (fi->state) {
default:
map_rua_fsm_state_chg(MAP_RUA_ST_DISCONNECTED);
map_rua_fsm_state_chg(MAP_RUA_ST_DISRUPTED);
return 0;
case MAP_RUA_ST_DISCONNECTED:
case MAP_RUA_ST_DISRUPTED:
return 1;
}
}
@ -210,8 +215,6 @@ static void map_rua_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *
return;
case MAP_RUA_EV_RX_DISCONNECT:
case MAP_RUA_EV_CN_DISC:
case MAP_RUA_EV_HNB_LINK_LOST:
/* Unlikely that SCCP is active, but let the SCCP FSM decide about that. */
handle_rx_rua(fi, ranap_msg);
/* There is a reason to shut down this RUA connection. Super unlikely, we haven't even processed the
@ -220,6 +223,11 @@ static void map_rua_init_action(struct osmo_fsm_inst *fi, uint32_t event, void *
map_rua_fsm_state_chg(MAP_RUA_ST_DISCONNECTED);
break;
case MAP_RUA_EV_CN_DISC:
case MAP_RUA_EV_HNB_LINK_LOST:
map_rua_fsm_state_chg(MAP_RUA_ST_DISRUPTED);
break;
default:
OSMO_ASSERT(false);
}
@ -276,14 +284,14 @@ static void map_rua_connected_action(struct osmo_fsm_inst *fi, uint32_t event, v
case MAP_RUA_EV_HNB_LINK_LOST:
/* The HNB is gone. Cannot gracefully cleanup the RUA connection, just be gone. */
map_rua_fsm_state_chg(MAP_RUA_ST_DISCONNECTED);
map_rua_fsm_state_chg(MAP_RUA_ST_DISRUPTED);
return;
case MAP_RUA_EV_CN_DISC:
/* There is a disruptive reason to shut down this RUA connection, HNB is still there */
OSMO_ASSERT(data == NULL);
map_rua_tx_disconnect(fi);
map_rua_fsm_state_chg(MAP_RUA_ST_DISCONNECTED);
map_rua_fsm_state_chg(MAP_RUA_ST_DISRUPTED);
return;
default:
@ -291,23 +299,35 @@ static void map_rua_connected_action(struct osmo_fsm_inst *fi, uint32_t event, v
}
}
static void map_rua_disconnected_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
static void map_rua_free_if_done(struct hnbgw_context_map *map, uint32_t sccp_event)
{
struct hnbgw_context_map *map = fi->priv;
/* From RUA's POV, we can now free the hnbgw_context_map.
* If SCCP is still active, tell it to disconnect -- in that case the SCCP side will call context_map_free().
* If SCCP is no longer active, free this map. */
if (map_sccp_is_active(map))
map_sccp_dispatch(map, MAP_SCCP_EV_RAN_DISC, NULL);
map_sccp_dispatch(map, sccp_event, NULL);
else
context_map_free(map);
}
static void map_rua_disconnected_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct hnbgw_context_map *map = fi->priv;
map_rua_free_if_done(map, MAP_SCCP_EV_RAN_DISC);
}
static void map_rua_disconnected_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct msgb *ranap_msg = data;
if (msg_has_l2_data(ranap_msg))
LOGPFSML(fi, LOGL_ERROR, "RUA not connected, cannot dispatch RANAP message\n");
/* Ignore all events. */
}
static void map_rua_disrupted_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct hnbgw_context_map *map = fi->priv;
map_rua_free_if_done(map, MAP_SCCP_EV_RAN_LINK_LOST);
}
void map_rua_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
@ -331,6 +351,7 @@ static const struct osmo_fsm_state map_rua_fsm_states[] = {
| S(MAP_RUA_ST_INIT)
| S(MAP_RUA_ST_CONNECTED)
| S(MAP_RUA_ST_DISCONNECTED)
| S(MAP_RUA_ST_DISRUPTED)
,
.action = map_rua_init_action,
},
@ -345,6 +366,7 @@ static const struct osmo_fsm_state map_rua_fsm_states[] = {
,
.out_state_mask = 0
| S(MAP_RUA_ST_DISCONNECTED)
| S(MAP_RUA_ST_DISRUPTED)
,
.action = map_rua_connected_action,
},
@ -357,6 +379,16 @@ static const struct osmo_fsm_state map_rua_fsm_states[] = {
.onenter = map_rua_disconnected_onenter,
.action = map_rua_disconnected_action,
},
[MAP_RUA_ST_DISRUPTED] = {
.name = "disrupted",
.in_event_mask = 0
| S(MAP_RUA_EV_CN_DISC)
| S(MAP_RUA_EV_HNB_LINK_LOST)
,
.onenter = map_rua_disrupted_onenter,
/* same as MAP_RUA_ST_DISCONNECTED: */
.action = map_rua_disconnected_action,
},
};
static struct osmo_fsm map_rua_fsm = {

View File

@ -52,6 +52,7 @@ static const struct value_string map_sccp_fsm_event_names[] = {
OSMO_VALUE_STRING(MAP_SCCP_EV_RX_DATA_INDICATION),
OSMO_VALUE_STRING(MAP_SCCP_EV_TX_DATA_REQUEST),
OSMO_VALUE_STRING(MAP_SCCP_EV_RAN_DISC),
OSMO_VALUE_STRING(MAP_SCCP_EV_RAN_LINK_LOST),
OSMO_VALUE_STRING(MAP_SCCP_EV_RX_RELEASED),
{}
};
@ -262,6 +263,7 @@ static void map_sccp_init_action(struct osmo_fsm_inst *fi, uint32_t event, void
map_sccp_fsm_state_chg(MAP_SCCP_ST_WAIT_CC);
return;
case MAP_SCCP_EV_RAN_LINK_LOST:
case MAP_SCCP_EV_RAN_DISC:
/* No CR has been sent yet, just go to disconnected state. */
if (msg_has_l2_data(ranap_msg))
@ -297,6 +299,7 @@ static void map_sccp_wait_cc_action(struct osmo_fsm_inst *fi, uint32_t event, vo
LOGPFSML(fi, LOGL_ERROR, "Connection not yet confirmed, cannot forward RANAP to CN\n");
return;
case MAP_SCCP_EV_RAN_LINK_LOST:
case MAP_SCCP_EV_RAN_DISC:
/* RUA connection was terminated. First wait for the CC before releasing the SCCP conn. */
if (msg_has_l2_data(ranap_msg))
@ -351,6 +354,16 @@ static void map_sccp_connected_action(struct osmo_fsm_inst *fi, uint32_t event,
tx_sccp_df1(fi, ranap_msg);
return;
case MAP_SCCP_EV_RAN_LINK_LOST:
/* RUA has disconnected ungracefully, so there is no Iu Release that told the CN to disconnect.
* Disconnect on the SCCP layer, ungracefully. */
/* There won't be any ranap_msg, but if a caller wants to dispatch a msg, forward it before
* disconnecting. */
tx_sccp_df1(fi, ranap_msg);
tx_sccp_rlsd(fi);
map_sccp_fsm_state_chg(MAP_SCCP_ST_DISCONNECTED);
return;
case MAP_SCCP_EV_RX_RELEASED:
/* The CN sends an N-Disconnect (SCCP Released) out of the usual sequence. Not what we expected, but
* handle it. */
@ -480,6 +493,7 @@ static const struct osmo_fsm_state map_sccp_fsm_states[] = {
.in_event_mask = 0
| S(MAP_SCCP_EV_TX_DATA_REQUEST)
| S(MAP_SCCP_EV_RAN_DISC)
| S(MAP_SCCP_EV_RAN_LINK_LOST)
| S(MAP_SCCP_EV_RX_RELEASED)
,
.out_state_mask = 0
@ -495,6 +509,7 @@ static const struct osmo_fsm_state map_sccp_fsm_states[] = {
| S(MAP_SCCP_EV_RX_CONNECTION_CONFIRM)
| S(MAP_SCCP_EV_TX_DATA_REQUEST)
| S(MAP_SCCP_EV_RAN_DISC)
| S(MAP_SCCP_EV_RAN_LINK_LOST)
| S(MAP_SCCP_EV_RX_RELEASED)
,
.out_state_mask = 0
@ -509,6 +524,7 @@ static const struct osmo_fsm_state map_sccp_fsm_states[] = {
| S(MAP_SCCP_EV_RX_DATA_INDICATION)
| S(MAP_SCCP_EV_TX_DATA_REQUEST)
| S(MAP_SCCP_EV_RAN_DISC)
| S(MAP_SCCP_EV_RAN_LINK_LOST)
| S(MAP_SCCP_EV_RX_RELEASED)
| S(MAP_SCCP_EV_RX_CONNECTION_CONFIRM)
,
@ -526,6 +542,7 @@ static const struct osmo_fsm_state map_sccp_fsm_states[] = {
| S(MAP_SCCP_EV_RX_DATA_INDICATION)
| S(MAP_SCCP_EV_TX_DATA_REQUEST)
| S(MAP_SCCP_EV_RAN_DISC)
| S(MAP_SCCP_EV_RAN_LINK_LOST)
| S(MAP_SCCP_EV_RX_CONNECTION_CONFIRM)
,
.out_state_mask = 0
@ -539,6 +556,7 @@ static const struct osmo_fsm_state map_sccp_fsm_states[] = {
.in_event_mask = 0
| S(MAP_SCCP_EV_TX_DATA_REQUEST)
| S(MAP_SCCP_EV_RAN_DISC)
| S(MAP_SCCP_EV_RAN_LINK_LOST)
,
.onenter = map_sccp_disconnected_onenter,
.action = map_sccp_disconnected_action,