WIP: MTP2 IAC + LSC FSM
Change-Id: I1392b8b2f85c70f3783af655d5906a86a8b9a9c1
This commit is contained in:
parent
6a8c053d4a
commit
6683ebc2ac
|
@ -0,0 +1,355 @@
|
|||
|
||||
#include <osmocom/core/fsm.h>
|
||||
#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
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
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;
|
|
@ -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 <osmocom/core/fsm.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
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;
|
|
@ -0,0 +1,191 @@
|
|||
#include <osmocom/core/fsm.h>
|
||||
#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 = {
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
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,
|
||||
};
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue