pespin has uploaded this change for review.

View Change

Introduce iu_rnc FSM

This FSM is similar to the already existing ran_peer_fsm in osmo-msc,
which already had better logic around SCCP and RANAP state handling.
Similarly, osmo-sgsn's struct ranap_iu_rnc maps to osmo-msc's struct ran_peer.

With this FSM we can currently track the RANAP link state towards a given
RNC peer:
* Reject (RANAP Error Indication) all UE-related messages until a RANAP
RESET from RNC is received first.
* Tear down all subsriber connections whenever the RANAP peer sends us a
RESET message.
* Tear down all subscriber connections whenever the SCCP link towards
RNC becomes unavailable.
* Send a RESET towards RNC peer once the SCCP link towrdards it becomes
available again.

This commit only implements so far the Rx path of the FSM, ie. when
receiving events/messages from a peer over SCCP and pushing them locally
up the stack (RANAP). The Tx side will be implemented in a follow-up
commit, which will allow discarding messages if the lower layers towards
a given RNC are known to be down.

Change-Id: I18b7803500163e78ff6a684095194174b0fb6ee1
---
M include/osmocom/sgsn/Makefile.am
M include/osmocom/sgsn/gprs_ranap.h
M include/osmocom/sgsn/iu_rnc.h
A include/osmocom/sgsn/iu_rnc_fsm.h
M include/osmocom/sgsn/sccp.h
M include/osmocom/sgsn/sgsn.h
M src/sgsn/Makefile.am
M src/sgsn/gprs_ranap.c
M src/sgsn/iu_rnc.c
A src/sgsn/iu_rnc_fsm.c
M src/sgsn/sccp.c
M src/sgsn/sgsn.c
M src/sgsn/sgsn_vty.c
M tests/gprs_routing_area/Makefile.am
M tests/osmo-sgsn_test-nodes.vty
M tests/sgsn/Makefile.am
16 files changed, 593 insertions(+), 95 deletions(-)

git pull ssh://gerrit.osmocom.org:29418/osmo-sgsn refs/changes/88/40988/1
diff --git a/include/osmocom/sgsn/Makefile.am b/include/osmocom/sgsn/Makefile.am
index 342b568..9c50618 100644
--- a/include/osmocom/sgsn/Makefile.am
+++ b/include/osmocom/sgsn/Makefile.am
@@ -29,6 +29,7 @@
gtp_mme.h \
iu_client.h \
iu_rnc.h \
+ iu_rnc_fsm.h \
mmctx.h \
pdpctx.h \
sccp.h \
diff --git a/include/osmocom/sgsn/gprs_ranap.h b/include/osmocom/sgsn/gprs_ranap.h
index 3c4f593..62914ba 100644
--- a/include/osmocom/sgsn/gprs_ranap.h
+++ b/include/osmocom/sgsn/gprs_ranap.h
@@ -13,6 +13,15 @@
struct sgsn_mm_ctx;
struct sgsn_pdp_ctx;

+/* struct RANAP_GlobalRNC_ID with a coupled buffer where .buf points to.
+ * Used to easily generate a struct RANAP_GlobalRNC_ID to encode,
+ * see sgsn_ranap_iu_grnc_id_compose(). */
+struct iu_grnc_id {
+ uint8_t plmn_buf[3];
+ struct RANAP_GlobalRNC_ID grnc_id;
+};
+int sgsn_ranap_iu_grnc_id_compose(struct iu_grnc_id *dst, const struct osmo_rnc_id *src);
+
int sgsn_ranap_iu_event(struct ranap_ue_conn_ctx *ctx, enum ranap_iu_event_type type, void *data);

int sgsn_ranap_iu_tx(struct msgb *msg, uint8_t sapi);
@@ -40,6 +49,12 @@
const struct osmo_sccp_addr *dst_addr,
const RANAP_Cause_t *cause);

+void sgsn_ranap_iu_handle_co_initial(struct ranap_iu_rnc *iu_rnc,
+ uint32_t conn_id,
+ const ranap_message *message);
+void sgsn_ranap_iu_handle_co(struct ranap_ue_conn_ctx *ue_ctx, const ranap_message *message);
+
+/* Entry points from rx SCCP: */
int sgsn_ranap_iu_rx_cl_msg(struct sgsn_sccp_user_iups *scu_iups,
const struct osmo_scu_unitdata_param *ud_prim,
const uint8_t *data, size_t len);
diff --git a/include/osmocom/sgsn/iu_rnc.h b/include/osmocom/sgsn/iu_rnc.h
index 9bdb559..b0e5be3 100644
--- a/include/osmocom/sgsn/iu_rnc.h
+++ b/include/osmocom/sgsn/iu_rnc.h
@@ -4,6 +4,7 @@

#include <osmocom/core/defs.h>
#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/fsm.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/iuh/common.h>
#include <osmocom/sigtran/sccp_sap.h>
@@ -26,6 +27,7 @@
struct osmo_rnc_id rnc_id;
struct sgsn_sccp_user_iups *scu_iups;
struct osmo_sccp_addr sccp_addr;
+ struct osmo_fsm_inst *fi;

/* A list of struct iu_lac_rac_entry */
struct llist_head lac_rac_list;
@@ -34,6 +36,15 @@
struct ranap_iu_rnc *iu_rnc_find_or_create(const struct osmo_rnc_id *rnc_id,
struct sgsn_sccp_user_iups *scu_iups,
const struct osmo_sccp_addr *addr);
+
+struct ranap_iu_rnc *iu_rnc_find_by_addr(const struct osmo_sccp_addr *rnc_sccp_addr);
+
void iu_rnc_update_rai_seen(struct ranap_iu_rnc *rnc, const struct osmo_routing_area_id *rai);

void iu_rnc_discard_all_ue_ctx(struct ranap_iu_rnc *rnc);
+
+#define LOG_RNC_CAT(IU_RNC, subsys, loglevel, fmt, args ...) \
+ LOGPFSMSL((IU_RNC)->fi, subsys, loglevel, fmt, ## args)
+
+#define LOG_RNC(IU_RNC, loglevel, fmt, args ...) \
+ LOG_RNC_CAT(IU_RNC, DRANAP, loglevel, fmt, ## args)
diff --git a/include/osmocom/sgsn/iu_rnc_fsm.h b/include/osmocom/sgsn/iu_rnc_fsm.h
new file mode 100644
index 0000000..d9be576
--- /dev/null
+++ b/include/osmocom/sgsn/iu_rnc_fsm.h
@@ -0,0 +1,36 @@
+#include <stdint.h>
+
+#include <osmocom/core/fsm.h>
+
+#include <osmocom/ranap/ranap_ies_defs.h>
+
+struct ranap_iu_rnc;
+
+enum iu_rnc_state {
+ IU_RNC_ST_WAIT_RX_RESET = 0,
+ IU_RNC_ST_WAIT_RX_RESET_ACK,
+ IU_RNC_ST_READY,
+ IU_RNC_ST_DISCARDING,
+};
+
+struct iu_rnc_ev_msg_up_co_initial_ctx {
+ struct ranap_iu_rnc *rnc;
+ uint32_t conn_id;
+ ranap_message message;
+};
+
+struct iu_rnc_ev_msg_up_co_ctx {
+ struct ranap_ue_conn_ctx *ue_ctx;
+ ranap_message message;
+};
+
+enum iu_rnc_event {
+ IU_RNC_EV_MSG_UP_CO_INITIAL, /* struct iu_rnc_ev_msg_up_co_initial_ctx* */
+ IU_RNC_EV_MSG_UP_CO, /* struct iu_rnc_ev_msg_up_co_ctx* */
+ IU_RNC_EV_RX_RESET, /* no param */
+ IU_RNC_EV_RX_RESET_ACK, /* no param */
+ IU_RNC_EV_AVAILABLE,
+ IU_RNC_EV_UNAVAILABLE
+};
+
+extern struct osmo_fsm iu_rnc_fsm;
diff --git a/include/osmocom/sgsn/sccp.h b/include/osmocom/sgsn/sccp.h
index 67388a4..0c05f15 100644
--- a/include/osmocom/sgsn/sccp.h
+++ b/include/osmocom/sgsn/sccp.h
@@ -23,6 +23,7 @@
#include <osmocom/sigtran/sccp_sap.h>

struct sgsn_instance;
+struct ranap_ue_conn_ctx;

struct sgsn_sccp_user_iups {
struct sgsn_instance *sgsn; /* backpointer */
diff --git a/include/osmocom/sgsn/sgsn.h b/include/osmocom/sgsn/sgsn.h
index 7d323ed..8fc97b0 100644
--- a/include/osmocom/sgsn/sgsn.h
+++ b/include/osmocom/sgsn/sgsn.h
@@ -180,6 +180,7 @@
#endif /* if BUILD_IU */
};

+extern struct osmo_tdef sgsn_T_defs[];
extern struct sgsn_instance *sgsn;
extern void *tall_sgsn_ctx;

diff --git a/src/sgsn/Makefile.am b/src/sgsn/Makefile.am
index fdad7dc..e64fe94 100644
--- a/src/sgsn/Makefile.am
+++ b/src/sgsn/Makefile.am
@@ -99,6 +99,7 @@
gprs_ranap.c \
iu_client.c \
iu_rnc.c \
+ iu_rnc_fsm.c \
sccp.c \
$(NULL)

diff --git a/src/sgsn/gprs_ranap.c b/src/sgsn/gprs_ranap.c
index d05cc7b..df9cc9e 100644
--- a/src/sgsn/gprs_ranap.c
+++ b/src/sgsn/gprs_ranap.c
@@ -29,6 +29,7 @@

#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/tdef.h>
+#include <osmocom/gsm/gsm23003.h>
#include <osmocom/gprs/gprs_msgb.h>

#include <osmocom/ranap/ranap_common.h>
@@ -49,17 +50,13 @@
#include <osmocom/sgsn/gtp_ggsn.h>
#include <osmocom/sgsn/gtp.h>
#include <osmocom/sgsn/iu_rnc.h>
+#include <osmocom/sgsn/iu_rnc_fsm.h>
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/mmctx.h>

/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the
* PLMN identity is a BCD representation of the MCC and MNC.
* See iu_grnc_id_parse(). */
-struct iu_grnc_id {
- struct osmo_plmn_id plmn;
- uint16_t rnc_id;
-};
-
static int iu_grnc_id_parse(struct osmo_rnc_id *dst, const struct RANAP_GlobalRNC_ID *src)
{
/* The size is coming from arbitrary sender, check it gracefully */
@@ -73,18 +70,15 @@
return 0;
}

-#if 0
/* not used at present */
-static int iu_grnc_id_compose(struct iu_grnc_id *src, struct RANAP_GlobalRNC_ID *dst)
+int sgsn_ranap_iu_grnc_id_compose(struct iu_grnc_id *dst, const struct osmo_rnc_id *src)
{
- /* The caller must ensure proper size */
- OSMO_ASSERT(dst->pLMNidentity.size == 3);
- gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0],
- src->mcc, src->mnc);
- dst->rNC_ID = src->rnc_id;
+ dst->grnc_id.pLMNidentity.buf = &dst->plmn_buf[0];
+ dst->grnc_id.pLMNidentity.size = 3;
+ osmo_plmn_to_bcd(dst->grnc_id.pLMNidentity.buf, &src->plmn);
+ dst->grnc_id.rNC_ID = src->rnc_id;
return 0;
}
-#endif

/* Callback for RAB assignment response */
static int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
@@ -385,8 +379,7 @@
osmo_timer_schedule(&ctx->release_timeout, timeout, 0);
}

-static int ranap_handle_co_initial_ue(struct sgsn_sccp_user_iups *scu_iups,
- const struct osmo_sccp_addr *rem_sccp_addr,
+static int ranap_handle_co_initial_ue(struct ranap_iu_rnc *rnc,
uint32_t conn_id,
const RANAP_InitialUE_MessageIEs_t *ies)
{
@@ -396,7 +389,6 @@
uint16_t sai;
struct ranap_ue_conn_ctx *ue;
struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
- struct ranap_iu_rnc *rnc;

if (ranap_parse_lai(&ra_id, &ies->lai) != 0) {
LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
@@ -427,9 +419,7 @@

gprs_rai_to_osmo(&ra_id2, &ra_id);

- /* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */
- rnc = iu_rnc_find_or_create(&rnc_id, scu_iups, rem_sccp_addr);
- OSMO_ASSERT(rnc);
+ /* Make sure we update LAC+RAC coming in on this connection. */
iu_rnc_update_rai_seen(rnc, &ra_id2);

ue = ue_conn_ctx_alloc(rnc, conn_id);
@@ -445,10 +435,9 @@
return 0;
}

-static void cn_ranap_handle_co_initial(struct sgsn_sccp_user_iups *scu_iups,
- const struct osmo_sccp_addr *rem_sccp_addr,
- uint32_t conn_id,
- const ranap_message *message)
+void sgsn_ranap_iu_handle_co_initial(struct ranap_iu_rnc *iu_rnc,
+ uint32_t conn_id,
+ const ranap_message *message)
{
int rc;

@@ -461,7 +450,7 @@
message->direction, message->procedureCode);
rc = -1;
} else
- rc = ranap_handle_co_initial_ue(scu_iups, rem_sccp_addr, conn_id, &message->msg.initialUE_MessageIEs);
+ rc = ranap_handle_co_initial_ue(iu_rnc, conn_id, &message->msg.initialUE_MessageIEs);

if (rc) {
LOGP(DRANAP, LOGL_ERROR, "Error in %s (%d)\n", __func__, rc);
@@ -474,20 +463,37 @@
uint32_t conn_id,
const uint8_t *data, size_t len)
{
- ranap_message message;
+ struct iu_rnc_ev_msg_up_co_initial_ctx ev_ctx = {
+ .conn_id = conn_id,
+ };
+ RANAP_Cause_t cause;
int rc;

- rc = ranap_cn_rx_co_decode2(&message, data, len);
+ rc = ranap_cn_rx_co_decode2(&ev_ctx.message, data, len);
if (rc != 0) {
LOGP(DRANAP, LOGL_ERROR, "Not calling cn_ranap_handle_co_initial() due to rc=%d\n", rc);
goto free_ret;
}

- cn_ranap_handle_co_initial(scu_iups, rem_sccp_addr, conn_id, &message);
+ ev_ctx.rnc = iu_rnc_find_by_addr(rem_sccp_addr);
+ if (!ev_ctx.rnc)
+ goto tx_err_ind;

+ rc = osmo_fsm_inst_dispatch(ev_ctx.rnc->fi, IU_RNC_EV_MSG_UP_CO_INITIAL, &ev_ctx);
+ if (rc != 0)
+ goto tx_err_ind;
+
+ goto free_ret;
+
+tx_err_ind:
+ cause = (RANAP_Cause_t){
+ .present = RANAP_Cause_PR_protocol,
+ .choice.protocol = RANAP_CauseProtocol_message_not_compatible_with_receiver_state,
+ };
+ sgsn_ranap_iu_tx_error_ind(scu_iups, rem_sccp_addr, &cause);
free_ret:
/* Free the asn1 structs in message */
- ranap_cn_rx_co_free(&message);
+ ranap_cn_rx_co_free(&ev_ctx.message);
return rc;
}

@@ -569,7 +575,7 @@
}

