From 6683ebc2acd86f4a9841b7c0037c7e5ef8a6a599 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 4 Sep 2022 11:13:36 +0200 Subject: [PATCH] WIP: MTP2 IAC + LSC FSM Change-Id: I1392b8b2f85c70f3783af655d5906a86a8b9a9c1 --- src/mtp2_iac_fsm.c | 355 +++++++++++++++++++++++++++++++ src/mtp2_iac_fsm.h | 16 ++ src/mtp2_lsc_fsm.c | 512 +++++++++++++++++++++++++++++++++++++++++++++ src/mtp2_lsc_fsm.h | 26 +++ src/mtp2_txc_fsm.c | 191 +++++++++++++++++ src/mtp2_txc_fsm.h | 30 +++ src/sccp_scoc.c | 26 +++ 7 files changed, 1156 insertions(+) create mode 100644 src/mtp2_iac_fsm.c create mode 100644 src/mtp2_iac_fsm.h create mode 100644 src/mtp2_lsc_fsm.c create mode 100644 src/mtp2_lsc_fsm.h create mode 100644 src/mtp2_txc_fsm.c create mode 100644 src/mtp2_txc_fsm.h diff --git a/src/mtp2_iac_fsm.c b/src/mtp2_iac_fsm.c new file mode 100644 index 00000000..e356876e --- /dev/null +++ b/src/mtp2_iac_fsm.c @@ -0,0 +1,355 @@ + +#include +#include "mtp2_iac_fsm.h" + +/* Implementation of the ITU-T Q.703 (MTP@) Initial alignment control FSM as + * described [primarily] in Figure 9/Q.703 */ + +enum mtp2_iac_fsm_state { + MTP2_IAC_S_IDLE, + MTP2_IAC_S_NOT_ALIGNED, + MTP2_IAC_S_ALIGNED, + MTP2_IAC_S_PROVING, +}; + +static const struct value_string mtp2_iac_event_names[] = { + { MTP2_IAC_E_EMERGENCY, "LSC2IAC_EMERGENCY" }, + { MTP2_IAC_E_START, "LSC2IAC_START" }, + { MTP2_IAC_E_STOP, "LSC2IAC_STOP" }, + { MTP2_IAC_E_RX_SIO, "RC2IAC_RX_SIO" }, + { MTP2_IAC_E_RX_SIOS, "RC2IAC_RX_SIOS" }, + { MTP2_IAC_E_RX_SIN, "RC2IAC_RX_SIN" }, + { MTP2_IAC_E_RX_SIE, "RC2IAC_RX_SIE" }, + { MTP2_IAC_E_CORRECT_SU, "DAEDR2IAC_CORRECT_SU" }, + { MTP2_IAC_E_ABORT_PROVING, "AERM2IAC_ABORT_PROVING" }, + { 0, NULL } +}; + +/* Section 12.3/Q.703 */ +#define MTP2_T1_64_MS 45000 +#define MTP2_T2_MS 60000 +#define MTP2_T3_MS 1500 +#define MTP2_T4e_64_MS 500 +#define MTP2_T4n_64_MS 8200 +#define MTP2_T5_MS 100 +#define MTP2_T6_64_MS 5000 +#define MTP2_T7_64_MS 1000 + +struct iac_fsm_data { + bool emergency; + bool further_proving; + uint32_t t4_ms; +}; + +static void mtp2_iac_fsm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data) + + struct iac_fsm_data *ifd = fi->priv; + + switch (event) { + case MTP2_IAC_E_EMERGENCY: + /* Mark emergency */ + ifd->emergency = true; + return; + case MTP2_IAC_E_START: + /* IAC -> TXC: Send SIO */ + /* Start T2 */ + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_NOT_ALIGNED, 0, 2); + break; + default: + OSMO_ASSERT(0); + } +} + +static void mtp2_iac_fsm_not_aligned(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct iac_fsm_data *ifd = fi->priv; + + switch (event) { + case MTP2_IAC_E_STOP: + /* Stop T2 (implicit below) */ + /* Cancel emergency */ + ifd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_IDLE, 0, 0); + case MTP2_IAC_E_RX_SIO: + case MTP2_IAC_E_RX_SIN: + /* Stop T2 (implicit below) */ + if (emergency) { + /* Set T4 to Pe */ + ifd->t4_ms = MTP2_T4e_64_MS; + /* IAC -> TXC: Send SIE */ + } else { + /* Set T4 to Pn */ + ifd->t4_ms = MTP2_T4n_64_MS; + /* IAC -> TXC: Send SIN */ + } + /* Start T3 */ + osmo_fsm_inst_state_chg_ms(fi, MTP2_IAC_S_ALIGNED, MTP2_T3_MS, 3); + break; + case MTP2_IAC_E_RX_SIE: + /* Stop T2 (implicit below) */ + if (emergency) { + /* Set T4 to Pe */ + ifd->t4_ms = MTP2_T4e_64_MS; + /* IAC -> TXC: Send SIE */ + } else { + /* Set T4 to Pe */ + ifd->t4_ms = MTP2_T4e_64_MS; + /* IAC -> TXC: Send SIN */ + } + /* Start T3 */ + osmo_fsm_inst_state_chg_ms(fi, MTP2_IAC_S_ALIGNED, MTP2_T3_MS, 3); + break; + case MTP2_IAC_E_EMERGENCY: + ifd->emergency = true; + break; + default: + OSMO_ASSERT(0); + } +} + +static void mtp2_iac_fsm_aligned(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct iac_fsm_data *ifd = fi->priv; + struct osmo_fsm_inst *lsc_fi = fi->proc.parent; + + switch (event) { + case MTP2_IAC_E_RX_SIE: + /* Set T4 to Pe */ + ifd->t4_ms = MTP2_T4e_64_MS; + /* fall-through */ + case MTP2_IAC_E_RX_SIN: + /* Stop T3 (implicit below) */ + if (t4 == Pe) { + /* IAC -> AERM: set i to ie */ + } + /* IAC -> AERM: Start */ + /* Start T4 (implicit below) */ + /* Cp := 0 */ + /* cancel further proving */ + ifd->further_proving = false; + osmo_fsm_inst_state_chg_ms(fi, MTP2_IAC_S_PROVING, ifd->t4_ms, 4); + break; + case MTP2_IAC_E_EMERGENCY: + /* IAC -> TXC: Send SIE */ + /* Set T4 to Pe */ + ifd->t4_ms = MTP2_T4e_64_MS; + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_ALIGNED, 0, 0); + break; + case MTP2_IAC_E_STOP: + /* Stop T3 (implicit below) */ + /* Cancel emergency */ + ifd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_IDLE, 0, 0); + break; + case MTP2_IAC_E_RX_SIOS: + /* IAC -> LSC: Alignment not possible */ + osmo_fsm_inst_dispatch(lsc_fi, MTP_LSC_E_ALIGNMENT_NOT_POSSIBLE, NULL); + /* Stop T3 (implicit below) */ + /* Cancel emergency */ + ifd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_IDLE, 0, 0); + break; + default: + OSMO_ASSERT(0); + } +} + +static void mtp2_iac_fsm_proving(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct iac_fsm_data *ifd = fi->priv; + struct osmo_fsm_inst *lsc_fi = fi->proc.parent; + + switch (event) { + case MTP2_IAC_E_RX_SIO: + /* Stop T4 (implicit below) */ + /* IAC -> AERM: Stop */ + /* Start T3 */ + osmo_fsm_inst_state_chg_ms(fi, MGP2_IAC_S_ALIGNED, MTP2_T3_MS, 3); + break; + case MTP2_IAC_E_CORRECT_SU: + if (ifd->further_proving) { + /* Stop T4 (implicit below) */ + /* 5 in-line below */ + /* IAC -> AERM: Start */ + /* Cancel further proving */ + ifd->further_proving = false; + /* Start T4 */ + osmo_fsm_inst_state_chg_ms(fi, MTP2_IAC_S_PROVING, ifd->t4_ms, 4); + } else { + /* 6: empty */ + } + break; + case MTP2_IAC_E_RX_SIOS: + /* Stop T4 (implicit below) */ + /* IAC -> LSC: Alignment not possible */ + osmo_fsm_inst_dispatch(lsc_fi, MTP_LSC_E_ALIGNMENT_NOT_POSSIBLE, NULL); + /* 4 in-line below */ + /* IAC -> AERM: Stop */ + /* cancel emergency */ + ifd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_IDLE, 0, 0); + break; + case MTP2_IAC_E_STOP: + /* Stop T4 (implicit below) */ + /* 4 in-line below */ + /* IAC -> AERM: Stop */ + /* cancel emergency */ + ifd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_IDLE, 0, 0); + break; + case MTP2_IAC_E_ABORT_PROVING: + /* Cp := Cp + 1 */ + if (id->cp == 5) { + /* IAC -> LSC: Alignment not possible */ + osmo_fsm_inst_dispatch(lsc_fi, MTP_LSC_E_ALIGNMENT_NOT_POSSIBLE, NULL); + /* Stop T4 (implicit below) */ + /* IAC -> AERM: Stop */ + /* cancel emergency */ + ifd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_IDLE, 0, 0); + } else{ + /* Mark further proving */ + ifd->further_proving = true; + } + break; + case MTP2_IAC_E_EMERGENCY: + /* IAC -> TXC: Send SIE */ + /* Stop T4 (implicit below) */ + /* Set T4 to Pe */ + ifd->t4_ms = MTP2_T4e_64_MS; + /* IAC -> AERM: Stop */ + /* Set Ti to Tie */ + /* IAC -> AERM: Start */ + /* Cancel further proving */ + ifd->further_proving = false; + /* Start T4 */ + osmo_fsm_inst_state_chg_ms(fi, MTP2_IAC_S_PROVING, ifd->t4_ms, 4); + break; + case MTP2_IAC_E_RX_SIE: + if (t4 == Pe) + break; + /* Stop T4 (implicit below) */ + /* Set T4 to Pe */ + ifd->t4_ms = MTP2_T4e_64_MS; + /* IAC -> AERM: Stop */ + /* Set Ti to Tie */ + /* IAC -> AERM: Start */ + /* Cancel further proving */ + ifd->further_proving = false; + /* Start T4 */ + osmo_fsm_inst_state_chg_ms(fi, MTP2_IAC_S_PROVING, ifd->t4_ms, 4); + break; + default: + OSMO_ASSERT(0); + } +} + +static const struct osmo_fsm_state mtp2_iac_states[] = { + [MTP2_IAC_S_IDLE] = { + .name = "IDLE", + .in_event_mask = S(MTP2_IAC_E_EMERGENCY) | + S(MTP2_IAC_E_START), + .out_state_mask = S(MTP2_IAC_S_IDLE) | + S(MTP2_IAC_S_NOT_ALIGNED), + .action = mtp2_iac_fsm_idle, + }, + [MTP2_IAC_S_NOT_ALIGNED] = { + .name = "NOT_ALIGNED", + .in_event_mask = S(MTP2_IAC_E_STOP) | + S(MTP2_IAC_E_SIO) | + S(MTP2_IAC_E_SIN) | + S(MTP2_IAC_E_SIE) | + S(MTP2_IAC_E_EMERGENCY), + .out_state_mask = S(MTP2_IAC_S_IDLE) | + S(MTP2_IAC_S_NOT_ALIGNED) | + S(MTP2_IAC_S_ALIGNED), + .action = mtp2_iac_fsm_not_aligned, + }, + [MTP2_IAC_S_ALIGNED] = { + .name = "ALIGNED", + .in_event_mask = S(MTP2_IAC_E_SIE) | + S(MTP2_IAC_E_SIN) | + S(MTP2_IAC_E_EMERGENCY) | + S(MTP2_IAC_E_STOP) | + S(MTP2_IAC_E_RX_SIOS), + .out_state_mask = S(MTP2_IAC_S_ALIGNED) | + S(MTP2_IAC_S_PROVING) | + S(MTP2_IAC_S_IDLE), + .action = mtp2_iac_fsm_aligned, + }, + [MTP2_IAC_S_PROVING] = { + .name = "PROVING", + .in_event_mask = S(MTP2_IAC_E_RX_SIO) | + S(MTP2_IAC_E_CORRECT_SU) | + S(MTP2_IAC_E_RX_SIOS) | + S(MTP2_IAC_E_STOP) | + S(MTP2_IAC_E_ABORT_PROVING) | + S(MTP2_IAC_E_EMERGENCY) | + S(MTP2_IAC_E_RX_SIE), + .out_state_mask = S(MTP2_IAC_S_ALIGNED) | + S(MTP2_IAC_S_IDLE) | + S(MTP2_IAC_S_PROVING), + .action = mtp2_iac_fsm_proving, + }, +}; + +static int mtp2_iac_fsm_timer_cb(struct osmo_fsm_inst *fi) +{ + struct iac_fsm_data *ifd = fi->priv; + struct osmo_fsm_inst *lsc_fi = fi->proc.parent; + + switch (fi->T) { + case 2: + /* Figure 9/Q.703 (sheet 1 of 6) */ + OSMO_ASSERT(fi->state == MTP2_IAC_S_NOT_ALIGNED); + /* IAC -> LSC: Alignment not possible */ + osmo_fsm_inst_dispatch(lsc_fi, MTP_LSC_E_ALIGNMENT_NOT_POSSIBLE, NULL); + /* Cancel emergency */ + ifd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_IDLE, 0, 0); + break; + case 3: + /* Figure 9/Q.703 (sheet 4 of 6) */ + OSMO_ASSERT(fi->state == MTP2_IAC_S_ALIGNED); + /* IAC -> LSC: Alignment not possible */ + osmo_fsm_inst_dispatch(lsc_fi, MTP_LSC_E_ALIGNMENT_NOT_POSSIBLE, NULL); + /* Cancel emergency */ + ifd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_IAC_S_IDLE, 0, 0); + break; + case 4: + /* Figure 9/Q.703 (sheet 5 of 6) */ + OSMO_ASSERT(fi->state == MTP2_IAC_S_PROVING); + if (ifd->further_proving) { + /* 5 in-line below */ + /* IAC -> AERM: Start */ + /* Cancel further proving */ + ifd->further_proving = false; + /* Start T4 */ + osmo_fsm_inst_state_chg_ms(fi, MTP2_IAC_S_PROVING, ifd->t4_ms, 4); + } else { + /* 6: empty */ + } + break; + default: + OSMO_ASSERT(0); + } +} + +struct osmo_fsm mtp2_iac_fsm = { + .name = "MTP2_IAC", + .states = mtp2_iac_states, + .num_states = ARRAY_SIZE(mtp2_iac_states), + .timer_cb = mtp2_iac_fsm_timer_cb, + .log_subsys = DLMTP2, + .event_names = mtp2_iac_event_names, +}; + +struct osmo_fsm_inst *mtp2_iac_fsm_alloc(struct osmo_fsm_inst *lsc_fsm) +{ + struct osmo_fsm_inst *fi; + struct mtp2_iac_fsm_priv *ifp; + + fi = osmo_fsm_inst_alloc_child +} + diff --git a/src/mtp2_iac_fsm.h b/src/mtp2_iac_fsm.h new file mode 100644 index 00000000..76040091 --- /dev/null +++ b/src/mtp2_iac_fsm.h @@ -0,0 +1,16 @@ +#pragma once +#include + +enum mtp2_iac_fsm_event { + MTP2_IAC_E_EMERGENCY, + MTP2_IAC_E_START, + MTP2_IAC_E_STOP, + MTP2_IAC_E_RX_SIO, + MTP2_IAC_E_RX_SIOS, + MTP2_IAC_E_RX_SIN, + MTP2_IAC_E_RX_SIE, + MTP2_IAC_E_CORRECT_SU, + MTP2_IAC_E_ABORT_PROVING, +}; + +extern struct osmo_fsm mtp2_iac_fsm; diff --git a/src/mtp2_lsc_fsm.c b/src/mtp2_lsc_fsm.c new file mode 100644 index 00000000..d14b0f01 --- /dev/null +++ b/src/mtp2_lsc_fsm.c @@ -0,0 +1,512 @@ +/* Implementation of the ITU-T Q.703 (MTP2) Link State Control FSM as + * described [primarily] in Figure 8/Q.703 */ + +#include + +#include "mtp2_lsc_fsm.h" +#include "mtp2_iac_fsm.h" + +enum mtp2_lsc_fsm_state { + MTP2_LSC_S_POWER_OFF, + MTP2_LSC_S_OUT_OF_SERVICE, + MTP2_LSC_S_INITIAL_ALIGNMENT, + MTP2_LSC_S_ALIGNED_READY, + MTP2_LSC_S_ALIGNED_NOT_READY, + MTP2_LSC_S_IN_SERVICE, + MTP2_LSC_S_PROCESSOR_OUTAGE, +}; + +static const struct value_string mtp2_lsc_event_names[] = { + { MTP_LSC_E_POWER_ON, "MGMT2LSC_POWER_ON" }, + { MTP_LSC_E_START, "L32LSC_START" }, + { MTP_LSC_E_EMERGENCY, "L32LSC_EMERGENCY" }, + { MTP_LSC_E_EMERGENCY_CEASES, "L32LSC_EMERGENCY_CEASES" }, + { MTP_LSC_E_LOCAL_PROC_OUTAGE, "MGMT2LSC_LOCAL_PROCESSOR_OUTAGE" }, + { MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD, "MGMT2LSC_LOCAL_PROCESSOR_OUTAGE_RECOVERED" }, + { MTP_LSC_E_LEVEL3_FAILURE, "MGMT2LSC_LEVEL3_FAILURE" }, + { MTP_LSC_E_ALIGNMENT_COMPLETE, "IAC2LSC_ALIGNMENT_COMPLETE" }, + { MTP_LSC_E_STOP, "L32LSC_STOP" }, + { MTP_LSC_E_LINK_FAILURE, "RC2LSC_LINK_FAILURE" }, + { MTP_LSC_E_ALIGNMENT_NOT_POSSIBLE, "IAC2LSC_ALIGNMENT_NOT_POSSIBLE" }, + { MTP_LSC_E_RX_SIO_SIOS, "RC2LSC_SIO_SIOS" }, + { MTP_LSC_E_RX_SIN_SIE, "RC2LSC_SIN_SIE" }, + { MTP_LSC_E_RX_SIPO, "RC2LSC_SIPO" }, + { MTP_LSC_E_RX_FISU_MSU, "RC2LSC_FISU_MSU" }, + { MTP_LSC_E_FLUSH_BUFFERS, "L32LSC_FLUSH_BUFFERS" }, + { MTP_LSC_E_CONTINUE, "L32LSC_CONTINUE" }, + { MTP_LSC_E_NO_PROC_OUTAGE, "POC2LSC_NO_PROCESSOR_OUTAGE" }, + { MTP_LSC_E_T1_EXP, "T1_EXPIRED" }, + { 0, NULL } +}; + +struct lsc_fsm_data { + /*! Initial Alignment Control FSM */ + struct osmo_fsm_inst *iac_fi; + + bool local_proc_outage; + + bool l3_indication_received; + bool processor_outage; /* remote? */ +}; + +/* Figure 8/Q.703 (sheet 1 of 14) */ +static void mtp2_lsc_fsm_power_off(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct lsc_fsm_data *lfd = fi->priv; + + switch (event) { + case MTP_LSC_E_POWER_ON: + /* LSC -> TXC: Start */ + /* LSC -> TXC: Send SIOS */ + /* LSC -> AERM: Set Ti to Tin */ + /* Cancel local processor outage */ + lfd->local_proc_outage = false; + /* Cancel emergency */ + lfd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_OUT_OF_SERVICE, 0, 0); + break; + default: + OSMO_ASSERT(0); + } +} + +/* Figure 8/Q.703 (sheet 2+3 of 14) */ +static void mtp2_lsc_fsm_out_of_service(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct lsc_fsm_data *lfd = fi->priv; + + switch (event) { + case MTP_LSC_E_START: + /* LSC -> RC: Start */ + /* LSC -> TXC: Start */ + if (ldf->emergency) { + /* LSC -> IAC: Emergency */ + osmo_fsm_inst_dispatch(lfd->iac_fi, MTP2_IAC_E_EMERGENCY, NULL); + } + /* LSC -> IAC: Start */ + osmo_fsm_inst_dispatch(lfd->iac_fi, MTP2_IAC_E_START, NULL); + /* LSC -> RC: Stop */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_INITIAL_ALIGNMENT, 0, 0); + break; + case MTP_LSC_E_EMERGENCY: + lfd->emergency = true; + break; + case MTP_LSC_E_EMERGENCY_CEASES: + lfd->emergency = false; + break; + case MTP_LSC_E_LOCAL_PROC_OUTAGE: + lfd->local_proc_outage = true; + break; + case MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD: + lfd->local_proc_outage = false; + break; + default: + OSMO_ASSERT(0); + } +} + +/* Figure 8/Q.703 (sheet 4+5 of 14) */ +static void mtp2_lsc_fsm_initial_alignment(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct lsc_fsm_data *lfd = fi->priv; + + switch (event) { + case MTP_LSC_E_LOCAL_PROC_OUTAGE: + /* fall-through */ + case MTP_LSC_E_LEVEL3_FAILURE: + lfd->local_proc_outage = true; + break; + case MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD: + lfd->local_proc_outage = false; + break; + case MTP_LSC_E_EMERGENCY: + lfd->emergency = true; + /* LSC -> IAC: Emergency */ + osmo_fsm_inst_dispatch(lfd->iac_fi, MTP2_IAC_E_EMERGENCY, NULL); + break; + case MTP_LSC_E_ALIGNMENT_COMPLETE: + /* LSC -> SUERM: Start */ + /* Start T1 */ + if (lfd->local_proc_outage) { + /* LSC -> POC: Local Processor Outage */ + /* LSC -> TXC: Send SIPO */ + /* LSC -> RC: Reject MSU/FISU */ + osmo_fsm_inst_state_chg_ms(fi, MTP3_LSC_S_ALIGNED_NOT_READY, MTP2_T1_64_MS, 1); + } else { + /* LSC -> TXC: Send FISU */ + /* LSC -> RC: Accept MSU/FISU */ + osmo_fsm_inst_state_chg_ms(fi, MTP2_LSC_S_ALIGNED_READY, MTP2_T1_64_MS, 1); + } + break; + case MTP_LSC_E_LINK_FAILURE: + /* LSC -> L3: Out of service */ + /* fall-through */ + case MTP_LSC_E_STOP: + /* LSC -> IAC: Stop */ + osmo_fsm_inst_dispatch(lfd->iac_fi, MTP2_IAC_E_STOP, NULL); + /* LSC -> RC: Stop */ + /* LSC -> TRX: Send SIOS */ + /* Cancel local processor outage */ + lfd->local_proc_outage = false; + /* Cancel emergency */ + lfd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_OUT_OF_SERVICE, 0, 0); + break; + case MTP_LSC_E_ALIGNMENT_NOT_POSSIBLE: + /* LSC -> L3: Out of service */ + /* LSC -> RC: Stop */ + /* LSC -> TRX: Send SIOS */ + /* Cancel local processor outage */ + lfd->local_proc_outage = false; + /* Cancel emergency */ + lfd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_OUT_OF_SERVICE, 0, 0); + break; + default: + OSMO_ASSERT(0); + } +} + +/* Figure 8/Q.703 (sheet 6+7 of 14) */ +static void mtp2_lsc_fsm_aligned_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct lsc_fsm_data *lfd = fi->priv; + switch (event) { + case MTP_LSC_E_LINK_FAILURE: + /* fall-through */ + case MTP_LSC_E_RX_SIO_SIOS: + case MTP_LSC_E_T1_EXP: + /* LSC -> L3: Out of service */ + /* fall-through */ + case MTP_LSC_E_STOP: + /* Stop T1 */ + /* LSC -> RC: Stop */ + /* LSC -> SUERM: Stop */ + /* LSC -> TXC: Send SIOS */ + /* Cancel emergency */ + lfd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_OUT_OF_SERVICE, 0, 0); + break; + case MTP_LSC_E_RX_SIPO: + /* Stop T1 */ + /* LSC -> L3: Remote processor outage */ + /* LSC -> POC: Remote processor outage */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_PROCESSOR_OUTAGE, 0, 0); + break; + case MTP_LSC_E_RX_FISU_MSU: + /* LSC -> L3: In service */ + /* Stop T1 */ + /* LSC -> TXC: Send MSU */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_IN_SERVICE, 0, 0); + break; + case MTP_LSC_E_LOCAL_PROC_OUTAGE: + /* fall-through */ + case MTP_LSC_E_LEVEL3_FAILURE: + /* LSC -> POC: Local Processor outage */ + /* LSC -> TXC: Send SIPO */ + /* LSC -> RC: Reject MSU/FISU */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_ALIGNED_NOT_READY, 0, 0); + break; + default: + OSMO_ASSERT(0); + } +} + +/* Figure 8/Q.703 (sheet 8+9 of 14) */ +static void mtp2_lsc_fsm_aligned_not_ready(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct lsc_fsm_data *lfd = fi->priv; + switch (event) { + case MTP_LSC_E_LINK_FAILURE: + /* fall-through */ + case MTP_LSC_E_RX_SIO_SIOS: + case MTP_LSC_E_T1_EXP: + /* LSC -> L3: Out of service */ + /* fall-through */ + case MTP_LSC_E_STOP: + /* Stop T1 */ + /* LSC -> RC: Stop */ + /* LSC -> SUERM: Stop */ + /* LSC -> TxC: Send SIOS */ + /* Cancel emergency and local processor outage */ + lfd->emergency = false; + lfd->local_proc_outage = false; + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_OUT_OF_SERVICE, 0, 0); + break; + case MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD: + /* LSC -> POC: Local processor recovered */ + /* Cancel local processor outage */ + lfd->local_proc_outage = false; + /* LSC -> TXC: Send FISU */ + /* LSC -> RC: Accept MSU/FISU */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_ALIGNED_READY, 0, 0); + break; + case MTP_LSC_E_RX_FISU_MSU: + /* LSC -> L3: In service */ + /* Stop T1 */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_PROCESSOR_OUTAGE, 0, 0); + break; + case MTP_LSC_E_RX_SIPO: + /* LSC -> L3: Remote processor outage */ + /* LSC -> POC: Remote processor outage */ + /* Stop T1 */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_PROCESSOR_OUTAGE, 0, 0); + break; + default: + OSMO_ASSERT(0); + + } +} + +/* Figure 8/Q.703 (sheet 10+11 of 14) */ +static void mtp2_lsc_fsm_in_service(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct lsc_fsm_data *lfd = fi->priv; + switch (event) { + case MTP_LSC_E_LINK_FAILURE: + /* fall-through */ + case MTP_LSC_E_RX_SIO_SIOS: + /* fall-through */ + case MTP_LSC_E_RX_SIN_SIE: + /* LSC -> L3: Out of service */ + /* fall-through */ + case MTP_LSC_E_STOP: + /* LSC -> SUERM: Stop */ + /* LSC -> RC: Stop */ + /* LSC -> TxC: Send SIOS */ + /* Cancel emergency */ + lfd->emergency = false; + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_OUT_OF_SERVICE, 0, 0); + break; + case MTP_LSC_E_LOCAL_PROC_OUTAGE: + /* fall-through */ + case MTP_LSC_E_LEVEL3_FAILURE: + /* LSC -> POC: Local Processor outage */ + /* LSC -> TXC: Send SIPO */ + /* LSC -> RC: Reject MSU/FISU */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_ALIGNED_NOT_READY, 0, 0); + break; + default: + OSMO_ASSERT(0); + } +} + +/* Figure 8/Q.703 (sheet 12-14 of 14) */ +static void mtp2_lsc_fsm_processor_outage(struct osmo_fsm_inst *fi, uint32_t event, void *data) +{ + struct lsc_fsm_data *lfd = fi->priv; + switch (event) { + case MTP_LSC_E_RX_FISU_MSU: + /* LSC -> POC: Remote processor recovered */ + /* LSC -> L3: Remote processor recovered */ + break; + case MTP_LSC_E_LEVEL3_FAILURE: + /* fall-through */ + case MTP_LSC_E_LOCAL_PROC_OUTAGE: + /* LSC -> POC: Local processor outage */ + /* LSC -> TXC: Send SIPO */ + break; + case MTP_LSC_E_RX_SIPO: + /* LSC -> L3: Remote processor outage */ + /* LSC -> POC: Remote processor outage */ + break; + case MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD: + /* LSC -> POC: Local processor recovered */ + /* LSC -> RC: Retrieve FSNX */ + /* LSC -> TXC: Send FISU */ + break; + case MTP_LSC_E_FLUSH_BUFFERS: + /* LSC -> TXC: Flush buffers */ + /* fall-through */ + case MTP_LSC_E_CONTINUE: + /* Mark L3 indication received */ + lfd->l3_indication_received = true; + if (lfd->processor_outage) + break; + /* Cancel Level3 indication received */ + /* LSC -> TXC: Send MSU/FISU */ + /* Cancel local processor outage */ + /* LSC -> RC: Accept MSU/FISU */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_IN_SERVICE, 0, 0); + break; + case MTP_LSC_E_NO_PROC_OUTAGE: + /* Cancel processor outage */ + lfd->processor_outage = false; + if (!lfd->l3_indication_received) + break; + /* Cancel Level3 indication received */ + /* LSC -> TXC: Send MSU/FISU */ + /* Cancel local processor outage */ + /* LSC -> RC: Accept MSU/FISU */ + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_IN_SERVICE, 0, 0); + break; + case MTP_LSC_E_LINK_FAILURE: + case MTP_LSC_E_RX_SIO_SIOS: + case MTP_LSC_E_RX_SIN_SIE: + /* LSC -> L3: Out of service */ + /* fall-through */ + case MTP_LSC_E_STOP: + /* LSC -> SUERM: Stop */ + /* LSC -> RC: Stop */ + /* LSC -> POC: Stop */ + /* LSC -> TXC: Send SIOS */ + /* Cancel emergency and local processor outage */ + lfd->emergency = false; + lfd->local_proc_outage = false; + osmo_fsm_inst_state_chg(fi, MTP2_LSC_S_OUT_OF_SERVICE, 0, 0); + break; + default: + OSMO_ASSERT(0); + } +} + + +static int mtp2_lsc_fsm_timer_cb(struct osmo_fsm_inst *fi) +{ + struct lsc_fsm_data *lfd = fi->priv; + + switch (fi-T) { + case 1: + /* we handle the timer expiration in the action call-backs + * to better align with the SDL diagrams */ + osmo_fsm_inst_dispatch(fi, MTP_LSC_E_T1_EXP, NULL); + break; + default: + OSMO_ASSERT(0); + } + + return 0; +} + + +static const struct osmo_fsm_state mtp2_lsc_states[] = { + [MTP2_LSC_S_POWER_OFF] = { + .name = "POWER_OFF", + .in_event_mask = S(MTP_LSC_E_POWER_ON), + .out_state_mask = S(MTP2_LSC_S_OUT_OF_SERVICE), + .action = mtp2_lsc_fsm_power_off, + }, + [MTP2_LSC_S_OUT_OF_SERVICE] = { + .name = "OUT_OF_SERVICE", + .in_event_mask = S(MTP_LSC_E_START) | + S(MTP_LSC_E_EMERGENCY) | + S(MTP_LSC_E_EMERGENCY_CEASES) | + S(MTP_LSC_E_LOCAL_PROC_OUTAGE) | + S(MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD) | + S(MTP_LSC_E_LEVEL3_FAILURE), + .out_state_mask = S(MTP2_LSC_S_OUT_OF_SERVICE) | + S(MTP2_LSC_S_INITIAL_ALIGNMENT), + .action = mtp2_lsc_fsm_out_of_service, + }, + [MTP2_LSC_S_INITIAL_ALIGNMENT] = { + .name = "INITIAL_ALIGNMENT", + .in_event_mask = S(MTP_LSC_E_EMERGENCY) | + S(MTP_LSC_E_LOCAL_PROC_OUTAGE) | + S(MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD) | + S(MTP_LSC_E_LEVEL3_FAILURE) | + S(MTP_LSC_E_ALIGNMENT_COMPLETE) | + S(MTP_LSC_E_STOP) | + S(MTP_LSC_E_LINK_FAILURE) | + S(MTP_LSC_E_ALIGNMENT_NOT_POSSIBLE), + .out_state_mask = S(MTP2_LSC_S_INITIAL_ALIGNMENT) | + S(MTP2_LSC_S_ALIGNED_NOT_READY) | + S(MTP2_LSC_S_OUT_OF_SERVICE), + .action = mtp2_lsc_fsm_initial_alignment, + }, + [MTP2_LSC_S_ALIGNED_READY] = { + .name = "ALIGNED_READY", + .in_event_mask = S(MTP_LSC_E_LINK_FAILURE) | + S(MTP_LSC_E_RX_SIO_SIOS) | + S(MTP_LSC_E_STOP) | + S(MTP_LSC_E_RX_SIPO) | + S(MTP_LSC_E_RX_FISU_MSU) | + S(MTP_LSC_E_LOCAL_PROC_OUTAGE) | + S(MTP_LSC_E_LEVEL3_FAILURE) | + S(MTP_LSC_E_T1_EXP), + .out_state_mask = S(MTP2_LSC_S_OUT_OF_SERVICE) | + S(MTP2_LSC_S_PROCESSOR_OUTAGE) | + S(MTP2_LSC_S_IN_SERVICE) | + S(MTP2_LSC_S_ALIGNED_NOT_READY), + .action = mtp2_lsc_fsm_aligned_ready, + }, + [MTP2_LSC_S_ALIGNED_NOT_READY] = { + .name = "ALIGNED_NOT_READY", + .in_event_mask = S(MTP_LSC_E_LINK_FAILURE) | + S(MTP_LSC_E_RX_SIO_SIOS) | + S(MTP_LSC_E_STOP) | + S(MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD) | + S(MTP_LSC_E_RX_FISU_MSU) | + S(MTP_LSC_E_RX_SIPO) | + S(MTP_LSC_E_T1_EXP), + .out_state_mask = S(MTP2_LSC_S_OUT_OF_SERVICE) | + S(MTP2_LSC_S_ALIGNED_READY) | + S(MTP2_LSC_S_PROCESSOR_OUTAGE), + .action = mtp2_lsc_fsm_aligned_not_ready, + }, + [MTP2_LSC_S_IN_SERVICE] = { + .name = "IN_SERVICE", + .in_event_mask = S(MTP_LSC_E_LINK_FAILURE) | + S(MTP_LSC_E_RX_SIO_SIOS) | + S(MTP_LSC_E_RX_SIN_SIE) | + S(MTP_LSC_E_LOCAL_PROC_OUTAGE) | + S(MTP_LSC_E_LEVEL3_FAILURE) | + S(MTP_LSC_E_RX_SIPO), + .out_state_mask = S(MTP2_LSC_S_OUT_OF_SERVICE) | + S(MTP2_LSC_S_PROCESSOR_OUTAGE), + .action = mtp2_lsc_fsm_in_service, + }, + [MTP2_LSC_S_PROCESSOR_OUTAGE] = { + .name = "PROCESSOR_OUTAGE", + .in_event_mask = S(MTP_LSC_E_RX_FISU_MSU) | + S(MTP_LSC_E_LEVEL3_FAILURE) | + S(MTP_LSC_E_LOCAL_PROC_OUTAGE) | + S(MTP_LSC_E_RX_SIPO) | + S(MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD) | + S(MTP_LSC_E_FLUSH_BUFFERS) | + S(MTP_LSC_E_NO_PROC_OUTAGE) | + S(MTP_LSC_E_LINK_FAILURE) | + S(MTP_LSC_E_RX_SIO_SIOS) | + S(MTP_LSC_E_RX_SIN_SIE) | + S(MTP_LSC_E_STOP), + .out_state_mask = S(MTP2_LSC_S_PROCESSOR_OUTAGE) | + S(MTP2_LSC_S_IN_SERVICE) | + S(MTP2_LSC_S_OUT_OF_SERVICE), + .action = mtp2_lsc_fsm_processor_outage, + }, +}; + + +struct osmo_fsm mtp2_lsc_fsm = { + .name = "MTP2_LSC", + .states = mtp2_lsc_states, + .num_states = ARRAY_SIZE(mtp2_lsc_states), + .timer_cb = mtp2_lsc_fsm_timer_cb, + .log_subsys = DLMTP2, + .event_names = mtp2_lsc_event_names, + .allstate_event_mask = , + .allstate_action = mtp2_lsc_allstate, +}; + +struct osmo_fsm_inst *mtp2_lxc_fsm_alloc(struct osmo_ss7_link *s7l, int log_level) +{ + struct osmo_fsm_inst *fi; + struct mtp2_lsc_fsm_priv *lfp; + + fi = osmo_fsm_inst_alloc(&mtp2_lsc_fsm, s7l, NULL, log_level, s7l->name); + + lfp = talloc_zero(fi, struct mtp2_lxc_fsm_priv); + if (!lfp) { + osmo_fsm_inst_term(fi, OSM_FSM_TERM_ERROR, NULL); + return NULL; + } + /* Initial Alignment Control FSM instance */ + lfp->iac_fi = mtp2_iac_fsm_alloc(fi); + + lfp->local_proc_outage = false; + lfp->l3_indication_received = false; + lfp->processor_outage = false; + + fi->priv = lfp; + + return fi; +} diff --git a/src/mtp2_lsc_fsm.h b/src/mtp2_lsc_fsm.h new file mode 100644 index 00000000..9aa1e4da --- /dev/null +++ b/src/mtp2_lsc_fsm.h @@ -0,0 +1,26 @@ +#pragma once +#include + +enum mtp2_lsc_fsm_event { + MTP_LSC_E_POWER_ON, /* MGMT -> LSC */ + MTP_LSC_E_START, /* L3 -> LSC */ + MTP_LSC_E_EMERGENCY, /* L3 -> LSC */ + MTP_LSC_E_EMERGENCY_CEASES, /* L3 -> LSC */ + MTP_LSC_E_LOCAL_PROC_OUTAGE, /* MGMT -> LSC */ + MTP_LSC_E_LOCAL_PROC_OUTAGE_RECOVD, /* MGMT -> LSC */ + MTP_LSC_E_LEVEL3_FAILURE, /* MGMT -> LSC */ + MTP_LSC_E_ALIGNMENT_COMPLETE, /* IAC -> LSC */ + MTP_LSC_E_STOP, /* L3 -> LSC */ + MTP_LSC_E_LINK_FAILURE, /* RC -> LSC */ + MTP_LSC_E_ALIGNMENT_NOT_POSSIBLE, /* IAC -> LSC */ + MTP_LSC_E_RX_SIO_SIOS, /* RC -> LSC */ + MTP_LSC_E_RX_SIPO, /* RC -> LSC */ + MTP_LSC_E_RX_FISU_MSU, /* RC -> LSC */ + MTP_LSC_E_FLUSH_BUFFERS, /* L3 -> LSC */ + MTP_LSC_E_CONTINUE, /* L3 -> LSC */ + MTP_LSC_E_NO_PROC_OUTAGE, /* POC -> LSC */ + MTP_LSC_E_T1_EXP, /* LSC -> LSC */ + +}; + +extern struct osmo_fsm mtp2_lsc_fsm; diff --git a/src/mtp2_txc_fsm.c b/src/mtp2_txc_fsm.c new file mode 100644 index 00000000..413b2800 --- /dev/null +++ b/src/mtp2_txc_fsm.c @@ -0,0 +1,191 @@ +#include +#include "mtp2_txc_fsm.h" + +struct txc_fsm_data { + /* Link Status Control FSM Instance */ + struct osmo_fsm_inst *lsc_fi; + /* back-pointer to SS7 Link */ + struct osmo_ss7_link *s7l; + + /* various fsm-private state */ + FIXME lssu_available; + bool sib_received; + bool rtb_full; + bool msu_inhibited; + + uint32_t fnsl; + uint32_t fnst; + uint32_t fnsx; + uint32_t fib; + uint32_t bib; + uint32_t fsnf; + uint32_t cm; +}; + +static inline bool is_m2pa(const struct txc_fsm_data *tfd) +{ + return tfd->s7l->type == OSMO_SS7_LINK_TYPE_M2PA; +} + +static void m2pa_txc_fsm_idle(struct osmo_fsm_inst *fi, uint32_t event ,void *data) +{ + struct txc_fsm_data *tfd = fi->priv; + + switch (event) { + case MTP2_TXC_E_START: + /* TXC -> DAEDT: Start */ + /* Cancel LSSU available */ + tfd->lssu_available = false; + /* Cancel SIB received */ + tfd->sib_received = false; + /* Cancel RTP full */ + tfd->rtb_full = false; + /* Cancel MSU inhibited */ + tfd->msu_inhibited = false; + /* initialize various variables */ + tfd->fsnl = 127; + tfd->fsnt = 127; + tfd->fsnx = 0; + tfd->fib = tfd->bib = 1; + tfd->fsnf = 0; + tfd->cm = 0; + osmo_fsm_inst_state_chg(fi, MTP2_TXC_S_IN_SERVICE, 0, 0); + break; + default: + OSMO_ASSERT(0); + } +} + +static void m2pa_txc_fsm_in_service(struct osmo_fsm_inst *fi, uint32_t event ,void *data) +{ + struct txc_fsm_data *tfd = fi->priv; + struct osmo_m2pa_peer *m2p; + + if (is_m2pa(tfd)) + m2p = tfd->s7l->u.m2pa; + else + m2p = NULL; + + switch (event) { + case MTP2_TXC_E_SEND_SIOS: + /* Stop T7 */ + tfd->lssu_available = SIOS; + if (is_m2pa(tfd)) + osmo_m2pa_peer_send_link_status(m2p, M2PA_LSTS_OUT_OF_SERVICE); + break; + case MTP2_TXC_E_SEND_SIPO: + /* Stop T7 */ + tfd->lssu_available = SIPO; + if (is_m2pa(tfd)) + osmo_m2pa_peer_send_link_status(m2p, M2PA_LSTS_PROCESSOR_OUTAGE); + break; + case MTP2_TXC_E_SEND_SIO: + tfd->lssu_available = SIO; + if (is_m2pa(tfd)) + osmo_m2pa_peer_send_link_status(m2p, M2PA_LSTS_ALIGNMENT); + break; + case MTP2_TXC_E_SEND_SIN: + tfd->lssu_available = SIN; + if (is_m2pa(tfd)) + osmo_m2pa_peer_send_link_status(m2p, M2PA_LSTS_PROVING_NORMAL); + break; + case MTP2_TXC_E_SEND_SIE: + tfd->lssu_available = SIE; + if (is_m2pa(tfd)) + osmo_m2pa_peer_send_link_status(m2p, M2PA_LSTS_PROVING_EMERGENCY); + break; + case MTP2_TXC_E_SEND_SIB: + tfd->lssu_available = SIB; + if (is_m2pa(tfd)) + osmo_m2pa_peer_send_link_status(m2p, M2PA_LSTS_BUSY); + break; + case MTP2_TXC_E_START: + /* Cancel SIB received */ + tfd->sib_received = false; + /* Cancel RTP full */ + tfd->rtb_full = false; + /* Cancel MSU inhibited */ + tfd->msu_inhibited = false; + /* initialize various variables */ + tfd->fsnl = 127; + tfd->fsnt = 127; + tfd->fsnx = 0; + tfd->fib = tfd->bib = 1; + tfd->fsnf = 0; + tfd->cm = 0; + osmo_fsm_inst_state_chg(fi, MTP2_TXC_S_IN_SERVICE, 0, 0); + break; + case MTP2_TXC_E_SEND_FISU: + /* Stop T7 */ + /* Mark MSU inhibited */ + tfd->msu_inhibited = true; + tfd->lssu_available = FISU; + if (is_m2pa(tfd)) + osmo_m2pa_peer_send_link_status(m2p, M2PA_LSTS_READY); + break; + case MTP2_TXC_E_SEND_MSU: + if (tfd->fsnl != tfd->fsnf - 1) { + /* Start T7 */ + } + /* Cancel MSU inhibited */ + tfd->msu_inhibited = false; + tfd->lssu_available = NULL; + break; + case MTP2_TXC_E_NACK_TO_BE_SENT: + ftd->bib = !ftd->bib; + break; + case MTP2_TXC_E_SIB_RECEIVED: + if (!tfd->sib_received) { + /* Start T6 */ + tfd->sib_received = true; + } + /* Start T7 */ + break; + case MTP2_TXC_E_MSG_FOR_TX: + /* Store MSU in TB */ + break; + case MTP2_TSC_E_FLUSH_BUFFERS: + /* Erase all MSUs in RTB and TB */ + /* Cancel RTB full */ + tfd->rtb_full = false; + tfd->cm = 0; + tfd->fsnf = tfd->bsnr + 1; + tfd->fsnl = tfd->bsnr; + tfd->fsnl = tfd->bsnr; + break; + default: + OSMO_ASSERT(0); + } +} + + +static const struct osmo_fsm_state m2pa_txc_fsm_states[] = { + [MTP2_TXC_S_IDLE] = { + .name = "IDLE", + .action = m2pa_txc_fsm_idle, + .in_event_mask = S(MTP2_TXC_E_START), + .out_state_mask = S(MTP2_TXC_S_IDLE) | + S(MTP2_TXC_S_IN_SERVICE), + }, + [MTP2_TXC_S_IN_SERVICE] = { + .name = "IN_SERVICE", + .action = m2pa_txc_fsm_in_service, + .in_event_mask = S(MTP2_TXC_E_SEND_SIOS) | + S(MTP2_TXC_E_SEND_SIPO) | + S(MTP2_TXC_E_SEND_SIO) | + S(MTP2_TXC_E_SEND_SIN) | + S(MTP2_TXC_E_SEND_SIE) | + S(MTP2_TXC_E_SEND_SIB) | + S(MTP2_TXC_E_START) | + S(MTP2_TXC_E_SEND_FISU) | + S(MTP2_TXC_E_SEND_MSU) | + S(MTP2_TXC_E_NACK_TO_BE_SENT) | + S(MTP2_TXC_E_SIB_RECEIVED) | + S(MTP2_TXC_E_MSG_FOR_TX) | + S(MTP2_TSC_E_FLUSH_BUFFERS), + .out_state_mask = S(MTP2_TXC_S_IN_SERVICE), + }, +}; + +struct osmo_fsm m2pa_txc_fsm = { +}; diff --git a/src/mtp2_txc_fsm.h b/src/mtp2_txc_fsm.h new file mode 100644 index 00000000..0513fd85 --- /dev/null +++ b/src/mtp2_txc_fsm.h @@ -0,0 +1,30 @@ +#pragma once +#include + +enum mtp2_txc_event { + MTP2_TXC_E_START, /* LSC -> TXC: Start */ + MTP2_TXC_E_SEND_SIOS, /* LSC -> TXC: Send SIOS */ + MTP2_TXC_E_SEND_SIPO, /* LSC -> TXC: Send SIPO */ + MTP2_TXC_E_SEND_FISU, /* LSC -> TXC: Send FISU */ + MTP2_TXC_E_SEND_MSU, /* LSC -> TXC: Send MSU */ + MTP2_TXC_E_FLUSH_BUFFERS, /* LSC -> TXC: Flush Buffers */ + MTP2_TXC_E_SEND_MSU, /* LSC -> TXC: Send MSU/FISU */ + + MTP2_TXC_E_SEND_SIO, /* IAC -> TXC: Send SIO */ + MTP2_TXC_E_SEND_SIE, /* IAC -> TXC: Send SIE */ + MTP2_TXC_E_SEND_SIN, /* IAC -> TXC: Send SIN */ + + MTP2_TXC_E_SEND_SIB, /* CC -> TXC: Send SIB */ + + MTP2_TXC_E_NACK_TO_BE_SENT, /* RC -> TXC: NACK To be sent */ + MTP2_TXC_E_SIB_RECEIVED, /* RC -> TXC: SIB Received */ + MTP2_TXC_E_MSG_FOR_TX, /* L3 -> TXC: Message for transmission */ + //MTP2_TXC_E_BSNR_AND_BIBR, /* RC -> TXC */ + //MTP2_TXC_E_FSNX_VALUE, /* RC -> TXC */ + MTP2_TSC_E_FLUSH_BUFFERS, /* LSC -> TXC: Flush buffers */ +}; + +enum mtp2_txc_fsm_state { + MTP2_TXC_S_IDLE, + MTP2_TXC_S_IN_SERVICE, +}; diff --git a/src/sccp_scoc.c b/src/sccp_scoc.c index db1db239..d95ed637 100644 --- a/src/sccp_scoc.c +++ b/src/sccp_scoc.c @@ -992,6 +992,14 @@ static void scoc_fsm_idle(struct osmo_fsm_inst *fi, uint32_t event, void *data) switch (event) { case SCOC_E_SCU_N_CONN_REQ: prim = data; + if (msgb_l2len(prim->oph.msg) > SCCP_CR_MAX_DATA_LEN) { + LOGPFSML(fi, LOGL_ERROR, "N-CONNECT.req with DATA length > %u " + "not permitted by Q.713\n", SCCP_CR_MAX_DATA_LEN); + /* FIXME: send empty CR and send data in later DT1 */ + scu_gen_encode_and_send(conn, event, NULL, OSMO_SCU_PRIM_N_DISCONNECT, + PRIM_OP_INDICATION); + break; + } uconp = &prim->u.connect; /* copy relevant parameters from prim to conn */ conn->called_addr = uconp->called_addr; @@ -1070,6 +1078,12 @@ static void scoc_fsm_conn_pend_in(struct osmo_fsm_inst *fi, uint32_t event, void switch (event) { case SCOC_E_SCU_N_CONN_RESP: prim = data; + if (msgb_l2len(prim->oph.msg) > SCCP_CC_MAX_DATA_LEN) { + LOGPFSML(fi, LOGL_ERROR, "N-CONNECT.resp with DATA length > %u " + "not permitted by Q.713\n", SCCP_CC_MAX_DATA_LEN); + /* FIXME: send CC with empty body and use DT1 to transfer data afterwards! */ + break; + } /* FIXME: assign local reference (only now?) */ /* FIXME: assign sls, protocol class and credit */ xua_gen_encode_and_send(conn, event, prim, SUA_CO_COAK); @@ -1080,6 +1094,12 @@ static void scoc_fsm_conn_pend_in(struct osmo_fsm_inst *fi, uint32_t event, void break; case SCOC_E_SCU_N_DISC_REQ: prim = data; + if (msgb_l2len(prim->oph.msg) > SCCP_CREF_MAX_DATA_LEN) { + LOGPFSML(fi, LOGL_ERROR, "N-DISCONNECT.req with DATA length > %u " + "not permitted by Q.713\n", SCCP_CREF_MAX_DATA_LEN); + /* FIXME: refuse without payload! */ + break; + } /* release resources: implicit */ xua_gen_encode_and_send(conn, event, prim, SUA_CO_COREF); /* N. B: we've ignored CREF sending errors as there's no recovery option anyway */ @@ -1230,6 +1250,12 @@ static void scoc_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *data /* fall-through */ case SCOC_E_SCU_N_DISC_REQ: prim = data; + if (msgb_l2len(prim->oph.msg) > SCCP_RLSD_MAX_DATA_LEN) { + LOGPFSML(fi, LOGL_ERROR, "N-DISCONNECT.req with DATA length > %u " + "not permitted by Q.713\n", SCCP_RLSD_MAX_DATA_LEN); + /* FIXME: send DT1 followed by empty RLSD */ + break; + } /* stop inact timers */ conn_stop_inact_timers(conn); /* send RLSD to SCRC */