WIP: MTP2 IAC + LSC FSM

Change-Id: I1392b8b2f85c70f3783af655d5906a86a8b9a9c1
This commit is contained in:
Harald Welte 2022-09-04 11:13:36 +02:00
parent 6a8c053d4a
commit 6683ebc2ac
7 changed files with 1156 additions and 0 deletions

355
src/mtp2_iac_fsm.c Normal file
View File

@ -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
}

16
src/mtp2_iac_fsm.h Normal file
View File

@ -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;

512
src/mtp2_lsc_fsm.c Normal file
View File

@ -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;
}

26
src/mtp2_lsc_fsm.h Normal file
View File

@ -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;

191
src/mtp2_txc_fsm.c Normal file
View File

@ -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 = {
};

30
src/mtp2_txc_fsm.h Normal file
View File

@ -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,
};

View File

@ -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 */