/* Entry point for connection-oriented RANAP message */
-static void cn_ranap_handle_co(struct ranap_ue_conn_ctx *ue_ctx, const ranap_message *message)
+void sgsn_ranap_iu_handle_co(struct ranap_ue_conn_ctx *ue_ctx, const ranap_message *message)
{
int rc;

@@ -649,20 +655,34 @@

int sgsn_ranap_iu_rx_co_msg(struct ranap_ue_conn_ctx *ue_ctx, const uint8_t *data, size_t len)
{
- ranap_message message;
+ struct iu_rnc_ev_msg_up_co_ctx ev_ctx = {
+ .ue_ctx = ue_ctx,
+ };
+ RANAP_Cause_t cause;
int rc;

- rc = ranap_cn_rx_co_decode2(&message, data, len);
+ rc = ranap_cn_rx_co_decode2(&ev_ctx.message, data, len);
if (rc != 0) {
LOGP(DRANAP, LOGL_ERROR, "Not calling cn_ranap_handle_co() due to rc=%d\n", rc);
goto free_ret;
}

- cn_ranap_handle_co(ue_ctx, &message);
+ rc = osmo_fsm_inst_dispatch(ue_ctx->rnc->fi, IU_RNC_EV_MSG_UP_CO, &ev_ctx);
+ if (rc != 0)
+ goto tx_err_ind;
+
+ goto free_ret;
+
+tx_err_ind:
+ cause = (RANAP_Cause_t){
+ .present = RANAP_Cause_PR_protocol,
+ .choice.protocol = RANAP_CauseProtocol_message_not_compatible_with_receiver_state,
+ };
+ sgsn_ranap_iu_tx_error_ind(ue_ctx->rnc->scu_iups, &ue_ctx->rnc->sccp_addr, &cause);

free_ret:
/* Free the asn1 structs in message */
- ranap_cn_rx_co_free(&message);
+ ranap_cn_rx_co_free(&ev_ctx.message);
return rc;
}

@@ -674,7 +694,7 @@
RANAP_Cause_t cause;
struct osmo_rnc_id rnc_id = {};
struct ranap_iu_rnc *rnc;
- struct msgb *resp;
+ int rc;

if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CN_DOMAININDICATOR_PRESENT) {
if (ies->cN_DomainIndicator != RANAP_CN_DomainIndicator_ps_domain) {
@@ -701,7 +721,7 @@
}
grnc_id = &ies->globalRNC_ID;

- if (iu_grnc_id_parse(&rnc_id, &ies->globalRNC_ID) != 0) {
+ if (iu_grnc_id_parse(&rnc_id, grnc_id) != 0) {
LOGP(DRANAP, LOGL_ERROR,
"Rx RESET: Failed to parse RANAP Global-RNC-ID IE\n");
cause = (RANAP_Cause_t){
@@ -713,12 +733,41 @@

rnc = iu_rnc_find_or_create(&rnc_id, scu_iups, &ud_prim->calling_addr);
OSMO_ASSERT(rnc);
+ rc = osmo_fsm_inst_dispatch(rnc->fi, IU_RNC_EV_RX_RESET, NULL);
+ if (rc != 0) {
+ cause = (RANAP_Cause_t){
+ .present = RANAP_Cause_PR_protocol,
+ .choice.protocol = RANAP_CauseProtocol_message_not_compatible_with_receiver_state,
+ };
+ return sgsn_ranap_iu_tx_error_ind(scu_iups, &ud_prim->calling_addr, &cause);
+ }
+ return 0;
+}

- /* send reset response */
- resp = ranap_new_msg_reset_ack(ies->cN_DomainIndicator, grnc_id);
- if (!resp)
- return -ENOMEM;
- return sgsn_ranap_iu_tx_cl(scu_iups, &ud_prim->calling_addr, resp);
+static int ranap_handle_cl_reset_ack(struct sgsn_sccp_user_iups *scu_iups,
+ const struct osmo_scu_unitdata_param *ud_prim,
+ const RANAP_ResetAcknowledgeIEs_t *ies)
+{
+ struct ranap_iu_rnc *rnc;
+ RANAP_Cause_t cause;
+ int rc;
+
+ rnc = iu_rnc_find_by_addr(&ud_prim->calling_addr);
+ if (!rnc)
+ goto tx_err_ind;
+
+ rc = osmo_fsm_inst_dispatch(rnc->fi, IU_RNC_EV_RX_RESET_ACK, NULL);
+ if (rc != 0)
+ goto tx_err_ind;
+
+ return 0;
+
+tx_err_ind:
+ cause = (RANAP_Cause_t){
+ .present = RANAP_Cause_PR_protocol,
+ .choice.protocol = RANAP_CauseProtocol_message_not_compatible_with_receiver_state,
+ };
+ return sgsn_ranap_iu_tx_error_ind(scu_iups, &ud_prim->calling_addr, &cause);
}

static int ranap_handle_cl_err_ind(struct sgsn_sccp_user_iups *scu_iups,
@@ -757,6 +806,15 @@
}
break;
case RANAP_RANAP_PDU_PR_successfulOutcome:
+ switch (message->procedureCode) {
+ case RANAP_ProcedureCode_id_Reset:
+ rc = ranap_handle_cl_reset_ack(scu_iups, ud_prim, &message->msg.resetAcknowledgeIEs);
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+ break;
case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
case RANAP_RANAP_PDU_PR_outcome:
default:
diff --git a/src/sgsn/iu_rnc.c b/src/sgsn/iu_rnc.c
index 158381c..abe6f61 100644
--- a/src/sgsn/iu_rnc.c
+++ b/src/sgsn/iu_rnc.c
@@ -40,25 +40,45 @@
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/iu_client.h>
#include <osmocom/sgsn/iu_rnc.h>
+#include <osmocom/sgsn/iu_rnc_fsm.h>
#include <osmocom/sgsn/sccp.h>
#include <osmocom/sgsn/sgsn.h>

static struct ranap_iu_rnc *iu_rnc_alloc(const struct osmo_rnc_id *rnc_id,
struct sgsn_sccp_user_iups *scu_iups,
- const struct osmo_sccp_addr *addr)
+ const struct osmo_sccp_addr *rnc_sccp_addr)
{
- struct ranap_iu_rnc *rnc = talloc_zero(sgsn, struct ranap_iu_rnc);
+ struct ranap_iu_rnc *rnc;
+ char *addr_str, *pos;
+
+ rnc = talloc_zero(sgsn, struct ranap_iu_rnc);
OSMO_ASSERT(rnc);

INIT_LLIST_HEAD(&rnc->lac_rac_list);

rnc->rnc_id = *rnc_id;
rnc->scu_iups = scu_iups;
- rnc->sccp_addr = *addr;
+ rnc->sccp_addr = *rnc_sccp_addr;
+
+ rnc->fi = osmo_fsm_inst_alloc(&iu_rnc_fsm, rnc, rnc, LOGL_INFO, NULL);
+ OSMO_ASSERT(rnc->fi);
+
+ /* Unfortunately, osmo_sccp_inst_addr_name() returns "RI=SSN_PC,PC=0.24.1,SSN=BSSAP" but neither commas nor
+ * full-stops are allowed as FSM inst id. Make it "RI-SSN_PC:PC-0-24-1:SSN-BSSAP". */
+ addr_str = osmo_sccp_addr_dump(rnc_sccp_addr);
+ for (pos = addr_str; *pos; pos++) {
+ if (*pos == ',')
+ *pos = ':';
+ else if (*pos == '.' || *pos == '=')
+ *pos = '-';
+ }
+ osmo_fsm_inst_update_id_f(rnc->fi, "RNC_ID-%s:%s",
+ osmo_rnc_id_name(rnc_id), addr_str);
+
llist_add(&rnc->entry, &sgsn->rnc_list);

LOGP(DRANAP, LOGL_NOTICE, "New RNC %s at %s\n",
- osmo_rnc_id_name(&rnc->rnc_id), osmo_sccp_addr_dump(addr));
+ osmo_rnc_id_name(&rnc->rnc_id), osmo_sccp_addr_dump(rnc_sccp_addr));

return rnc;
}
@@ -73,6 +93,17 @@
return NULL;
}

+struct ranap_iu_rnc *iu_rnc_find_by_addr(const struct osmo_sccp_addr *rnc_sccp_addr)
+{
+ struct ranap_iu_rnc *rnc;
+ llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
+ if (osmo_sccp_addr_ri_cmp(rnc_sccp_addr, &rnc->sccp_addr))
+ continue;
+ return rnc;
+ }
+ return NULL;
+}
+
struct ranap_iu_rnc *iu_rnc_find_or_create(const struct osmo_rnc_id *rnc_id,
struct sgsn_sccp_user_iups *scu_iups,
const struct osmo_sccp_addr *addr)
diff --git a/src/sgsn/iu_rnc_fsm.c b/src/sgsn/iu_rnc_fsm.c
new file mode 100644
index 0000000..4085586
--- /dev/null
+++ b/src/sgsn/iu_rnc_fsm.c
@@ -0,0 +1,349 @@
+/* A remote RNC (Radio Network Controller) FSM */
+
+/* (C) 2025 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ * 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/>.
+ *
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/fsm.h>
+#include <osmocom/core/tdef.h>
+
+#include <osmocom/sigtran/sccp_helpers.h>
+
+#include <osmocom/sgsn/debug.h>
+#include <osmocom/sgsn/gprs_ranap.h>
+#include <osmocom/sgsn/iu_rnc_fsm.h>
+#include <osmocom/sgsn/iu_rnc.h>
+#include <osmocom/sgsn/sgsn.h>
+
+#define S(x) (1 << (x))
+
+struct osmo_fsm iu_rnc_fsm;
+
+
+static const struct osmo_tdef_state_timeout iu_rnc_fsm_timeouts[32] = {
+ [IU_RNC_ST_WAIT_RX_RESET_ACK] = { .T = -1002 },
+ [IU_RNC_ST_DISCARDING] = { .T = -1002 },
+};
+
+#define iu_rnc_state_chg(iu_rnc, next_st) \
+ osmo_tdef_fsm_inst_state_chg((iu_rnc)->fi, next_st, iu_rnc_fsm_timeouts, sgsn_T_defs, 5)
+
+static const struct value_string iu_rnc_fsm_event_names[] = {
+ OSMO_VALUE_STRING(IU_RNC_EV_MSG_UP_CO_INITIAL),
+ OSMO_VALUE_STRING(IU_RNC_EV_MSG_UP_CO),
+ OSMO_VALUE_STRING(IU_RNC_EV_RX_RESET),
+ OSMO_VALUE_STRING(IU_RNC_EV_RX_RESET_ACK),
+ OSMO_VALUE_STRING(IU_RNC_EV_AVAILABLE),
+ OSMO_VALUE_STRING(IU_RNC_EV_UNAVAILABLE),
+ {}
+};
+
+/* Drop all SCCP connections for this iu_rnc, respond with RESET ACKNOWLEDGE and move to READY state. */
+static void iu_rnc_rx_reset(struct ranap_iu_rnc *rnc)
+{
+ struct msgb *reset_ack;
+ struct iu_grnc_id grnc_id;
+ sgsn_ranap_iu_grnc_id_compose(&grnc_id, &rnc->rnc_id);
+
+ iu_rnc_discard_all_ue_ctx(rnc);
+
+ reset_ack = ranap_new_msg_reset_ack(RANAP_CN_DomainIndicator_ps_domain, &grnc_id.grnc_id);
+ if (!reset_ack) {
+ LOG_RNC(rnc, LOGL_ERROR, "Failed to compose RESET ACKNOWLEDGE message\n");
+ iu_rnc_state_chg(rnc, IU_RNC_ST_WAIT_RX_RESET);
+ return;
+ }
+ if (sgsn_ranap_iu_tx_cl(rnc->scu_iups, &rnc->sccp_addr, reset_ack) < 0) {
+ LOG_RNC(rnc, LOGL_ERROR, "Failed to send RESET ACKNOWLEDGE message\n");
+ iu_rnc_state_chg(rnc, IU_RNC_ST_WAIT_RX_RESET);
+ return;
+ }
+
+ LOG_RNC(rnc, LOGL_INFO, "Sent RESET ACKNOWLEDGE\n");
+ iu_rnc_state_chg(rnc, IU_RNC_ST_READY);
+}
+
+static void iu_rnc_reset(struct ranap_iu_rnc *rnc)
+{
+ struct msgb *reset;
+ const RANAP_Cause_t cause = {
+ .present = RANAP_Cause_PR_protocol,
+ .choice = {
+ .protocol = RANAP_CauseProtocol_message_not_compatible_with_receiver_state,
+ },
+ };
+
+ iu_rnc_state_chg(rnc, IU_RNC_ST_WAIT_RX_RESET_ACK);
+ iu_rnc_discard_all_ue_ctx(rnc);
+
+ reset = ranap_new_msg_reset(RANAP_CN_DomainIndicator_ps_domain, &cause);
+ if (!reset) {
+ LOG_RNC(rnc, LOGL_ERROR, "Failed to compose RESET message\n");
+ iu_rnc_state_chg(rnc, IU_RNC_ST_WAIT_RX_RESET);
+ return;
+ }
+
+ if (sgsn_ranap_iu_tx_cl(rnc->scu_iups, &rnc->sccp_addr, reset) < 0) {
+ LOG_RNC(rnc, LOGL_ERROR, "Failed to send RESET message\n");
+ iu_rnc_state_chg(rnc, IU_RNC_ST_WAIT_RX_RESET);
+ return;
+ }
+}
+
+static void iu_rnc_st_wait_rx_reset(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct ranap_iu_rnc *rnc = fi->priv;
+ switch (event) {
+
+ case IU_RNC_EV_MSG_UP_CO:
+ case IU_RNC_EV_MSG_UP_CO_INITIAL:
+ OSMO_ASSERT(data);
+
+#define LEGACY_BEHAVIOR
+#ifdef LEGACY_BEHAVIOR
+ LOG_RNC(rnc, LOGL_ERROR, "Receiving CO message on RAN peer that has not done a proper RESET yet."
+ " Accepting RAN peer implicitly (legacy compat)\n");
+ iu_rnc_state_chg(rnc, IU_RNC_ST_READY);
+ osmo_fsm_inst_dispatch(rnc->fi, event, data);
+ return;
+#else
+ LOG_RNC(rnc, LOGL_ERROR, "Receiving CO message on RAN peer that has not done a proper RESET yet."
+ " Disconnecting on incoming message, sending RESET to RAN peer.\n");
+ /* No valid RESET procedure has happened here yet. Usually, we're expecting the RAN peer (BSC,
+ * RNC) to first send a RESET message before sending Connection Oriented messages. So if we're
+ * getting a CO message, likely we've just restarted or something. Send a RESET to the peer. */
+
+ /* Make sure the MS / UE properly disconnects. */
+ clear_and_disconnect(rnc, ctx->conn_id);
+
+ iu_rnc_reset(rnc);
+ return;
+#endif
+
+ case IU_RNC_EV_RX_RESET:
+ iu_rnc_rx_reset(rnc);
+ return;
+
+ case IU_RNC_EV_AVAILABLE:
+ /* Send a RESET to the peer. */
+ iu_rnc_reset(rnc);
+ return;
+
+ case IU_RNC_EV_UNAVAILABLE:
+ /* Do nothing, wait for peer to come up again. */
+ return;
+
+ default:
+ LOG_RNC(rnc, LOGL_ERROR, "Unhandled event: %s\n", osmo_fsm_event_name(&iu_rnc_fsm, event));
+ return;
+ }
+}
+
+static void iu_rnc_st_wait_rx_reset_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct ranap_iu_rnc *rnc = fi->priv;
+ struct iu_rnc_ev_msg_up_co_initial_ctx *ev_msg_up_co_initial_ctx;
+ struct iu_rnc_ev_msg_up_co_ctx *ev_msg_up_co_ctx;
+
+ switch (event) {
+
+ case IU_RNC_EV_RX_RESET_ACK:
+ iu_rnc_state_chg(rnc, IU_RNC_ST_READY);
+ return;
+
+
+ case IU_RNC_EV_MSG_UP_CO_INITIAL:
+ ev_msg_up_co_initial_ctx = data;
+ OSMO_ASSERT(ev_msg_up_co_initial_ctx);
+ LOG_RNC(rnc, LOGL_ERROR, "Receiving CO Initial message on RAN peer that has not done a proper RESET yet."
+ " Disconnecting on incoming message, sending RESET to RAN peer.\n");
+ osmo_sccp_tx_disconn(ev_msg_up_co_initial_ctx->rnc->scu_iups->scu,
+ ev_msg_up_co_initial_ctx->conn_id, NULL, 0);
+ /* No valid RESET procedure has happened here yet. */
+ iu_rnc_reset(rnc);
+ return;
+ return;
+ case IU_RNC_EV_MSG_UP_CO:
+ ev_msg_up_co_ctx = data;
+ OSMO_ASSERT(ev_msg_up_co_ctx);
+ LOG_RNC(rnc, LOGL_ERROR, "Receiving CO message on RAN peer that has not done a proper RESET yet."
+ " Disconnecting on incoming message, sending RESET to RAN peer.\n");
+ ue_conn_ctx_link_invalidated_free(ev_msg_up_co_ctx->ue_ctx);
+ /* No valid RESET procedure has happened here yet. */
+ iu_rnc_reset(rnc);
+ return;
+
+ case IU_RNC_EV_RX_RESET:
+ iu_rnc_rx_reset(rnc);
+ return;
+
+ case IU_RNC_EV_AVAILABLE:
+ /* Send a RESET to the peer. */
+ iu_rnc_reset(rnc);
+ return;
+
+ case IU_RNC_EV_UNAVAILABLE:
+ iu_rnc_state_chg(rnc, IU_RNC_ST_WAIT_RX_RESET);
+ return;
+
+ default:
+ LOG_RNC(rnc, LOGL_ERROR, "Unhandled event: %s\n", osmo_fsm_event_name(&iu_rnc_fsm, event));
+ return;
+ }
+}
+
+static void iu_rnc_st_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct ranap_iu_rnc *rnc = fi->priv;
+ struct iu_rnc_ev_msg_up_co_initial_ctx *ev_msg_up_co_initial_ctx;
+ struct iu_rnc_ev_msg_up_co_ctx *ev_msg_up_co_ctx;
+
+ switch (event) {
+
+ case IU_RNC_EV_MSG_UP_CO_INITIAL:
+ ev_msg_up_co_initial_ctx = data;
+ OSMO_ASSERT(ev_msg_up_co_initial_ctx);
+ OSMO_ASSERT(ev_msg_up_co_initial_ctx->rnc);
+
+ sgsn_ranap_iu_handle_co_initial(ev_msg_up_co_initial_ctx->rnc,
+ ev_msg_up_co_initial_ctx->conn_id,
+ &ev_msg_up_co_initial_ctx->message);
+ return;
+
+ case IU_RNC_EV_MSG_UP_CO:
+ ev_msg_up_co_ctx = data;
+ OSMO_ASSERT(ev_msg_up_co_ctx);
+ OSMO_ASSERT(ev_msg_up_co_ctx->ue_ctx);
+
+ sgsn_ranap_iu_handle_co(ev_msg_up_co_ctx->ue_ctx, &ev_msg_up_co_ctx->message);
+ return;
+
+ case IU_RNC_EV_RX_RESET:
+ iu_rnc_rx_reset(rnc);
+ return;
+
+ case IU_RNC_EV_AVAILABLE:
+ /* Do nothing, we were already up. */
+ return;
+
+ case IU_RNC_EV_UNAVAILABLE:
+ iu_rnc_discard_all_ue_ctx(rnc);
+ iu_rnc_state_chg(rnc, IU_RNC_ST_WAIT_RX_RESET);
+ return;
+
+ default:
+ LOG_RNC(rnc, LOGL_ERROR, "Unhandled event: %s\n", osmo_fsm_event_name(&iu_rnc_fsm, event));
+ return;
+ }
+}
+
+static int iu_rnc_fsm_timer_cb(struct osmo_fsm_inst *fi)
+{
+ struct ranap_iu_rnc *rnc = fi->priv;
+ iu_rnc_state_chg(rnc, IU_RNC_ST_WAIT_RX_RESET);
+ return 0;
+}
+
+static void iu_rnc_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
+{
+ struct ranap_iu_rnc *rnc = fi->priv;
+
+ iu_rnc_discard_all_ue_ctx(rnc);
+}
+
+static const struct osmo_fsm_state iu_rnc_fsm_states[] = {
+ [IU_RNC_ST_WAIT_RX_RESET] = {
+ .name = "WAIT_RX_RESET",
+ .action = iu_rnc_st_wait_rx_reset,
+ .in_event_mask = 0
+ | S(IU_RNC_EV_RX_RESET)
+ | S(IU_RNC_EV_MSG_UP_CO_INITIAL)
+ | S(IU_RNC_EV_MSG_UP_CO)
+ | S(IU_RNC_EV_AVAILABLE)
+ | S(IU_RNC_EV_UNAVAILABLE)
+ ,
+ .out_state_mask = 0
+ | S(IU_RNC_ST_WAIT_RX_RESET)
+ | S(IU_RNC_ST_WAIT_RX_RESET_ACK)
+ | S(IU_RNC_ST_READY)
+ | S(IU_RNC_ST_DISCARDING)
+ ,
+ },
+ [IU_RNC_ST_WAIT_RX_RESET_ACK] = {
+ .name = "WAIT_RX_RESET_ACK",
+ .action = iu_rnc_st_wait_rx_reset_ack,
+ .in_event_mask = 0
+ | S(IU_RNC_EV_RX_RESET)
+ | S(IU_RNC_EV_RX_RESET_ACK)
+ | S(IU_RNC_EV_MSG_UP_CO_INITIAL)
+ | S(IU_RNC_EV_MSG_UP_CO)
+ | S(IU_RNC_EV_AVAILABLE)
+ | S(IU_RNC_EV_UNAVAILABLE)
+ ,
+ .out_state_mask = 0
+ | S(IU_RNC_ST_WAIT_RX_RESET)
+ | S(IU_RNC_ST_WAIT_RX_RESET_ACK)
+ | S(IU_RNC_ST_READY)
+ | S(IU_RNC_ST_DISCARDING)
+ ,
+ },
+ [IU_RNC_ST_READY] = {
+ .name = "READY",
+ .action = iu_rnc_st_ready,
+ .in_event_mask = 0
+ | S(IU_RNC_EV_RX_RESET)
+ | S(IU_RNC_EV_MSG_UP_CO_INITIAL)
+ | S(IU_RNC_EV_MSG_UP_CO)
+ | S(IU_RNC_EV_AVAILABLE)
+ | S(IU_RNC_EV_UNAVAILABLE)
+ ,
+ .out_state_mask = 0
+ | S(IU_RNC_ST_WAIT_RX_RESET)
+ | S(IU_RNC_ST_WAIT_RX_RESET_ACK)
+ | S(IU_RNC_ST_READY)
+ | S(IU_RNC_ST_DISCARDING)
+ ,
+ },
+ [IU_RNC_ST_DISCARDING] = {
+ .name = "DISCARDING",
+ },
+};
+
+struct osmo_fsm iu_rnc_fsm = {
+ .name = "iu_rnc",
+ .states = iu_rnc_fsm_states,
+ .num_states = ARRAY_SIZE(iu_rnc_fsm_states),
+ .log_subsys = DRANAP,
+ .event_names = iu_rnc_fsm_event_names,
+ .timer_cb = iu_rnc_fsm_timer_cb,
+ .cleanup = iu_rnc_fsm_cleanup,
+};
+
+static __attribute__((constructor)) void iu_rnc_init(void)
+{
+ OSMO_ASSERT(osmo_fsm_register(&iu_rnc_fsm) == 0);
+}
diff --git a/src/sgsn/sccp.c b/src/sgsn/sccp.c
index 8b57dd4..83aa19f 100644
--- a/src/sgsn/sccp.c
+++ b/src/sgsn/sccp.c
@@ -33,6 +33,7 @@
#include <osmocom/sgsn/debug.h>
#include <osmocom/sgsn/iu_client.h>
#include <osmocom/sgsn/iu_rnc.h>
+#include <osmocom/sgsn/iu_rnc_fsm.h>
#include <osmocom/sgsn/gprs_ranap.h>
#include <osmocom/sgsn/sccp.h>
#include <osmocom/sgsn/sgsn.h>
@@ -147,10 +148,21 @@
{
struct ranap_iu_rnc *rnc;

- LOGP(DSUA, LOGL_DEBUG, "(calling_addr=%s) N-NOTICE.ind cause=%u='%s' importance=%u\n",
- osmo_sccp_addr_dump(&ni->calling_addr),
- ni->cause, osmo_sccp_return_cause_name(ni->cause),
- ni->importance);
+ rnc = iu_rnc_find_by_addr(&ni->calling_addr);
+
+ if (!rnc) {
+ LOGP(DSUA, LOGL_DEBUG,
+ "(calling_addr=%s) N-NOTICE.ind cause=%u='%s' importance=%u didn't match any RNC, ignoring\n",
+ osmo_sccp_addr_dump(&ni->calling_addr),
+ ni->cause, osmo_sccp_return_cause_name(ni->cause),
+ ni->importance);
+ return;
+ }
+
+ LOG_RNC(rnc, LOGL_NOTICE,
+ "N-NOTICE.ind cause=%u='%s' importance=%u\n",
+ ni->cause, osmo_sccp_return_cause_name(ni->cause),
+ ni->importance);

switch (ni->cause) {
case SCCP_RETURN_CAUSE_SUBSYSTEM_CONGESTION:
@@ -161,19 +173,8 @@
break;
}

- /* Messages are not arriving to RNC. Signal to user that all related ue_ctx are invalid. */
- llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
- if (osmo_sccp_addr_ri_cmp(&rnc->sccp_addr, &ni->calling_addr))
- continue;
- LOGP(DSUA, LOGL_NOTICE,
- "RNC %s now unreachable: N-NOTICE.ind cause=%u='%s' importance=%u\n",
- osmo_rnc_id_name(&rnc->rnc_id),
- ni->cause, osmo_sccp_return_cause_name(ni->cause),
- ni->importance);
- iu_rnc_discard_all_ue_ctx(rnc);
- /* TODO: ideally we'd have some event to submit to upper
- * layer to inform about peer availability change... */
- }
+ /* Messages are not arriving to rnc. Signal it is unavailable to update local state. */
+ osmo_fsm_inst_dispatch(rnc->fi, IU_RNC_EV_UNAVAILABLE, NULL);
}

static void handle_pcstate_ind(struct sgsn_sccp_user_iups *scu_iups, const struct osmo_scu_pcstate_param *pcst)
@@ -191,6 +192,13 @@

osmo_sccp_make_addr_pc_ssn(&rem_addr, pcst->affected_pc, OSMO_SCCP_SSN_RANAP);

+ rnc = iu_rnc_find_by_addr(&rem_addr);
+ if (!rnc) {
+ LOGP(DSUA, LOGL_DEBUG, "No RNC found under pc=%u=s%s\n",
+ pcst->affected_pc, osmo_ss7_pointcode_print(cs7, pcst->affected_pc));
+ return;
+ }
+
/* See if this marks the point code to have become available, or to have been lost.
*
* I want to detect two events:
@@ -245,38 +253,19 @@
}

if (disconnected) {
- /* A previously usable RNC has disconnected. Signal to user that all related ue_ctx are invalid. */
- llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
- struct ranap_ue_conn_ctx *ue_ctx, *ue_ctx_tmp;
- if (osmo_sccp_addr_cmp(&rnc->sccp_addr, &rem_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC))
- continue;
- LOGP(DSUA, LOGL_NOTICE,
- "RNC %s now unreachable: N-PCSTATE ind: pc=%u=%s sp_status=%s remote_sccp_status=%s\n",
- osmo_rnc_id_name(&rnc->rnc_id),
- pcst->affected_pc, osmo_ss7_pointcode_print(cs7, pcst->affected_pc),
- osmo_sccp_sp_status_name(pcst->sp_status),
- osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status));
- llist_for_each_entry_safe(ue_ctx, ue_ctx_tmp, &scu_iups->ue_conn_ctx_list, list) {
- if (ue_ctx->rnc != rnc)
- continue;
- ue_conn_ctx_link_invalidated_free(ue_ctx);
- }
- /* TODO: ideally we'd have some event to submit to upper
- * layer to inform about peer availability change... */
- }
+ LOG_RNC(rnc, LOGL_NOTICE,
+ "now unreachable: N-PCSTATE ind: pc=%u=%s sp_status=%s remote_sccp_status=%s\n",
+ pcst->affected_pc, osmo_ss7_pointcode_print(cs7, pcst->affected_pc),
+ osmo_sccp_sp_status_name(pcst->sp_status),
+ osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status));
+ osmo_fsm_inst_dispatch(rnc->fi, IU_RNC_EV_UNAVAILABLE, NULL);
} else if (connected) {
- llist_for_each_entry(rnc, &sgsn->rnc_list, entry) {
- if (osmo_sccp_addr_cmp(&rnc->sccp_addr, &rem_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC))
- continue;
- LOGP(DSUA, LOGL_NOTICE,
- "RNC %s now available: N-PCSTATE ind: pc=%u=%s sp_status=%s remote_sccp_status=%s\n",
- osmo_rnc_id_name(&rnc->rnc_id),
- pcst->affected_pc, osmo_ss7_pointcode_print(cs7, pcst->affected_pc),
- osmo_sccp_sp_status_name(pcst->sp_status),
- osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status));
- /* TODO: ideally we'd have some event to submit to upper
- * layer to inform about peer availability change... */
- }
+ LOG_RNC(rnc, LOGL_NOTICE,
+ "now available: N-PCSTATE ind: pc=%u=%s sp_status=%s remote_sccp_status=%s\n",
+ pcst->affected_pc, osmo_ss7_pointcode_print(cs7, pcst->affected_pc),
+ osmo_sccp_sp_status_name(pcst->sp_status),
+ osmo_sccp_rem_sccp_status_name(pcst->remote_sccp_status));
+ osmo_fsm_inst_dispatch(rnc->fi, IU_RNC_EV_AVAILABLE, NULL);
}
}

