2022-12-09 18:20:45 +00:00
/* ITU-T G.964 Section 13 PSTN signalling protocol specification - LE */
/* (C) 2022 by Andreas Eversberg <jolly@eversberg.eu>
*
* All Rights Reserved
*
* SPDX - License - Identifier : GPL - 2.0 +
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
*/
/***********************************************************************/
/* internal data structures */
/***********************************************************************/
# include <errno.h>
# include <arpa/inet.h>
# include <osmocom/core/linuxlist.h>
# include <osmocom/gsm/tlv.h>
# include "v5x_internal.h"
# include "v5x_protocol.h"
# include "v5x_le_pstn_fsm.h"
2022-12-16 17:49:11 +00:00
# include "v5x_le_management.h"
2022-12-09 18:20:45 +00:00
# include "logging.h"
/* Table 28/G.964 Timers in the LE */
# define TIMEOUT_T1 2 /* default */
# define TIMEOUT_T3 2
# define TIMEOUT_T4 2
# define TIMEOUT_Tr 5
# define TIMEOUT_Tt 10
# define S(x) (1 << (x))
/***********************************************************************/
/* state names, event names, primitives, ... */
/***********************************************************************/
/* 13.2.1.2 PSTN protocol FSM - LE(PSTN) */
enum v5x_le_pstn_state {
V5x_LE_PTSN_S_LE0_OUT_OF_SERVICE , /* LE0 */
V5x_LE_PTSN_S_LE1_NULL , /* LE1 */
V5x_LE_PTSN_S_LE2_PATH_INITIATED_LE , /* LE2 */
V5x_LE_PTSN_S_LE3_PATH_INITIATED_AN , /* LE3 */
V5x_LE_PTSN_S_LE4_PATH_ACTIVE , /* LE4 */
V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ , /* LE5 */
V5x_LE_PTSN_S_LE6_PORT_BLOCKED , /* LE6 */
} ;
enum v5x_le_pstn_fsm_event {
/* inbound function elements from AN (Table 3/G.964) */
V5x_PSTN_LE_FE_establish_req ,
V5x_PSTN_LE_FE_establish_ack_req ,
V5x_PSTN_LE_FE_line_signal_req ,
V5x_PSTN_LE_FE_protocol_param_req ,
V5x_PSTN_LE_FE_disconnect_req ,
V5x_PSTN_LE_FE_disconnect_compl_req ,
/* inbound messages from AN (Table 3/G.964) */
V5x_PSTN_LE_DISCONNECT ,
V5x_PSTN_LE_DISCONNECT_COMPL ,
V5x_PSTN_LE_ESTABLISH ,
V5x_PSTN_LE_ESTABLISH_ACK ,
V5x_PSTN_LE_SIGNAL ,
V5x_PSTN_LE_SIGNAL_ACK ,
V5x_PSTN_LE_STATUS ,
/* timer events (Table 3/G.964) */
V5x_PSTN_LE_TIMEOUT_T1 ,
V5x_PSTN_LE_TIMEOUT_T3 ,
V5x_PSTN_LE_TIMEOUT_T4 ,
V5x_PSTN_LE_TIMEOUT_Tr ,
V5x_PSTN_LE_TIMEOUT_Tt ,
/* inbound primitives from Mgmt (Table 3/G.964) */
V5x_PSTN_LE_MDU_CTRL_port_blocked ,
V5x_PSTN_LE_MDU_CTRL_port_unblocked ,
V5x_PSTN_LE_MDU_CTRL_restart_req ,
V5x_PSTN_LE_MDU_CTRL_restart_compl_req ,
} ;
static const struct value_string v5x_ctrl_le_port_fsm_event_names [ ] = {
{ V5x_PSTN_LE_FE_establish_req , " FE-establish_request " } ,
{ V5x_PSTN_LE_FE_establish_ack_req , " FE-establish_acknowledge_request " } ,
{ V5x_PSTN_LE_FE_line_signal_req , " FE-line_signal_request " } ,
{ V5x_PSTN_LE_FE_protocol_param_req , " FE-protocol_parameter_request " } ,
{ V5x_PSTN_LE_FE_disconnect_req , " FE-disconnect_request " } ,
{ V5x_PSTN_LE_FE_disconnect_compl_req , " FE-disconnect_complete_request " } ,
{ V5x_PSTN_LE_DISCONNECT , " DISCONNECT " } ,
{ V5x_PSTN_LE_DISCONNECT_COMPL , " DISCONNECT COMPLETE " } ,
{ V5x_PSTN_LE_ESTABLISH , " ESTABLISH " } ,
{ V5x_PSTN_LE_ESTABLISH_ACK , " ESTABLISH ACK " } ,
{ V5x_PSTN_LE_SIGNAL , " SIGNAL " } ,
{ V5x_PSTN_LE_SIGNAL_ACK , " SIGNAL_ACK " } ,
{ V5x_PSTN_LE_STATUS , " STATUS " } ,
{ V5x_PSTN_LE_TIMEOUT_T1 , " TIMEOUT T1 " } ,
{ V5x_PSTN_LE_TIMEOUT_T3 , " TIMEOUT T3 " } ,
{ V5x_PSTN_LE_TIMEOUT_T4 , " TIMEOUT T4 " } ,
{ V5x_PSTN_LE_TIMEOUT_Tr , " TIMEOUT Tr " } ,
{ V5x_PSTN_LE_TIMEOUT_Tt , " TIMEOUT Tt " } ,
{ V5x_PSTN_LE_MDU_CTRL_port_blocked , " MDU-CTRL (port blocked) " } ,
{ V5x_PSTN_LE_MDU_CTRL_port_unblocked , " MDU-CTRL (port unblocked) " } ,
{ V5x_PSTN_LE_MDU_CTRL_restart_req , " MDU-CTRL (restart request) " } ,
{ V5x_PSTN_LE_MDU_CTRL_restart_compl_req , " MDU-CTRL (restart complete) " } ,
{ 0 , NULL }
} ;
/***********************************************************************
* V5 Message encoding / sending
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* G.964 Section 13.3.1 / Table 5 */
static struct msgb * v5x_enc_establish ( struct v5x_user_port * v5up , uint8_t * cond_ie , uint8_t cond_len )
{
2022-12-16 17:49:11 +00:00
struct v5x_l3_hdr * l3h ;
2022-12-09 18:20:45 +00:00
struct msgb * msg = msgb_alloc_v5x ( ) ;
if ( ! msg )
return NULL ;
2022-12-16 17:49:11 +00:00
l3h = ( struct v5x_l3_hdr * ) msgb_put ( msg , sizeof ( * l3h ) ) ;
l3h - > pdisc = V5X_CTRL_PDISC ;
2022-12-26 13:44:39 +00:00
l3h - > l3_addr = htons ( v5x_l3_addr_enc ( v5up - > nr , false ) ) ;
2022-12-16 17:49:11 +00:00
l3h - > msg_type = V5X_CTRL_MSGT_ESTABLISH ;
2022-12-09 18:20:45 +00:00
/* optional conditional IE */
if ( cond_ie & & cond_len )
memcpy ( msgb_put ( msg , cond_len ) , cond_ie , cond_len ) ;
return msg ;
}
/* G.964 Section 13.3.1 / Table 6 */
static struct msgb * v5x_enc_establish_ack ( struct v5x_user_port * v5up , uint8_t * cond_ie , uint8_t cond_len )
{
2022-12-16 17:49:11 +00:00
struct v5x_l3_hdr * l3h ;
2022-12-09 18:20:45 +00:00
struct msgb * msg = msgb_alloc_v5x ( ) ;
if ( ! msg )
return NULL ;
2022-12-16 17:49:11 +00:00
l3h = ( struct v5x_l3_hdr * ) msgb_put ( msg , sizeof ( * l3h ) ) ;
l3h - > pdisc = V5X_CTRL_PDISC ;
2022-12-26 13:44:39 +00:00
l3h - > l3_addr = htons ( v5x_l3_addr_enc ( v5up - > nr , false ) ) ;
2022-12-16 17:49:11 +00:00
l3h - > msg_type = V5X_CTRL_MSGT_ESTABLISH_ACK ;
2022-12-09 18:20:45 +00:00
/* optional conditional IE */
if ( cond_ie & & cond_len )
memcpy ( msgb_put ( msg , cond_len ) , cond_ie , cond_len ) ;
return msg ;
}
/* G.964 Section 13.3.1 / Table 7 */
static struct msgb * v5x_enc_signal ( struct v5x_user_port * v5up , uint8_t seq_nr , uint8_t * cond_ie , uint8_t cond_len )
{
uint8_t seq_ie = seq_nr | 0x80 ;
2022-12-16 17:49:11 +00:00
struct v5x_l3_hdr * l3h ;
2022-12-09 18:20:45 +00:00
struct msgb * msg = msgb_alloc_v5x ( ) ;
if ( ! msg )
return NULL ;
2022-12-16 17:49:11 +00:00
l3h = ( struct v5x_l3_hdr * ) msgb_put ( msg , sizeof ( * l3h ) ) ;
l3h - > pdisc = V5X_CTRL_PDISC ;
2022-12-26 13:44:39 +00:00
l3h - > l3_addr = htons ( v5x_l3_addr_enc ( v5up - > nr , false ) ) ;
2022-12-16 17:49:11 +00:00
l3h - > msg_type = V5X_CTRL_MSGT_SIGNAL ;
2022-12-09 18:20:45 +00:00
/* Sequence-number */
2022-12-16 17:49:11 +00:00
msgb_tlv_put ( msg , V5X_CTRL_IEI_SEQUENCE_NR , 1 , & seq_ie ) ;
2022-12-09 18:20:45 +00:00
/* manatory conditional IE */
OSMO_ASSERT ( cond_ie & & cond_len ) ;
memcpy ( msgb_put ( msg , cond_len ) , cond_ie , cond_len ) ;
return msg ;
}
/* G.964 Section 13.3.1 / Table 8 */
static struct msgb * v5x_enc_signal_ack ( struct v5x_user_port * v5up , uint8_t seq_nr )
{
uint8_t seq_ie = seq_nr | 0x80 ;
2022-12-16 17:49:11 +00:00
struct v5x_l3_hdr * l3h ;
2022-12-09 18:20:45 +00:00
struct msgb * msg = msgb_alloc_v5x ( ) ;
if ( ! msg )
return NULL ;
2022-12-16 17:49:11 +00:00
l3h = ( struct v5x_l3_hdr * ) msgb_put ( msg , sizeof ( * l3h ) ) ;
l3h - > pdisc = V5X_CTRL_PDISC ;
2022-12-26 13:44:39 +00:00
l3h - > l3_addr = htons ( v5x_l3_addr_enc ( v5up - > nr , false ) ) ;
2022-12-16 17:49:11 +00:00
l3h - > msg_type = V5X_CTRL_MSGT_SIGNAL_ACK ;
2022-12-09 18:20:45 +00:00
/* Sequence-number */
2022-12-16 17:49:11 +00:00
msgb_tlv_put ( msg , V5X_CTRL_IEI_SEQUENCE_NR , 1 , & seq_ie ) ;
2022-12-09 18:20:45 +00:00
return msg ;
}
/* G.964 Section 13.3.1 / Table 10 */
static struct msgb * v5x_enc_status_enquiry ( struct v5x_user_port * v5up )
{
2022-12-16 17:49:11 +00:00
struct v5x_l3_hdr * l3h ;
2022-12-09 18:20:45 +00:00
struct msgb * msg = msgb_alloc_v5x ( ) ;
if ( ! msg )
return NULL ;
2022-12-16 17:49:11 +00:00
l3h = ( struct v5x_l3_hdr * ) msgb_put ( msg , sizeof ( * l3h ) ) ;
l3h - > pdisc = V5X_CTRL_PDISC ;
2022-12-26 13:44:39 +00:00
l3h - > l3_addr = htons ( v5x_l3_addr_enc ( v5up - > nr , false ) ) ;
2022-12-16 17:49:11 +00:00
l3h - > msg_type = V5X_CTRL_MSGT_STATUS_ENQUIRY ;
2022-12-09 18:20:45 +00:00
return msg ;
}
/* G.964 Section 13.3.1 / Table 11 */
static struct msgb * v5x_enc_disconnect ( struct v5x_user_port * v5up , uint8_t * steady_ie , uint8_t steady_len )
{
2022-12-16 17:49:11 +00:00
struct v5x_l3_hdr * l3h ;
2022-12-09 18:20:45 +00:00
struct msgb * msg = msgb_alloc_v5x ( ) ;
if ( ! msg )
return NULL ;
2022-12-16 17:49:11 +00:00
l3h = ( struct v5x_l3_hdr * ) msgb_put ( msg , sizeof ( * l3h ) ) ;
l3h - > pdisc = V5X_CTRL_PDISC ;
2022-12-26 13:44:39 +00:00
l3h - > l3_addr = htons ( v5x_l3_addr_enc ( v5up - > nr , false ) ) ;
2022-12-16 17:49:11 +00:00
l3h - > msg_type = V5X_CTRL_MSGT_DISCONNECT ;
2022-12-09 18:20:45 +00:00
/* optional conditional IE */
if ( steady_ie & & steady_len )
memcpy ( msgb_put ( msg , steady_len ) , steady_ie , steady_len ) ;
return msg ;
}
/* G.964 Section 13.3.1 / Table 12 */
static struct msgb * v5x_enc_disconnect_compl ( struct v5x_user_port * v5up , uint8_t * steady_ie , uint8_t steady_len )
{
2022-12-16 17:49:11 +00:00
struct v5x_l3_hdr * l3h ;
2022-12-09 18:20:45 +00:00
struct msgb * msg = msgb_alloc_v5x ( ) ;
if ( ! msg )
return NULL ;
2022-12-16 17:49:11 +00:00
l3h = ( struct v5x_l3_hdr * ) msgb_put ( msg , sizeof ( * l3h ) ) ;
l3h - > pdisc = V5X_CTRL_PDISC ;
2022-12-26 13:44:39 +00:00
l3h - > l3_addr = htons ( v5x_l3_addr_enc ( v5up - > nr , false ) ) ;
2022-12-16 17:49:11 +00:00
l3h - > msg_type = V5X_CTRL_MSGT_DISCONNECT_COMPLETE ;
2022-12-09 18:20:45 +00:00
/* optional conditional IE */
if ( steady_ie & & steady_len )
memcpy ( msgb_put ( msg , steady_len ) , steady_ie , steady_len ) ;
return msg ;
}
/* G.964 Section 13.3.1 / Table 13 */
static struct msgb * v5x_enc_protocol_param ( struct v5x_user_port * v5up , uint8_t seq_nr , uint8_t * cond_ie , uint8_t cond_len )
{
uint8_t seq_ie = seq_nr | 0x80 ;
2022-12-16 17:49:11 +00:00
struct v5x_l3_hdr * l3h ;
2022-12-09 18:20:45 +00:00
struct msgb * msg = msgb_alloc_v5x ( ) ;
if ( ! msg )
return NULL ;
2022-12-16 17:49:11 +00:00
l3h = ( struct v5x_l3_hdr * ) msgb_put ( msg , sizeof ( * l3h ) ) ;
l3h - > pdisc = V5X_CTRL_PDISC ;
2022-12-26 13:44:39 +00:00
l3h - > l3_addr = htons ( v5x_l3_addr_enc ( v5up - > nr , false ) ) ;
2022-12-16 17:49:11 +00:00
l3h - > msg_type = V5X_CTRL_MSGT_PROTOCOL_PARAMETER ;
2022-12-09 18:20:45 +00:00
/* Sequence-number */
2022-12-16 17:49:11 +00:00
msgb_tlv_put ( msg , V5X_CTRL_IEI_SEQUENCE_NR , 1 , & seq_ie ) ;
2022-12-09 18:20:45 +00:00
/* manatory conditional IE */
OSMO_ASSERT ( cond_ie & & cond_len ) ;
memcpy ( msgb_put ( msg , cond_len ) , cond_ie , cond_len ) ;
return msg ;
}
/***********************************************************************/
/* upper layer interface */
/***********************************************************************/
static void rcv_fe ( struct osmo_fsm_inst * fi , enum v5x_fe_prim prim , const struct tlv_parsed * tp )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
struct msgb * msg ;
uint8_t * tlv , len ;
msg = msgb_alloc_v5x ( ) ;
OSMO_ASSERT ( msg ) ;
/* add IE, if tp was given */
if ( tp ) {
/* single octet */
2022-12-16 17:49:11 +00:00
if ( TLVP_PRESENT ( tp , V5X_CTRL_IEI_PULSE_NOTIFICATION ) )
* msgb_put ( msg , 1 ) = * TLVP_VAL ( tp , V5X_CTRL_IEI_PULSE_NOTIFICATION ) ;
if ( TLVP_PRESENT ( tp , V5X_CTRL_IEI_LINE_INFORMATION ) )
* msgb_put ( msg , 1 ) = * TLVP_VAL ( tp , V5X_CTRL_IEI_LINE_INFORMATION ) ;
if ( TLVP_PRESENT ( tp , V5X_CTRL_IEI_SEQUENCE_RESPONSE ) )
* msgb_put ( msg , 1 ) = * TLVP_VAL ( tp , V5X_CTRL_IEI_SEQUENCE_RESPONSE ) ;
2022-12-09 18:20:45 +00:00
/* multiple octets */
2022-12-16 17:49:11 +00:00
if ( TLVP_PRESENT ( tp , V5X_CTRL_IEI_PULSED_SIGNAL ) ) {
len = TLVP_LEN ( tp , V5X_CTRL_IEI_PULSED_SIGNAL ) ;
2022-12-09 18:20:45 +00:00
tlv = msgb_put ( msg , 2 + len ) ;
2022-12-16 17:49:11 +00:00
tlv [ 0 ] = V5X_CTRL_IEI_PULSED_SIGNAL ;
2022-12-09 18:20:45 +00:00
tlv [ 1 ] = len ;
2022-12-16 17:49:11 +00:00
memcpy ( tlv + 2 , TLVP_VAL ( tp , V5X_CTRL_IEI_PULSED_SIGNAL ) , len ) ;
2022-12-09 18:20:45 +00:00
}
2022-12-16 17:49:11 +00:00
if ( TLVP_PRESENT ( tp , V5X_CTRL_IEI_STEADY_SIGNAL ) ) {
len = TLVP_LEN ( tp , V5X_CTRL_IEI_STEADY_SIGNAL ) ;
2022-12-09 18:20:45 +00:00
tlv = msgb_put ( msg , 2 + len ) ;
2022-12-16 17:49:11 +00:00
tlv [ 0 ] = V5X_CTRL_IEI_STEADY_SIGNAL ;
2022-12-09 18:20:45 +00:00
tlv [ 1 ] = len ;
2022-12-16 17:49:11 +00:00
memcpy ( tlv + 2 , TLVP_VAL ( tp , V5X_CTRL_IEI_STEADY_SIGNAL ) , len ) ;
2022-12-09 18:20:45 +00:00
}
2022-12-16 17:49:11 +00:00
if ( TLVP_PRESENT ( tp , V5X_CTRL_IEI_DIGIT_SIGNAL ) ) {
len = TLVP_LEN ( tp , V5X_CTRL_IEI_DIGIT_SIGNAL ) ;
2022-12-09 18:20:45 +00:00
tlv = msgb_put ( msg , 2 + len ) ;
2022-12-16 17:49:11 +00:00
tlv [ 0 ] = V5X_CTRL_IEI_DIGIT_SIGNAL ;
2022-12-09 18:20:45 +00:00
tlv [ 1 ] = len ;
2022-12-16 17:49:11 +00:00
memcpy ( tlv + 2 , TLVP_VAL ( tp , V5X_CTRL_IEI_DIGIT_SIGNAL ) , len ) ;
2022-12-09 18:20:45 +00:00
}
2022-12-16 17:49:11 +00:00
if ( TLVP_PRESENT ( tp , V5X_CTRL_IEI_RESOURCE_UNAVAILABLE ) ) {
len = TLVP_LEN ( tp , V5X_CTRL_IEI_RESOURCE_UNAVAILABLE ) ;
2022-12-09 18:20:45 +00:00
tlv = msgb_put ( msg , 2 + len ) ;
2022-12-16 17:49:11 +00:00
tlv [ 0 ] = V5X_CTRL_IEI_RESOURCE_UNAVAILABLE ;
2022-12-09 18:20:45 +00:00
tlv [ 1 ] = len ;
2022-12-16 17:49:11 +00:00
memcpy ( tlv + 2 , TLVP_VAL ( tp , V5X_CTRL_IEI_RESOURCE_UNAVAILABLE ) , len ) ;
2022-12-09 18:20:45 +00:00
}
2022-12-16 17:49:11 +00:00
if ( TLVP_PRESENT ( tp , V5X_CTRL_IEI_METERING_REPORT ) ) {
len = TLVP_LEN ( tp , V5X_CTRL_IEI_METERING_REPORT ) ;
2022-12-09 18:20:45 +00:00
tlv = msgb_put ( msg , 2 + len ) ;
2022-12-16 17:49:11 +00:00
tlv [ 0 ] = V5X_CTRL_IEI_METERING_REPORT ;
2022-12-09 18:20:45 +00:00
tlv [ 1 ] = len ;
2022-12-16 17:49:11 +00:00
memcpy ( tlv + 2 , TLVP_VAL ( tp , V5X_CTRL_IEI_METERING_REPORT ) , len ) ;
2022-12-09 18:20:45 +00:00
}
}
2022-12-26 13:44:39 +00:00
v5x_le_pstn_fe_rcv ( pstn - > v5up , prim , msg ) ;
2022-12-09 18:20:45 +00:00
}
static void rcv_mdu ( struct osmo_fsm_inst * fi , enum v5x_mgmt_prim prim )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
2022-12-26 13:44:39 +00:00
v5x_le_pstn_mdu_rcv ( pstn - > v5up , prim ) ;
2022-12-09 18:20:45 +00:00
}
2022-12-16 17:49:11 +00:00
void v5x_le_pstn_fe_snd ( struct v5x_user_port * v5up , enum v5x_fe_prim prim , struct msgb * msg )
2022-12-09 18:20:45 +00:00
{
struct v5x_pstn_proto * pstn = v5up - > pstn . proto ;
struct osmo_fsm_inst * fi = pstn - > fi ;
enum v5x_le_pstn_fsm_event event ;
int rc ;
OSMO_ASSERT ( msg ) ;
switch ( prim ) {
case FE_establish_req :
event = V5x_PSTN_LE_FE_establish_req ;
break ;
case FE_establish_ack_req :
event = V5x_PSTN_LE_FE_establish_ack_req ;
break ;
case FE_line_signal_req :
event = V5x_PSTN_LE_FE_line_signal_req ;
break ;
case FE_protocol_param_req :
event = V5x_PSTN_LE_FE_protocol_param_req ;
break ;
case FE_disconnect_req :
event = V5x_PSTN_LE_FE_disconnect_req ;
break ;
case FE_disconnect_compl_req :
event = V5x_PSTN_LE_FE_disconnect_compl_req ;
break ;
default :
LOGP ( DV5PSTN , LOGL_NOTICE , " Got invalid prim %d at this protocol \n " , prim ) ;
return ;
}
/* send event to FSM */
rc = osmo_fsm_inst_dispatch ( fi , event , msg ) ;
if ( rc < 0 )
msgb_free ( msg ) ;
}
2022-12-16 17:49:11 +00:00
void v5x_le_pstn_mdu_snd ( struct v5x_user_port * v5up , enum v5x_mgmt_prim prim )
2022-12-09 18:20:45 +00:00
{
struct v5x_pstn_proto * pstn = v5up - > pstn . proto ;
struct osmo_fsm_inst * fi = pstn - > fi ;
enum v5x_le_pstn_fsm_event event ;
switch ( prim ) {
case MDU_CTRL_port_blocked :
event = V5x_PSTN_LE_MDU_CTRL_port_blocked ;
break ;
case MDU_CTRL_port_unblocked :
event = V5x_PSTN_LE_MDU_CTRL_port_unblocked ;
break ;
case MDU_CTRL_port_restart_req :
event = V5x_PSTN_LE_MDU_CTRL_restart_req ;
break ;
case MDU_CTRL_port_restart_compl :
event = V5x_PSTN_LE_MDU_CTRL_restart_compl_req ;
break ;
default :
LOGP ( DV5PSTN , LOGL_NOTICE , " Got invalid prim %d at this protocol \n " , prim ) ;
return ;
}
/* send event to FSM */
osmo_fsm_inst_dispatch ( fi , event , NULL ) ;
}
2022-12-26 13:44:39 +00:00
/***********************************************************************/
/* lower layer interface */
/***********************************************************************/
static void dl_send ( struct osmo_fsm_inst * fi , struct msgb * msg )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
v5x_dl_snd ( pstn - > v5up - > interface , V5X_DLADDR_PSTN , msg ) ;
}
2022-12-09 18:20:45 +00:00
/***********************************************************************/
/* PSTN state FSM */
/***********************************************************************/
2022-12-26 13:44:39 +00:00
static void start_timer_Tr ( struct v5x_pstn_proto * pstn )
{
LOGP ( DV5PSTN , LOGL_DEBUG , " Start timer Tr \n " ) ;
osmo_timer_schedule ( & pstn - > timer_Tr , TIMEOUT_Tr , 0 ) ;
}
static void start_timer_Tt ( struct v5x_pstn_proto * pstn )
{
LOGP ( DV5PSTN , LOGL_DEBUG , " Start timer Tt \n " ) ;
osmo_timer_schedule ( & pstn - > timer_Tt , TIMEOUT_Tt , 0 ) ;
}
static void stop_timer_Tr ( struct v5x_pstn_proto * pstn )
{
if ( osmo_timer_pending ( & pstn - > timer_Tr ) ) {
LOGP ( DV5PSTN , LOGL_DEBUG , " Stop timer Tr \n " ) ;
osmo_timer_del ( & pstn - > timer_Tr ) ;
}
}
static void stop_timer_Tt ( struct v5x_pstn_proto * pstn )
{
if ( osmo_timer_pending ( & pstn - > timer_Tt ) ) {
LOGP ( DV5PSTN , LOGL_DEBUG , " Stop timer Tt \n " ) ;
osmo_timer_del ( & pstn - > timer_Tt ) ;
}
}
static void stop_timer ( struct osmo_fsm_inst * fi )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
LOGP ( DV5PSTN , LOGL_DEBUG , " Stop all timers \n " ) ;
osmo_timer_del ( & fi - > timer ) ;
stop_timer_Tr ( pstn ) ;
stop_timer_Tt ( pstn ) ;
}
static void start_timer ( struct osmo_fsm_inst * fi , enum v5x_le_pstn_fsm_event event , int count )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
int timeout = 0 ;
const char * timer_name = NULL ;
switch ( event ) {
case V5x_PSTN_LE_TIMEOUT_T1 :
timer_name = " T1 " ;
timeout = TIMEOUT_T1 ;
fi - > T = 1 ;
break ;
case V5x_PSTN_LE_TIMEOUT_T3 :
timer_name = " T3 " ;
timeout = TIMEOUT_T3 ;
fi - > T = 3 ;
break ;
case V5x_PSTN_LE_TIMEOUT_T4 :
timer_name = " T4 " ;
timeout = TIMEOUT_T4 ;
fi - > T = 4 ;
break ;
default :
OSMO_ASSERT ( 0 ) ;
}
LOGP ( DV5PSTN , LOGL_DEBUG , " Start timer %s (count = %d) \n " , timer_name , count ) ;
pstn - > timeout_event = event ;
pstn - > timeout_count = count ;
osmo_timer_schedule ( & fi - > timer , timeout , 0 ) ;
}
2022-12-09 18:20:45 +00:00
static int v5x_le_pstn_fsm_timer_cb ( struct osmo_fsm_inst * fi )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
osmo_fsm_inst_dispatch ( fi , pstn - > timeout_event , NULL ) ;
return 0 ;
}
static void timeout_Tr_cb ( void * data )
{
struct v5x_pstn_proto * pstn = data ;
osmo_fsm_inst_dispatch ( pstn - > fi , V5x_PSTN_LE_TIMEOUT_Tr , NULL ) ;
}
static void timeout_Tt_cb ( void * data )
{
struct v5x_pstn_proto * pstn = data ;
osmo_fsm_inst_dispatch ( pstn - > fi , V5x_PSTN_LE_TIMEOUT_Tt , NULL ) ;
}
static void do_status_enquiry ( struct osmo_fsm_inst * fi )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
LOGP ( DV5PSTN , LOGL_NOTICE , " Received message not allowed in current state, sending status enquiry. \n " ) ;
/* start T4 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T4 , 1 ) ;
/* send STATUS ENQUIRY */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_status_enquiry ( pstn - > v5up ) ) ;
2022-12-09 18:20:45 +00:00
}
static void do_establish_request ( struct osmo_fsm_inst * fi , struct msgb * msg )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
/* change state to LE2 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE2_PATH_INITIATED_LE , 0 , 0 ) ;
/* init sequence variables */
pstn - > S_s = pstn - > S_a = pstn - > S_r = 0 ;
/* start T1 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T1 , 1 ) ;
/* store ESTABLISH message */
if ( pstn - > tx_msg )
msgb_free ( pstn - > tx_msg ) ;
pstn - > tx_msg = msgb_copy ( msg , NULL ) ;
/* send ESTABLISH */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_establish ( pstn - > v5up , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
}
static void do_establish_indication ( struct osmo_fsm_inst * fi , const struct tlv_parsed * tp )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
/* init sequence variables */
pstn - > S_s = pstn - > S_a = pstn - > S_r = 0 ;
/* send FE-establish_indication */
rcv_fe ( fi , FE_establish_ind , tp ) ;
}
static void do_disconnect_complete ( struct osmo_fsm_inst * fi , const struct tlv_parsed * tp )
{
/* change state to LE1 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE1_NULL , 0 , 0 ) ;
/* stop all timers */
stop_timer ( fi ) ;
/* send FE-disconnect_complete_indication */
rcv_fe ( fi , FE_disconnect_compl_ind , tp ) ;
}
static void do_disconnect_with_error ( struct osmo_fsm_inst * fi )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
/* change state to LE5 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ , 0 , 0 ) ;
/* stop all timers */
stop_timer ( fi ) ;
/* start T3 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T3 , 1 ) ;
/* store empty disconnect message */
if ( pstn - > tx_msg ) {
msgb_free ( pstn - > tx_msg ) ;
pstn - > tx_msg = NULL ;
}
/* send DISCONNECT */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
/* send MDU-error_indication */
rcv_mdu ( fi , MDU_error_ind ) ;
}
static void do_block ( struct osmo_fsm_inst * fi )
{
/* change state to LE6 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE6_PORT_BLOCKED , 0 , 0 ) ;
/* stop all timers */
stop_timer ( fi ) ;
/* send FE-disconnect_complete_indication */
rcv_fe ( fi , FE_disconnect_compl_ind , NULL ) ;
}
static void do_restart ( struct osmo_fsm_inst * fi )
{
/* change state to LE0 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE0_OUT_OF_SERVICE , 0 , 0 ) ;
/* send FE-disconnect_complete_indication */
rcv_fe ( fi , FE_disconnect_compl_ind , NULL ) ;
/* send MDU-CTRL (restart ack) */
rcv_mdu ( fi , MDU_CTRL_port_restart_ack ) ;
}
static void pstn_le0_out_of_service ( struct osmo_fsm_inst * fi , uint32_t event , void * data )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
struct msgb * msg = data ;
const struct tlv_parsed * tp = data ;
uint8_t cause ;
switch ( event ) {
case V5x_PSTN_LE_FE_establish_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_ESTABLISH :
case V5x_PSTN_LE_DISCONNECT :
case V5x_PSTN_LE_ESTABLISH_ACK :
case V5x_PSTN_LE_SIGNAL :
case V5x_PSTN_LE_SIGNAL_ACK :
/* do several thing here */
do_status_enquiry ( fi ) ;
break ;
case V5x_PSTN_LE_DISCONNECT_COMPL :
/* ignore */
break ;
case V5x_PSTN_LE_FE_establish_ack_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_STATUS :
2022-12-16 17:49:11 +00:00
cause = * TLVP_VAL ( tp , V5X_CTRL_IEI_CAUSE ) & 0x7f ;
2022-12-09 18:20:45 +00:00
if ( cause = = 0 ) {
/* stop T4 */
stop_timer ( fi ) ;
} else {
/* send MDU-error_indication */
rcv_mdu ( fi , MDU_error_ind ) ;
}
break ;
case V5x_PSTN_LE_FE_protocol_param_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_FE_disconnect_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_port_blocked :
/* change state to LE6 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE6_PORT_BLOCKED , 0 , 0 ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_port_unblocked :
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_req :
/* send MDU-CTRL (restart ack) */
rcv_mdu ( fi , MDU_CTRL_port_restart_ack ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_compl_req :
/* change state to LE1 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE1_NULL , 0 , 0 ) ;
break ;
case V5x_PSTN_LE_TIMEOUT_T4 :
/* first or second timeout ? */
if ( pstn - > timeout_count < = 3 ) {
/* start T4 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T4 , pstn - > timeout_count + 1 ) ;
/* send STATUS ENQUIRY again */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_status_enquiry ( pstn - > v5up ) ) ;
2022-12-09 18:20:45 +00:00
} else {
/* send MDU-error_indication */
rcv_mdu ( fi , MDU_error_ind ) ;
}
break ;
2022-12-26 13:44:39 +00:00
default :
OSMO_ASSERT ( 0 ) ;
2022-12-09 18:20:45 +00:00
}
}
static void pstn_le1_null ( struct osmo_fsm_inst * fi , uint32_t event , void * data )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
struct msgb * msg = data ;
const struct tlv_parsed * tp = data ;
uint8_t cause ;
switch ( event ) {
case V5x_PSTN_LE_FE_establish_req :
/* do several thing here */
do_establish_request ( fi , msg ) ;
break ;
case V5x_PSTN_LE_ESTABLISH :
/* change state to LE3 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE3_PATH_INITIATED_AN , 0 , 0 ) ;
/* do several thing here */
do_establish_indication ( fi , tp ) ;
break ;
case V5x_PSTN_LE_DISCONNECT :
/* send DISCONNECT COMPLETE */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect_compl ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
break ;
case V5x_PSTN_LE_ESTABLISH_ACK :
case V5x_PSTN_LE_SIGNAL :
case V5x_PSTN_LE_SIGNAL_ACK :
/* do several thing here */
do_status_enquiry ( fi ) ;
break ;
case V5x_PSTN_LE_STATUS :
2022-12-16 17:49:11 +00:00
cause = * TLVP_VAL ( tp , V5X_CTRL_IEI_CAUSE ) & 0x7f ;
2022-12-09 18:20:45 +00:00
if ( cause = = 0 ) {
/* stop T4 */
stop_timer ( fi ) ;
} else {
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_FE_protocol_param_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_port_blocked :
/* do several thing here */
do_block ( fi ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_port_unblocked :
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_req :
/* do several thing here */
do_restart ( fi ) ;
break ;
case V5x_PSTN_LE_TIMEOUT_T4 :
/* first or second timeout ? */
if ( pstn - > timeout_count < 3 ) {
/* start T4 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T4 , pstn - > timeout_count + 1 ) ;
/* send STATUS ENQUIRY again */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_status_enquiry ( pstn - > v5up ) ) ;
2022-12-09 18:20:45 +00:00
} else {
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
2022-12-26 13:44:39 +00:00
default :
OSMO_ASSERT ( 0 ) ;
2022-12-09 18:20:45 +00:00
}
}
static void pstn_le2_path_initiated_le ( struct osmo_fsm_inst * fi , uint32_t event , void * data )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
struct msgb * msg = data ;
const struct tlv_parsed * tp = data ;
uint8_t cause ;
switch ( event ) {
case V5x_PSTN_LE_ESTABLISH :
/* do several thing here */
do_establish_indication ( fi , tp ) ;
break ;
case V5x_PSTN_LE_DISCONNECT :
/* send DISCONNECT COMPLETE */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect_compl ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
/* do several thing here */
do_disconnect_complete ( fi , tp ) ;
break ;
case V5x_PSTN_LE_DISCONNECT_COMPL :
/* do several thing here */
do_disconnect_complete ( fi , tp ) ;
break ;
case V5x_PSTN_LE_FE_establish_ack_req :
/* change state to LE4 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE4_PATH_ACTIVE , 0 , 0 ) ;
/* stop T1 */
stop_timer ( fi ) ;
/* send ESTABLISH ACK */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_establish_ack ( pstn - > v5up , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
break ;
case V5x_PSTN_LE_ESTABLISH_ACK :
/* change state to LE4 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE4_PATH_ACTIVE , 0 , 0 ) ;
/* stop T1 */
stop_timer ( fi ) ;
/* send FE-establish_acknowledge_indication */
rcv_fe ( fi , FE_establish_ack_ind , tp ) ;
break ;
case V5x_PSTN_LE_SIGNAL :
case V5x_PSTN_LE_SIGNAL_ACK :
/* do several thing here */
do_status_enquiry ( fi ) ;
break ;
case V5x_PSTN_LE_STATUS :
2022-12-16 17:49:11 +00:00
cause = * TLVP_VAL ( tp , V5X_CTRL_IEI_CAUSE ) & 0x7f ;
2022-12-09 18:20:45 +00:00
if ( cause = = 0 ) {
/* stop T4 */
stop_timer ( fi ) ;
} else {
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_FE_protocol_param_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_FE_disconnect_req :
/* change state to LE5 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ , 0 , 0 ) ;
/* stop all timers */
stop_timer ( fi ) ;
/* start T3 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T3 , 2 ) ;
/* store DISCONNECT message */
if ( pstn - > tx_msg )
msgb_free ( pstn - > tx_msg ) ;
pstn - > tx_msg = msgb_copy ( msg , NULL ) ;
/* send DISCONNECT */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect ( pstn - > v5up , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
break ;
case V5x_PSTN_LE_FE_disconnect_compl_req :
// NOTE: The Table 31-32/G.964 is wrong at this point, there is no use here
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_port_blocked :
/* do several thing here */
do_block ( fi ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_port_unblocked :
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_req :
/* send DISCONNECT COMPLETE */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect_compl ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
/* do several thing here */
do_restart ( fi ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_compl_req :
/* ignore */
break ;
case V5x_PSTN_LE_TIMEOUT_T1 :
/* first timeout ? */
if ( pstn - > timeout_count = = 1 ) {
/* start T1 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T1 , 2 ) ;
/* send ESTABLISH again */
OSMO_ASSERT ( pstn - > tx_msg ) ;
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_establish ( pstn - > v5up , pstn - > tx_msg - > data , pstn - > tx_msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
} else {
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_TIMEOUT_T4 :
/* first or second timeout ? */
if ( pstn - > timeout_count < 3 ) {
/* start T4 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T4 , pstn - > timeout_count + 1 ) ;
/* send STATUS ENQUIRY again */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_status_enquiry ( pstn - > v5up ) ) ;
2022-12-09 18:20:45 +00:00
} else {
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
2022-12-26 13:44:39 +00:00
default :
OSMO_ASSERT ( 0 ) ;
2022-12-09 18:20:45 +00:00
}
}
static void pstn_le3_path_initiated_an ( struct osmo_fsm_inst * fi , uint32_t event , void * data )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
struct msgb * msg = data ;
const struct tlv_parsed * tp = data ;
uint8_t cause ;
switch ( event ) {
case V5x_PSTN_LE_FE_establish_req :
/* do several thing here */
do_establish_request ( fi , msg ) ;
break ;
case V5x_PSTN_LE_ESTABLISH :
/* do several thing here */
do_establish_indication ( fi , tp ) ;
break ;
case V5x_PSTN_LE_DISCONNECT :
/* send DISCONNECT COMPLETE */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect_compl ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
/* do several thing here */
do_disconnect_complete ( fi , tp ) ;
break ;
case V5x_PSTN_LE_DISCONNECT_COMPL :
/* do several thing here */
do_disconnect_complete ( fi , tp ) ;
break ;
case V5x_PSTN_LE_FE_establish_ack_req :
/* change state to LE4 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE4_PATH_ACTIVE , 0 , 0 ) ;
/* send ESTABLISH ACK */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_establish_ack ( pstn - > v5up , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
break ;
case V5x_PSTN_LE_ESTABLISH_ACK :
case V5x_PSTN_LE_SIGNAL :
case V5x_PSTN_LE_SIGNAL_ACK :
/* do several thing here */
do_status_enquiry ( fi ) ;
break ;
case V5x_PSTN_LE_STATUS :
2022-12-16 17:49:11 +00:00
cause = * TLVP_VAL ( tp , V5X_CTRL_IEI_CAUSE ) & 0x7f ;
2022-12-09 18:20:45 +00:00
if ( cause = = 0 ) {
/* stop T4 */
stop_timer ( fi ) ;
} else {
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_FE_protocol_param_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_FE_disconnect_req :
/* change state to LE5 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ , 0 , 0 ) ;
/* stop all timers */
stop_timer ( fi ) ;
/* start T3 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T3 , 2 ) ;
/* store DISCONNECT message */
if ( pstn - > tx_msg )
msgb_free ( pstn - > tx_msg ) ;
pstn - > tx_msg = msgb_copy ( msg , NULL ) ;
/* Send DISCONNECT */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect ( pstn - > v5up , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
break ;
case V5x_PSTN_LE_FE_disconnect_compl_req :
/* change state to LE1 */
// NOTE: The Table 31-32/G.964 is wrong at this point, see Figure B.3/G.964
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE1_NULL , 0 , 0 ) ;
/* stop all timers */
stop_timer ( fi ) ;
/* send DISCONNECT COMPLETE */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect_compl ( pstn - > v5up , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_port_blocked :
/* do several thing here */
do_block ( fi ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_port_unblocked :
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_req :
/* send DISCONNECT COMPLETE */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect_compl ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
/* do several thing here */
do_restart ( fi ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_compl_req :
/* ignore */
break ;
case V5x_PSTN_LE_TIMEOUT_T4 :
/* first or second timeout ? */
if ( pstn - > timeout_count < 3 ) {
/* start T4 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T4 , pstn - > timeout_count + 1 ) ;
/* send STATUS ENQUIRY again */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_status_enquiry ( pstn - > v5up ) ) ;
2022-12-09 18:20:45 +00:00
} else {
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
2022-12-26 13:44:39 +00:00
default :
OSMO_ASSERT ( 0 ) ;
2022-12-09 18:20:45 +00:00
}
}
static void pstn_le4_path_active ( struct osmo_fsm_inst * fi , uint32_t event , void * data )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
struct msgb * msg = data ;
const struct tlv_parsed * tp = data ;
uint8_t cause , seq_nr , unacked , acked ;
switch ( event ) {
case V5x_PSTN_LE_ESTABLISH :
/* do several thing here */
do_status_enquiry ( fi ) ;
break ;
case V5x_PSTN_LE_DISCONNECT :
/* send DISCONNECT COMPLETE */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect_compl ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
/* do several thing here */
do_disconnect_complete ( fi , tp ) ;
break ;
case V5x_PSTN_LE_DISCONNECT_COMPL :
/* send FE-disconnect_complete_indication */
rcv_fe ( fi , FE_disconnect_compl_ind , NULL ) ;
/* do several thing here */
do_disconnect_complete ( fi , tp ) ;
break ;
case V5x_PSTN_LE_ESTABLISH_ACK :
/* start T4 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T4 , 1 ) ;
/* send STATUS ENQUIRY */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_status_enquiry ( pstn - > v5up ) ) ;
2022-12-09 18:20:45 +00:00
break ;
case V5x_PSTN_LE_SIGNAL :
/* get sequence number and check if msg is in sequence */
2022-12-16 17:49:11 +00:00
seq_nr = * TLVP_VAL ( tp , V5X_CTRL_IEI_SEQUENCE_NR ) & 0x7f ;
2022-12-09 18:20:45 +00:00
if ( pstn - > S_r = = seq_nr ) {
2022-12-26 13:44:39 +00:00
LOGP ( DV5PSTN , LOGL_DEBUG , " Received expected 'receive' sequence number: S(R)=%d == M(R)=%d \n " ,
pstn - > S_r , seq_nr ) ;
2022-12-09 18:20:45 +00:00
/* start Tr, if not pending */
if ( ! osmo_timer_pending ( & pstn - > timer_Tr ) )
start_timer_Tr ( pstn ) ;
/* increment receive sequence number */
pstn - > S_r = ( pstn - > S_r + 1 ) & 127 ;
/* send FE-signal_indication */
rcv_fe ( fi , FE_line_signal_ind , tp ) ;
} else {
2022-12-26 13:44:39 +00:00
LOGP ( DV5PSTN , LOGL_ERROR , " Invalid 'receive' sequence number: S(R)=%d != M(R)=%d \n " ,
pstn - > S_r , seq_nr ) ;
2022-12-09 18:20:45 +00:00
/* send FE-signal_indication */
rcv_fe ( fi , FE_line_signal_ind , tp ) ;
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_SIGNAL_ACK :
2022-12-16 17:49:11 +00:00
seq_nr = * TLVP_VAL ( tp , V5X_CTRL_IEI_SEQUENCE_NR ) & 0x7f ;
2022-12-09 18:20:45 +00:00
unacked = ( pstn - > S_s - pstn - > S_a ) & 127 ;
acked = ( pstn - > S_s - seq_nr ) & 127 ;
if ( acked < = unacked ) {
2022-12-26 13:44:39 +00:00
LOGP ( DV5PSTN , LOGL_DEBUG , " Received expected 'transmit' sequence number: M(R)=%d is inside "
" S(A)=%d...S(S)=%d range \n " , seq_nr , pstn - > S_a , pstn - > S_s ) ;
2022-12-09 18:20:45 +00:00
LOGP ( DV5PSTN , LOGL_DEBUG , " We had %d unacked messages, now we have %d acked messages. \n " , unacked , acked ) ;
/* update acknowledge sequence number */
pstn - > S_a = seq_nr ;
if ( pstn - > S_a = = pstn - > S_s ) {
LOGP ( DV5PSTN , LOGL_DEBUG , " No more outstanding message, so we don't need Tt anymore. \n " ) ;
/* stop Tt */
stop_timer_Tt ( pstn ) ;
} else {
LOGP ( DV5PSTN , LOGL_DEBUG , " There are still outstanding message, we still need Tt. \n " ) ;
/* start Tt */
start_timer_Tt ( pstn ) ;
}
} else {
2022-12-26 13:44:39 +00:00
LOGP ( DV5PSTN , LOGL_ERROR , " Invalid 'transmit' sequence number: M(R)=%d not inside "
" S(A)=%d...S(S)=%d range \n " , seq_nr , pstn - > S_a , pstn - > S_s ) ;
2022-12-09 18:20:45 +00:00
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_STATUS :
2022-12-16 17:49:11 +00:00
cause = * TLVP_VAL ( tp , V5X_CTRL_IEI_CAUSE ) & 0x7f ;
2022-12-09 18:20:45 +00:00
if ( cause = = 0 ) {
/* stop T4 */
stop_timer ( fi ) ;
} else {
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_FE_line_signal_req :
/* if the maximum number of outstanding sequence numbers is not exceeded (127) */
if ( ( ( pstn - > S_s + 1 ) & 127 ) ! = pstn - > S_a ) {
/* start Tt, if not pending: This is wrong in the state tables, but look at 13.5.5.2.2! */
if ( ! osmo_timer_pending ( & pstn - > timer_Tt ) )
start_timer_Tt ( pstn ) ;
/* store SIGNAL message */
if ( pstn - > tx_msg )
msgb_free ( pstn - > tx_msg ) ;
pstn - > tx_msg = msgb_copy ( msg , NULL ) ;
/* send SIGNAL */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_signal ( pstn - > v5up , pstn - > S_s , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
/* increment send sequence number */
pstn - > S_s = ( pstn - > S_s + 1 ) & 127 ;
} else {
/* send SIGNAL */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_signal ( pstn - > v5up , pstn - > S_s , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_FE_protocol_param_req :
/* if the maximum number of outstanding sequence numbers is not exceeded (127) */
if ( ( ( pstn - > S_s + 1 ) & 127 ) ! = pstn - > S_a ) {
/* start Tt */
start_timer_Tt ( pstn ) ;
/* send SIGNAL */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_protocol_param ( pstn - > v5up , pstn - > S_s , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
/* increment send sequence number */
pstn - > S_s = ( pstn - > S_s + 1 ) & 127 ;
} else {
/* send SIGNAL */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_protocol_param ( pstn - > v5up , pstn - > S_s , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_FE_disconnect_req :
/* change state to LE5 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ , 0 , 0 ) ;
/* stop all timers */
stop_timer ( fi ) ;
/* start T3 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T3 , 2 ) ;
/* store DISCONNECT message */
if ( pstn - > tx_msg )
msgb_free ( pstn - > tx_msg ) ;
pstn - > tx_msg = msgb_copy ( msg , NULL ) ;
/* Send DISCONNECT */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect ( pstn - > v5up , msg - > data , msg - > len ) ) ;
2022-12-09 18:20:45 +00:00
msgb_free ( msg ) ;
break ;
case V5x_PSTN_LE_FE_disconnect_compl_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_port_blocked :
/* do several thing here */
do_block ( fi ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_port_unblocked :
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_req :
/* send DISCONNECT COMPLETE */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect_compl ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
/* do several thing here */
do_restart ( fi ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_compl_req :
/* ignore */
break ;
case V5x_PSTN_LE_TIMEOUT_T4 :
/* first or second timeout ? */
if ( pstn - > timeout_count < 3 ) {
/* start T4 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T4 , pstn - > timeout_count + 1 ) ;
/* send STATUS ENQUIRY again */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_status_enquiry ( pstn - > v5up ) ) ;
2022-12-09 18:20:45 +00:00
} else {
/* do several thing here */
do_disconnect_with_error ( fi ) ;
}
break ;
case V5x_PSTN_LE_TIMEOUT_Tr :
/* send SIGNAL ACK */
2022-12-26 13:44:39 +00:00
LOGP ( DV5PSTN , LOGL_DEBUG , " Sending recent 'receive' sequence number: S(R)=%d as acknowledge. \n " ,
pstn - > S_r ) ;
dl_send ( fi , v5x_enc_signal_ack ( pstn - > v5up , pstn - > S_r ) ) ;
2022-12-09 18:20:45 +00:00
break ;
case V5x_PSTN_LE_TIMEOUT_Tt :
/* do several thing here */
LOGP ( DV5PSTN , LOGL_ERROR , " Aborting, because of missing acknowledge of outstanding 'transmit' sequence number: S(A)=%d...S(S)=%d \n " , pstn - > S_a , pstn - > S_s ) ;
do_disconnect_with_error ( fi ) ;
break ;
2022-12-26 13:44:39 +00:00
default :
OSMO_ASSERT ( 0 ) ;
2022-12-09 18:20:45 +00:00
}
}
static void pstn_le5_path_disconnect_req ( struct osmo_fsm_inst * fi , uint32_t event , void * data )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
struct msgb * msg = data ;
const struct tlv_parsed * tp = data ;
switch ( event ) {
case V5x_PSTN_LE_ESTABLISH :
/* ignore */
break ;
case V5x_PSTN_LE_DISCONNECT :
case V5x_PSTN_LE_DISCONNECT_COMPL :
/* stop T3 */
stop_timer ( fi ) ;
/* change state to LE1 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE1_NULL , 0 , 0 ) ;
/* send FE-disconnect_complete_indication */
rcv_fe ( fi , FE_disconnect_compl_ind , tp ) ;
break ;
case V5x_PSTN_LE_ESTABLISH_ACK :
/* ignore */
break ;
case V5x_PSTN_LE_SIGNAL :
/* ignore */
break ;
case V5x_PSTN_LE_SIGNAL_ACK :
/* ignore */
break ;
case V5x_PSTN_LE_STATUS :
/* ignore */
break ;
case V5x_PSTN_LE_FE_line_signal_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_FE_protocol_param_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_FE_disconnect_compl_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_port_blocked :
/* do several thing here */
do_block ( fi ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_port_unblocked :
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_req :
/* send DISCONNECT COMPLETE */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect_compl ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
/* do several thing here */
do_restart ( fi ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_compl_req :
/* ignore */
break ;
case V5x_PSTN_LE_TIMEOUT_T3 :
/* send DISCONNECT again */
if ( pstn - > tx_msg )
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect ( pstn - > v5up , pstn - > tx_msg - > data ,
2022-12-09 18:20:45 +00:00
pstn - > tx_msg - > len ) ) ;
else
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_disconnect ( pstn - > v5up , NULL , 0 ) ) ;
2022-12-09 18:20:45 +00:00
/* start T3 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T3 , pstn - > timeout_count + 1 ) ;
/* third timeout ? */
if ( pstn - > timeout_count > 3 ) {
/* send MDU-error_indication */
rcv_mdu ( fi , MDU_error_ind ) ;
}
break ;
2022-12-26 13:44:39 +00:00
default :
OSMO_ASSERT ( 0 ) ;
2022-12-09 18:20:45 +00:00
}
}
static void pstn_le6_port_blocked ( struct osmo_fsm_inst * fi , uint32_t event , void * data )
{
struct v5x_pstn_proto * pstn = fi - > priv ;
struct msgb * msg = data ;
switch ( event ) {
case V5x_PSTN_LE_FE_establish_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_ESTABLISH :
case V5x_PSTN_LE_DISCONNECT :
case V5x_PSTN_LE_ESTABLISH_ACK :
case V5x_PSTN_LE_SIGNAL :
case V5x_PSTN_LE_SIGNAL_ACK :
/* do several thing here */
do_status_enquiry ( fi ) ;
break ;
case V5x_PSTN_LE_DISCONNECT_COMPL :
/* ignore */
break ;
case V5x_PSTN_LE_FE_establish_ack_req :
msgb_free ( msg ) ;
/* ignore */
break ;
case V5x_PSTN_LE_STATUS :
break ;
case V5x_PSTN_LE_MDU_CTRL_port_blocked :
/* ignore */
break ;
case V5x_PSTN_LE_MDU_CTRL_port_unblocked :
/* change state to LE1 */
osmo_fsm_inst_state_chg ( fi , V5x_LE_PTSN_S_LE1_NULL , 0 , 0 ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_req :
/* send MDU-CTRL (restart ack) */
rcv_mdu ( fi , MDU_CTRL_port_restart_ack ) ;
break ;
case V5x_PSTN_LE_MDU_CTRL_restart_compl_req :
/* ignore */
break ;
case V5x_PSTN_LE_TIMEOUT_T4 :
/* first or second timeout ? */
if ( pstn - > timeout_count < 3 ) {
/* start T4 */
start_timer ( fi , V5x_PSTN_LE_TIMEOUT_T4 , pstn - > timeout_count + 1 ) ;
/* send STATUS ENQUIRY again */
2022-12-26 13:44:39 +00:00
dl_send ( fi , v5x_enc_status_enquiry ( pstn - > v5up ) ) ;
2022-12-09 18:20:45 +00:00
} else {
/* send MDU-error_indication */
rcv_mdu ( fi , MDU_error_ind ) ;
}
break ;
2022-12-26 13:44:39 +00:00
default :
OSMO_ASSERT ( 0 ) ;
2022-12-09 18:20:45 +00:00
}
}
/* Table 3/G.964 Primitives, messages and timers used in the LE(PSTN) FSM */
static const struct osmo_fsm_state v5x_le_pstn_fsm_states [ ] = {
[ V5x_LE_PTSN_S_LE0_OUT_OF_SERVICE ] = {
. name = " Out of service (LE0) " ,
. in_event_mask = S ( V5x_PSTN_LE_FE_establish_req ) |
S ( V5x_PSTN_LE_ESTABLISH ) |
S ( V5x_PSTN_LE_DISCONNECT ) |
S ( V5x_PSTN_LE_DISCONNECT_COMPL ) |
S ( V5x_PSTN_LE_FE_establish_ack_req ) |
S ( V5x_PSTN_LE_ESTABLISH_ACK ) |
S ( V5x_PSTN_LE_SIGNAL ) |
S ( V5x_PSTN_LE_SIGNAL_ACK ) |
S ( V5x_PSTN_LE_STATUS ) |
S ( V5x_PSTN_LE_FE_protocol_param_req ) |
S ( V5x_PSTN_LE_FE_disconnect_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_blocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_unblocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_compl_req ) |
S ( V5x_PSTN_LE_TIMEOUT_T4 ) ,
. out_state_mask = S ( V5x_LE_PTSN_S_LE1_NULL ) |
S ( V5x_LE_PTSN_S_LE6_PORT_BLOCKED ) ,
. action = pstn_le0_out_of_service ,
} ,
[ V5x_LE_PTSN_S_LE1_NULL ] = {
. name = " Null (LE1) " ,
. in_event_mask = S ( V5x_PSTN_LE_FE_establish_req ) |
S ( V5x_PSTN_LE_ESTABLISH ) |
S ( V5x_PSTN_LE_DISCONNECT ) |
S ( V5x_PSTN_LE_ESTABLISH_ACK ) |
S ( V5x_PSTN_LE_SIGNAL ) |
S ( V5x_PSTN_LE_SIGNAL_ACK ) |
S ( V5x_PSTN_LE_STATUS ) |
S ( V5x_PSTN_LE_FE_protocol_param_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_blocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_unblocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_req ) |
S ( V5x_PSTN_LE_TIMEOUT_T4 ) ,
. out_state_mask = S ( V5x_LE_PTSN_S_LE0_OUT_OF_SERVICE ) |
S ( V5x_LE_PTSN_S_LE2_PATH_INITIATED_LE ) |
S ( V5x_LE_PTSN_S_LE3_PATH_INITIATED_AN ) |
S ( V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ ) |
S ( V5x_LE_PTSN_S_LE6_PORT_BLOCKED ) ,
. action = pstn_le1_null ,
} ,
[ V5x_LE_PTSN_S_LE2_PATH_INITIATED_LE ] = {
. name = " Path initiated by LE (LE2) " ,
. in_event_mask = S ( V5x_PSTN_LE_ESTABLISH ) |
S ( V5x_PSTN_LE_DISCONNECT ) |
S ( V5x_PSTN_LE_DISCONNECT_COMPL ) |
S ( V5x_PSTN_LE_FE_establish_ack_req ) |
S ( V5x_PSTN_LE_ESTABLISH_ACK ) |
S ( V5x_PSTN_LE_SIGNAL ) |
S ( V5x_PSTN_LE_SIGNAL_ACK ) |
S ( V5x_PSTN_LE_STATUS ) |
S ( V5x_PSTN_LE_FE_protocol_param_req ) |
S ( V5x_PSTN_LE_FE_disconnect_req ) |
S ( V5x_PSTN_LE_FE_disconnect_compl_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_blocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_unblocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_compl_req ) |
S ( V5x_PSTN_LE_TIMEOUT_T1 ) |
S ( V5x_PSTN_LE_TIMEOUT_T4 ) ,
. out_state_mask = S ( V5x_LE_PTSN_S_LE0_OUT_OF_SERVICE ) |
S ( V5x_LE_PTSN_S_LE1_NULL ) |
S ( V5x_LE_PTSN_S_LE4_PATH_ACTIVE ) |
S ( V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ ) |
S ( V5x_LE_PTSN_S_LE6_PORT_BLOCKED ) ,
. action = pstn_le2_path_initiated_le ,
} ,
[ V5x_LE_PTSN_S_LE3_PATH_INITIATED_AN ] = {
. name = " Path initiated by AN (LE3) " ,
. in_event_mask = S ( V5x_PSTN_LE_FE_establish_req ) |
S ( V5x_PSTN_LE_ESTABLISH ) |
S ( V5x_PSTN_LE_DISCONNECT ) |
S ( V5x_PSTN_LE_DISCONNECT_COMPL ) |
S ( V5x_PSTN_LE_FE_establish_ack_req ) |
S ( V5x_PSTN_LE_ESTABLISH_ACK ) |
S ( V5x_PSTN_LE_SIGNAL ) |
S ( V5x_PSTN_LE_SIGNAL_ACK ) |
S ( V5x_PSTN_LE_STATUS ) |
S ( V5x_PSTN_LE_FE_protocol_param_req ) |
S ( V5x_PSTN_LE_FE_disconnect_req ) |
S ( V5x_PSTN_LE_FE_disconnect_compl_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_blocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_unblocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_compl_req ) |
S ( V5x_PSTN_LE_TIMEOUT_T4 ) ,
. out_state_mask = S ( V5x_LE_PTSN_S_LE0_OUT_OF_SERVICE ) |
S ( V5x_LE_PTSN_S_LE1_NULL ) |
S ( V5x_LE_PTSN_S_LE2_PATH_INITIATED_LE ) |
S ( V5x_LE_PTSN_S_LE4_PATH_ACTIVE ) |
S ( V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ ) |
S ( V5x_LE_PTSN_S_LE6_PORT_BLOCKED ) ,
. action = pstn_le3_path_initiated_an ,
} ,
[ V5x_LE_PTSN_S_LE4_PATH_ACTIVE ] = {
. name = " Path active (LE4) " ,
. in_event_mask = S ( V5x_PSTN_LE_ESTABLISH ) |
S ( V5x_PSTN_LE_DISCONNECT ) |
S ( V5x_PSTN_LE_DISCONNECT_COMPL ) |
S ( V5x_PSTN_LE_ESTABLISH_ACK ) |
S ( V5x_PSTN_LE_SIGNAL ) |
S ( V5x_PSTN_LE_SIGNAL_ACK ) |
S ( V5x_PSTN_LE_STATUS ) |
S ( V5x_PSTN_LE_FE_line_signal_req ) |
S ( V5x_PSTN_LE_FE_protocol_param_req ) |
S ( V5x_PSTN_LE_FE_disconnect_req ) |
S ( V5x_PSTN_LE_FE_disconnect_compl_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_blocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_unblocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_compl_req ) |
S ( V5x_PSTN_LE_TIMEOUT_Tr ) |
S ( V5x_PSTN_LE_TIMEOUT_Tt ) |
S ( V5x_PSTN_LE_TIMEOUT_T4 ) ,
. out_state_mask = S ( V5x_LE_PTSN_S_LE0_OUT_OF_SERVICE ) |
S ( V5x_LE_PTSN_S_LE1_NULL ) |
S ( V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ ) |
S ( V5x_LE_PTSN_S_LE6_PORT_BLOCKED ) ,
. action = pstn_le4_path_active ,
} ,
[ V5x_LE_PTSN_S_LE5_PATH_DICONNECT_REQ ] = {
. name = " Path Disconnect request (LE5) " ,
. in_event_mask = S ( V5x_PSTN_LE_ESTABLISH ) |
S ( V5x_PSTN_LE_DISCONNECT ) |
S ( V5x_PSTN_LE_DISCONNECT_COMPL ) |
S ( V5x_PSTN_LE_ESTABLISH_ACK ) |
S ( V5x_PSTN_LE_SIGNAL ) |
S ( V5x_PSTN_LE_SIGNAL_ACK ) |
S ( V5x_PSTN_LE_STATUS ) |
S ( V5x_PSTN_LE_FE_line_signal_req ) |
S ( V5x_PSTN_LE_FE_protocol_param_req ) |
S ( V5x_PSTN_LE_FE_disconnect_compl_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_blocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_unblocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_compl_req ) |
S ( V5x_PSTN_LE_TIMEOUT_T3 ) ,
. out_state_mask = S ( V5x_LE_PTSN_S_LE1_NULL ) ,
. action = pstn_le5_path_disconnect_req ,
} ,
[ V5x_LE_PTSN_S_LE6_PORT_BLOCKED ] = {
. name = " Port blocked (LE6) " ,
. in_event_mask = S ( V5x_PSTN_LE_FE_establish_req ) |
S ( V5x_PSTN_LE_ESTABLISH ) |
S ( V5x_PSTN_LE_DISCONNECT ) |
S ( V5x_PSTN_LE_DISCONNECT_COMPL ) |
S ( V5x_PSTN_LE_FE_establish_ack_req ) |
S ( V5x_PSTN_LE_ESTABLISH_ACK ) |
S ( V5x_PSTN_LE_SIGNAL ) |
S ( V5x_PSTN_LE_SIGNAL_ACK ) |
S ( V5x_PSTN_LE_STATUS ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_blocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_port_unblocked ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_req ) |
S ( V5x_PSTN_LE_MDU_CTRL_restart_compl_req ) |
S ( V5x_PSTN_LE_TIMEOUT_T4 ) ,
. out_state_mask = S ( V5x_LE_PTSN_S_LE1_NULL ) ,
. action = pstn_le6_port_blocked ,
} ,
} ;
struct osmo_fsm v5x_le_pstn_fsm = {
2022-12-16 17:49:11 +00:00
. name = " V5X_LE_PSTN " ,
2022-12-09 18:20:45 +00:00
. states = v5x_le_pstn_fsm_states ,
. num_states = ARRAY_SIZE ( v5x_le_pstn_fsm_states ) ,
. allstate_event_mask = 0 ,
. allstate_action = NULL ,
. cleanup = NULL ,
. timer_cb = v5x_le_pstn_fsm_timer_cb ,
. log_subsys = DV5PSTN ,
. event_names = v5x_ctrl_le_port_fsm_event_names ,
} ;
2022-12-16 17:49:11 +00:00
struct v5x_pstn_proto * v5x_le_pstn_create ( struct v5x_user_port * v5up , uint16_t nr )
2022-12-09 18:20:45 +00:00
{
struct v5x_pstn_proto * pstn ;
OSMO_ASSERT ( v5up ) ;
pstn = talloc_zero ( v5up , struct v5x_pstn_proto ) ;
if ( ! pstn )
return NULL ;
pstn - > v5up = v5up ;
pstn - > fi = osmo_fsm_inst_alloc ( & v5x_le_pstn_fsm , pstn , pstn , LOGL_DEBUG , NULL ) ;
if ( ! pstn - > fi )
NULL ;
osmo_fsm_inst_update_id_f ( pstn - > fi , " %d " , nr ) ;
pstn - > timer_Tr . data = pstn ;
pstn - > timer_Tr . cb = timeout_Tr_cb ;
pstn - > timer_Tt . data = pstn ;
pstn - > timer_Tt . cb = timeout_Tt_cb ;
return pstn ;
}
2022-12-16 17:49:11 +00:00
void v5x_le_pstn_destroy ( struct v5x_pstn_proto * pstn )
2022-12-09 18:20:45 +00:00
{
/* free pending message */
if ( pstn - > tx_msg )
msgb_free ( pstn - > tx_msg ) ;
if ( pstn - > fi ) {
stop_timer_Tr ( pstn ) ;
stop_timer_Tt ( pstn ) ;
osmo_fsm_inst_free ( pstn - > fi ) ;
}
2022-12-16 17:49:11 +00:00
talloc_free ( pstn ) ;
2022-12-09 18:20:45 +00:00
}
2022-12-26 13:44:39 +00:00
const char * v5x_le_pstn_state_name ( struct v5x_pstn_proto * pstn )
{
return v5x_le_pstn_fsm_states [ pstn - > fi - > state ] . name ;
}
2022-12-16 17:49:11 +00:00
void v5x_le_pstn_init ( void )
2022-12-09 18:20:45 +00:00
{
int rc ;
rc = osmo_fsm_register ( & v5x_le_pstn_fsm ) ;
OSMO_ASSERT ( ! rc ) ;
LOGP ( DV5PSTN , LOGL_NOTICE , " Using V5x PSTN protocol \n " ) ;
}
/***********************************************************************
* V5 Message receiving / decoding
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* receive message from lower (DL) layer */
2022-12-26 13:44:39 +00:00
int v5x_le_pstn_dl_rcv ( struct v5x_user_port * v5up , uint8_t msg_type , const struct tlv_parsed * tp )
2022-12-09 18:20:45 +00:00
{
enum v5x_le_pstn_fsm_event event ;
switch ( msg_type ) {
2022-12-16 17:49:11 +00:00
case V5X_CTRL_MSGT_ESTABLISH :
2022-12-09 18:20:45 +00:00
event = V5x_PSTN_LE_ESTABLISH ;
break ;
2022-12-16 17:49:11 +00:00
case V5X_CTRL_MSGT_ESTABLISH_ACK :
2022-12-09 18:20:45 +00:00
event = V5x_PSTN_LE_ESTABLISH_ACK ;
break ;
2022-12-16 17:49:11 +00:00
case V5X_CTRL_MSGT_SIGNAL :
2022-12-09 18:20:45 +00:00
event = V5x_PSTN_LE_SIGNAL ;
break ;
2022-12-16 17:49:11 +00:00
case V5X_CTRL_MSGT_SIGNAL_ACK :
2022-12-09 18:20:45 +00:00
event = V5x_PSTN_LE_SIGNAL_ACK ;
break ;
2022-12-16 17:49:11 +00:00
case V5X_CTRL_MSGT_DISCONNECT :
2022-12-09 18:20:45 +00:00
event = V5x_PSTN_LE_DISCONNECT ;
break ;
2022-12-16 17:49:11 +00:00
case V5X_CTRL_MSGT_DISCONNECT_COMPLETE :
2022-12-09 18:20:45 +00:00
event = V5x_PSTN_LE_DISCONNECT_COMPL ;
break ;
2022-12-16 17:49:11 +00:00
case V5X_CTRL_MSGT_STATUS :
2022-12-09 18:20:45 +00:00
event = V5x_PSTN_LE_STATUS ;
break ;
default :
LOGP ( DV5PSTN , LOGL_NOTICE , " Invalid PSTN protocol message %d receied from AN. \n " , msg_type ) ;
return - EINVAL ;
}
osmo_fsm_inst_dispatch ( v5up - > pstn . proto - > fi , event , ( void * ) tp ) ;
return 0 ;
}