diff --git a/src/sgsn/sgsn.c b/src/sgsn/sgsn.c
index c78997e..1b02f76 100644
--- a/src/sgsn/sgsn.c
+++ b/src/sgsn/sgsn.c
@@ -61,6 +61,7 @@
#include <osmocom/sgsn/pdpctx.h>
#include <osmocom/sgsn/gprs_routing_area.h>
#if BUILD_IU
+#include <osmocom/sgsn/iu_rnc_fsm.h>
#include <osmocom/sgsn/sccp.h>
#endif /* #if BUILD_IU */

@@ -68,8 +69,6 @@

#define GPRS_LLME_CHECK_TICK 30

-extern struct osmo_tdef sgsn_T_defs[];
-
static const struct rate_ctr_desc sgsn_ctr_description[] = {
{ "llc:dl_bytes", "Count sent LLC bytes before giving it to the bssgp layer" },
{ "llc:ul_bytes", "Count successful received LLC bytes (encrypt & fcs correct)" },
diff --git a/src/sgsn/sgsn_vty.c b/src/sgsn/sgsn_vty.c
index 9721ee1..7761afc 100644
--- a/src/sgsn/sgsn_vty.c
+++ b/src/sgsn/sgsn_vty.c
@@ -98,7 +98,7 @@

/* Non spec timer */
#define NONSPEC_X1001_SECS 5 /* wait for a RANAP Release Complete */
-
+#define RANAP_TRafR_SECS 5 /* wait for a RANAP Release Complete */

struct osmo_tdef sgsn_T_defs[] = {
{ .T=3312, .default_val=GSM0408_T3312_SECS, .desc="Periodic RA Update timer (s)" },
@@ -114,8 +114,11 @@
{ .T=3395, .default_val=GSM0408_T3395_SECS, .desc="Wait for DEACT PDP CTX ACK timer (s)" },
{ .T=3397, .default_val=GSM0408_T3397_SECS, .desc="Wait for DEACT AA PDP CTX ACK timer (s)" },
/* non spec timers */
+#if BUILD_IU
{ .T=-1001, .default_val=NONSPEC_X1001_SECS, .desc="RANAP Release timeout. Wait for RANAP Release Complete."
"On expiry release Iu connection (s)" },
+ { .T=-1002, .default_val=RANAP_TRafR_SECS, .desc="TRafR, Maximum time for Reset procedure in the CN (s)" },
+#endif /* #if BUILD_IU */
{}
};

diff --git a/tests/gprs_routing_area/Makefile.am b/tests/gprs_routing_area/Makefile.am
index ea2779a..380d946 100644
--- a/tests/gprs_routing_area/Makefile.am
+++ b/tests/gprs_routing_area/Makefile.am
@@ -89,6 +89,7 @@
$(top_builddir)/src/sgsn/gprs_mm_state_iu_fsm.o \
$(top_builddir)/src/sgsn/iu_client.o \
$(top_builddir)/src/sgsn/iu_rnc.o \
+ $(top_builddir)/src/sgsn/iu_rnc_fsm.o \
$(top_builddir)/src/sgsn/sccp.o \
$(LIBOSMORANAP_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \
diff --git a/tests/osmo-sgsn_test-nodes.vty b/tests/osmo-sgsn_test-nodes.vty
index 32ff8e7..3b914c8 100644
--- a/tests/osmo-sgsn_test-nodes.vty
+++ b/tests/osmo-sgsn_test-nodes.vty
@@ -13,6 +13,7 @@
T3395 = 8 s Wait for DEACT PDP CTX ACK timer (s) (default: 8 s)
T3397 = 8 s Wait for DEACT AA PDP CTX ACK timer (s) (default: 8 s)
X1001 = 5 s RANAP Release timeout. Wait for RANAP Release Complete.On expiry release Iu connection (s) (default: 5 s)
+X1002 = 5 s TRafR, Maximum time for Reset procedure in the CN (s) (default: 5 s)
OsmoSGSN# configure terminal
OsmoSGSN(config)# list
...
diff --git a/tests/sgsn/Makefile.am b/tests/sgsn/Makefile.am
index 8bf78e7..77c1dd7 100644
--- a/tests/sgsn/Makefile.am
+++ b/tests/sgsn/Makefile.am
@@ -103,6 +103,7 @@
$(top_builddir)/src/sgsn/gprs_mm_state_iu_fsm.o \
$(top_builddir)/src/sgsn/iu_client.o \
$(top_builddir)/src/sgsn/iu_rnc.o \
+ $(top_builddir)/src/sgsn/iu_rnc_fsm.o \
$(top_builddir)/src/sgsn/sccp.o \
$(LIBOSMORANAP_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \

To view, visit change 40988. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: newchange
Gerrit-Project: osmo-sgsn
Gerrit-Branch: master
Gerrit-Change-Id: I18b7803500163e78ff6a684095194174b0fb6ee1
Gerrit-Change-Number: 40988
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin@sysmocom.de>