2022-12-04 16:56:51 +00:00
/* Management information forwarding between AN <-> 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 .
*
*/
2022-12-26 13:45:13 +00:00
# warning The blocking_enable state and timer is a hack to delay port blocking messages during startup. (AN may not like to get blocking messages too early.) This must be replaced by a more elegant algorithm.
// FIXME: explain each process, especially the port blocking/unblocking states and process
2022-12-04 16:56:51 +00:00
# include <stdint.h>
2022-12-26 13:45:13 +00:00
# include <errno.h>
2022-12-04 16:56:51 +00:00
# include "v5x_internal.h"
2022-12-16 17:57:05 +00:00
# include "v5x_protocol.h"
2022-12-26 13:45:13 +00:00
# include "v5x_le_ctrl_fsm.h"
2022-12-16 17:57:05 +00:00
# include "v5x_le_port_fsm.h"
2022-12-04 16:56:51 +00:00
# include "v5x_le_pstn_fsm.h"
2022-12-26 13:45:13 +00:00
# include "v52_le_lcp_fsm.h"
# include "v52_le_bcc_fsm.h"
# include "v52_le_pp_fsm.h"
# include "v5x_le_management.h"
2023-02-12 14:19:08 +00:00
# include "layer1.h"
2022-12-04 16:56:51 +00:00
# include "logging.h"
2022-12-16 17:57:05 +00:00
void v5x_le_mgmt_init ( void )
2022-12-04 16:56:51 +00:00
{
LOGP ( DV5MGMT , LOGL_NOTICE , " Using V5x management \n " ) ;
}
2022-12-26 13:45:13 +00:00
/*
* provisioning and port handling
*/
struct osmo_timer_list provisioning_timer ;
struct osmo_timer_list blocking_enable_timer ;
static void provisioning_cb ( void * data )
{
struct v5x_interface * v5if = data ;
/* ask for variant and interface ID */
LOGP ( DV5MGMT , LOGL_INFO , " Requesting variant and interface ID. \n " ) ;
v5x_le_ctrl_common_snd ( v5if , V5X_CTRL_ID_REQUEST_VARIANT_AND_INTERFACE_ID , NULL , NULL , NULL ) ;
}
static void blocking_enable_cb ( void * data )
{
struct v5x_interface * v5if = data ;
struct v5x_link * v5l ;
struct v5x_user_port * v5up ;
LOGP ( DV5MGMT , LOGL_DEBUG , " Enable sending of port blocking/unblocking and sending all block states to AN. \n " ) ;
/* unblock all links */
if ( v5if - > dialect = = V5X_DIALECT_V52 ) {
llist_for_each_entry ( v5l , & v5if - > links , list ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send unblocking request for link %d. \n " , v5l - > id ) ;
v52_le_lcp_mdu_snd ( v5l , MDU_LUBR ) ;
}
}
/* unblock all ports */
llist_for_each_entry ( v5up , & v5if - > user_ports , list ) {
if ( v5up - > blocking_enabled )
continue ;
v5up - > blocking_enabled = true ;
if ( v5up - > le_unblocked ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send unblock request to %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
v5x_port_mph_snd ( v5up , MPH_UBR ) ;
if ( v5up - > pstn . proto & & v5up - > an_unblocked ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send port unblocked control to PSTN port %d. \n " , v5up - > nr ) ;
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_unblocked ) ;
}
} else {
LOGP ( DV5MGMT , LOGL_INFO , " Send block indication to %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
v5x_port_mph_snd ( v5up , MPH_BI ) ;
if ( v5up - > pstn . proto ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send port blocked control to PSTN port %d. \n " , v5up - > nr ) ;
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_blocked ) ;
}
}
}
}
static void restart_all_pstn_ports ( struct v5x_interface * v5if )
{
struct v5x_user_port * v5up ;
llist_for_each_entry ( v5up , & v5if - > user_ports , list ) {
if ( v5up - > pstn . proto ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send restart request to PSTN port %d. \n " , v5up - > nr ) ;
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_restart_req ) ;
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_restart_compl ) ;
}
}
}
static void _block_unblock_socket ( struct v5x_user_port * v5up , bool block )
{
uint8_t ctrl ;
if ( block & & v5up - > an_unblocked ) {
v5up - > an_unblocked = false ;
ctrl = PH_CTRL_BLOCK ;
ph_socket_tx_msg ( & v5up - > ph_socket , v5up - > type = = V5X_USER_TYPE_ISDN ? 3 : 0 , PH_PRIM_CTRL_IND , & ctrl ,
1 ) ;
return ;
}
if ( ! block & & ! v5up - > an_unblocked ) {
v5up - > an_unblocked = true ;
ctrl = PH_CTRL_UNBLOCK ;
ph_socket_tx_msg ( & v5up - > ph_socket , v5up - > type = = V5X_USER_TYPE_ISDN ? 3 : 0 , PH_PRIM_CTRL_IND , & ctrl ,
1 ) ;
return ;
}
}
/* messages from common control layer */
void v5x_le_common_ctrl_rcv ( struct v5x_interface * v5if , uint8_t cfi , uint8_t variant , uint8_t rej_cause ,
uint32_t interface_id )
{
struct v5x_user_port * v5up ;
LOGP ( DV5MGMT , LOGL_DEBUG , " Received common control message from control protocol. "
" (cfi = %d, variant = %d, rej_cause = %d, interface_id = %d) \n " , cfi , variant , rej_cause , interface_id ) ;
switch ( cfi ) {
case V5X_CTRL_ID_REQUEST_VARIANT_AND_INTERFACE_ID :
LOGP ( DV5MGMT , LOGL_INFO , " AN requests variant and interface ID, replying. \n " ) ;
v5x_le_ctrl_common_snd ( v5if , V5X_CTRL_ID_VARIANT_AND_INTERFACE_ID , NULL , & v5if - > variant_local ,
& v5if - > id_local ) ;
break ;
case V5X_CTRL_ID_RESTART_REQUEST :
LOGP ( DV5MGMT , LOGL_INFO , " AN requests restart, sending restart to every PSTN port and replying. \n " ) ;
/* all PSTN ports are restarted */
restart_all_pstn_ports ( v5if ) ;
v5x_le_ctrl_common_snd ( v5if , V5X_CTRL_ID_RESTART_COMPLETE , NULL , NULL , NULL ) ;
break ;
case V5X_CTRL_ID_VARIANT_AND_INTERFACE_ID :
LOGP ( DV5MGMT , LOGL_INFO , " AN replies variant and interface ID. (variant = %d, interface_id = %d) \n " ,
variant , interface_id ) ;
v5if - > variant_remote = variant ;
v5if - > variant_remote_valid = true ;
if ( v5if - > variant_remote ! = v5if - > variant_local ) {
LOGP ( DV5MGMT , LOGL_ERROR , " Variant does not match: AN(%d) != LE(%d) \n " , v5if - > variant_remote ,
v5if - > variant_local ) ;
}
v5if - > id_remote = interface_id ;
v5if - > id_remote_valid = true ;
if ( v5if - > id_remote ! = v5if - > id_local ) {
LOGP ( DV5MGMT , LOGL_ERROR , " Interface ID does not match: AN(%d) != LE(%d) \n " , v5if - > id_remote ,
v5if - > id_local ) ;
}
if ( v5if - > variant_remote ! = v5if - > variant_local | | v5if - > id_remote ! = v5if - > id_local ) {
LOGP ( DV5MGMT , LOGL_ERROR , " **************************************************************** \n " ) ;
LOGP ( DV5MGMT , LOGL_ERROR , " You must set correct Variant and Interface ID on both AN and LE! \n " ) ;
LOGP ( DV5MGMT , LOGL_ERROR , " **************************************************************** \n " ) ;
break ;
}
memset ( & blocking_enable_timer , 0 , sizeof ( blocking_enable_timer ) ) ;
blocking_enable_timer . data = v5if ;
blocking_enable_timer . cb = blocking_enable_cb ;
osmo_timer_schedule ( & blocking_enable_timer , 4 , 0 ) ; // FIXME: make configurable
break ;
case V5X_CTRL_ID_RESTART_COMPLETE :
LOGP ( DV5MGMT , LOGL_INFO , " AN indicated complete restart. \n " ) ;
break ;
case V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_ISDN_REQUEST :
case V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_REQUEST :
case V5X_CTRL_ID_UNBLK_ALL_REL_ISDN_REQUEST :
LOGP ( DV5MGMT , LOGL_INFO , " Multiple port unblocking received. \n " ) ;
LOGP ( DV5MGMT , LOGL_INFO , " Accepting multiple port unblocking, sending reply. \n " ) ;
v5x_le_ctrl_common_snd ( v5if , cfi + 1 , NULL , NULL , NULL ) ;
llist_for_each_entry ( v5up , & v5if - > user_ports , list ) {
if ( cfi = = V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_REQUEST & & ! v5up - > pstn . proto )
continue ;
if ( cfi = = V5X_CTRL_ID_UNBLK_ALL_REL_ISDN_REQUEST & & v5up - > pstn . proto )
continue ;
v5up - > blocking_enabled = true ;
if ( v5up - > le_unblocked ) {
LOGP ( DV5MGMT , LOGL_INFO , " -> Set %s port %d into unblocked state. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
_block_unblock_socket ( v5up , false ) ;
if ( v5up - > pstn . proto ) {
v5x_le_port_pstn_unblock ( v5up - > port_fi ) ;
LOGP ( DV5MGMT , LOGL_INFO , " -> Send port unblocked control to PSTN port %d. \n " ,
v5up - > nr ) ;
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_unblocked ) ;
} else
v5x_le_port_isdn_unblock ( v5up - > port_fi ) ;
}
}
LOGP ( DV5MGMT , LOGL_INFO , " Completed multiple port unblocking, sending info. \n " ) ;
v5x_le_ctrl_common_snd ( v5if , cfi + 3 , NULL , NULL , NULL ) ;
break ;
case V5X_CTRL_ID_BLK_ALL_PSTN_REQUEST :
case V5X_CTRL_ID_BLK_ALL_ISDN_REQUEST :
LOGP ( DV5MGMT , LOGL_INFO , " Multiple port blocking request from remote. \n " ) ;
LOGP ( DV5MGMT , LOGL_INFO , " Accepting multiple port blocking, sending reply. \n " ) ;
v5x_le_ctrl_common_snd ( v5if , cfi + 1 , NULL , NULL , NULL ) ;
llist_for_each_entry ( v5up , & v5if - > user_ports , list ) {
if ( cfi = = V5X_CTRL_ID_BLK_ALL_PSTN_REQUEST & & ! v5up - > pstn . proto )
continue ;
if ( cfi = = V5X_CTRL_ID_BLK_ALL_ISDN_REQUEST & & v5up - > pstn . proto )
continue ;
v5up - > blocking_enabled = true ;
LOGP ( DV5MGMT , LOGL_INFO , " -> Set %s port %d into blocked state. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
_block_unblock_socket ( v5up , true ) ;
if ( v5up - > pstn . proto ) {
v5x_le_port_pstn_block ( v5up - > port_fi ) ;
LOGP ( DV5MGMT , LOGL_INFO , " -> Send port blocked control to PSTN port %d. \n " , v5up - > nr ) ;
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_blocked ) ;
} else
v5x_le_port_isdn_block ( v5up - > port_fi ) ;
}
LOGP ( DV5MGMT , LOGL_INFO , " Completed multiple port blocking, sending info. \n " ) ;
v5x_le_ctrl_common_snd ( v5if , cfi + 3 , NULL , NULL , NULL ) ;
break ;
case V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_ISDN_COMPLETED :
case V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_COMPLETED :
case V5X_CTRL_ID_UNBLK_ALL_REL_ISDN_COMPLETED :
LOGP ( DV5MGMT , LOGL_INFO , " Completed multiple port blocking by remote. Updating blocked ports. \n " ) ;
llist_for_each_entry ( v5up , & v5if - > user_ports , list ) {
if ( cfi = = V5X_CTRL_ID_UNBLK_ALL_REL_PSTN_COMPLETED & & ! v5up - > pstn . proto )
continue ;
if ( cfi = = V5X_CTRL_ID_UNBLK_ALL_REL_ISDN_COMPLETED & & v5up - > pstn . proto )
continue ;
if ( ! v5up - > le_unblocked ) {
LOGP ( DV5MGMT , LOGL_INFO , " -> Send block indication to %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
v5x_port_mph_snd ( v5up , MPH_BI ) ;
}
}
case V5X_CTRL_ID_BLK_ALL_PSTN_COMPLETED :
case V5X_CTRL_ID_BLK_ALL_ISDN_COMPLETED :
break ;
default :
LOGP ( DV5MGMT , LOGL_NOTICE , " Ignoring common control message with cfi = %d \n " , cfi ) ;
}
}
/* perform provisioning */
void v5x_le_provisioning_start ( struct v5x_interface * v5if )
{
memset ( & provisioning_timer , 0 , sizeof ( provisioning_timer ) ) ;
provisioning_timer . data = v5if ;
provisioning_timer . cb = provisioning_cb ;
osmo_timer_schedule ( & provisioning_timer , 1 , 0 ) ; // FIXME: make configurable
}
void v5x_le_pstn_restart ( struct v5x_interface * v5if )
{
/* request a restart */
LOGP ( DV5MGMT , LOGL_NOTICE , " Perform PSTN restart. \n " ) ;
v5x_le_ctrl_common_snd ( v5if , V5X_CTRL_ID_RESTART_REQUEST , NULL , NULL , NULL ) ;
/* all PSTN ports are restarted */
restart_all_pstn_ports ( v5if ) ;
v5x_le_ctrl_common_snd ( v5if , V5X_CTRL_ID_RESTART_COMPLETE , NULL , NULL , NULL ) ;
}
2022-12-04 16:56:51 +00:00
/* received management primitives from LE (NAT protocol via PH-socket) */
2022-12-26 13:45:13 +00:00
void v5x_le_nat_ph_rcv ( struct v5x_user_port * v5up , uint8_t prim , uint8_t * data , int length )
2022-12-04 16:56:51 +00:00
{
ph_socket_t * s = & v5up - > ph_socket ;
switch ( prim ) {
case PH_PRIM_CTRL_REQ :
if ( length & & * data = = PH_CTRL_UNBLOCK ) {
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received unblocking from LE of %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
2022-12-04 16:56:51 +00:00
v5up - > le_unblocked = true ;
2022-12-26 13:45:13 +00:00
if ( v5up - > blocking_enabled ) {
v5x_port_mph_snd ( v5up , MPH_UBR ) ;
if ( v5up - > pstn . proto & & v5up - > an_unblocked ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send port unblocked control to PSTN port %d. \n " ,
v5up - > nr ) ;
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_unblocked ) ;
}
}
2022-12-04 16:56:51 +00:00
if ( ! v5up - > an_unblocked ) {
LOGP ( DV5MGMT , LOGL_INFO , " Reply with blocking, because AN is blocked. \n " ) ;
uint8_t ctrl = PH_CTRL_BLOCK ;
2022-12-26 13:45:13 +00:00
ph_socket_tx_msg ( & v5up - > ph_socket , v5up - > type = = V5X_USER_TYPE_ISDN ? 3 : 0 ,
PH_PRIM_CTRL_IND , & ctrl , 1 ) ;
2022-12-04 16:56:51 +00:00
}
}
if ( length & & * data = = PH_CTRL_BLOCK ) {
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received blocking from LE of %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
2022-12-04 16:56:51 +00:00
v5up - > le_unblocked = false ;
2022-12-26 13:45:13 +00:00
if ( v5up - > blocking_enabled ) {
v5x_port_mph_snd ( v5up , MPH_BI ) ;
if ( v5up - > pstn . proto ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send port blocked control to PSTN port %d. \n " ,
v5up - > nr ) ;
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_blocked ) ;
}
}
2022-12-04 16:56:51 +00:00
}
break ;
case PH_PRIM_ACT_REQ :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received activation from LE of %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
2022-12-04 16:56:51 +00:00
if ( ! v5up - > an_unblocked ) {
ph_socket_tx_msg ( s , 3 , PH_PRIM_DACT_IND , NULL , 0 ) ;
break ;
}
2022-12-26 13:45:13 +00:00
v5x_port_mph_snd ( v5up , MPH_AR ) ;
2022-12-04 16:56:51 +00:00
break ;
case PH_PRIM_DACT_REQ :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received deactivation from LE of %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
v5x_port_mph_snd ( v5up , MPH_DR ) ;
2022-12-04 16:56:51 +00:00
break ;
default :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received unknown prim %d from LE for %s port %d. \n " , prim ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
2022-12-04 16:56:51 +00:00
}
}
/* received management primitives from AN (via port control protocol) */
2022-12-26 13:45:13 +00:00
void v5x_le_port_mph_rcv ( struct v5x_user_port * v5up , enum v5x_mph_prim prim , uint8_t perf_grading )
2022-12-04 16:56:51 +00:00
{
switch ( prim ) {
case MPH_UBR :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received unblocking request from AN of %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
v5up - > blocking_enabled = true ;
2022-12-04 16:56:51 +00:00
if ( v5up - > le_unblocked ) {
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Reply with unblocking request, because port available at LE. \n " ) ;
v5x_port_mph_snd ( v5up , MPH_UBR ) ;
2022-12-04 16:56:51 +00:00
_block_unblock_socket ( v5up , false ) ;
2022-12-26 13:45:13 +00:00
if ( v5up - > pstn . proto ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send port unblocked control to PSTN port %d. \n " , v5up - > nr ) ;
2022-12-16 17:57:05 +00:00
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_unblocked ) ;
2022-12-26 13:45:13 +00:00
}
} else {
LOGP ( DV5MGMT , LOGL_INFO , " Reply with blocking indication, because port unavailable at LE. \n " ) ;
v5up - > an_unblocked = false ;
v5x_port_mph_snd ( v5up , MPH_BI ) ;
}
2022-12-04 16:56:51 +00:00
break ;
case MPH_UBI :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received unblocking indication from AN of %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
v5up - > blocking_enabled = true ;
2022-12-04 16:56:51 +00:00
_block_unblock_socket ( v5up , false ) ;
2022-12-26 13:45:13 +00:00
if ( v5up - > pstn . proto ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send port unblocked control to PSTN port %d. \n " , v5up - > nr ) ;
2022-12-16 17:57:05 +00:00
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_unblocked ) ;
2022-12-26 13:45:13 +00:00
}
2022-12-04 16:56:51 +00:00
break ;
case MPH_BR :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received blocking request from AN of %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
v5up - > blocking_enabled = true ;
LOGP ( DV5MGMT , LOGL_INFO , " Reply with blocking indication. \n " ) ;
v5x_port_mph_snd ( v5up , MPH_BI ) ;
2022-12-04 16:56:51 +00:00
_block_unblock_socket ( v5up , true ) ;
2022-12-26 13:45:13 +00:00
if ( v5up - > pstn . proto ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send port blocked control to PSTN port %d. \n " , v5up - > nr ) ;
2022-12-16 17:57:05 +00:00
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_blocked ) ;
2022-12-26 13:45:13 +00:00
}
2022-12-04 16:56:51 +00:00
break ;
case MPH_BI :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received blocking indication from AN of %s port %d. \n " ,
( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
v5up - > blocking_enabled = true ;
2022-12-04 16:56:51 +00:00
_block_unblock_socket ( v5up , true ) ;
2022-12-26 13:45:13 +00:00
if ( v5up - > pstn . proto ) {
LOGP ( DV5MGMT , LOGL_INFO , " Send port blocked control to PSTN port %d. \n " , v5up - > nr ) ;
2022-12-16 17:57:05 +00:00
v5x_le_pstn_mdu_snd ( v5up , MDU_CTRL_port_blocked ) ;
2022-12-26 13:45:13 +00:00
}
2022-12-04 16:56:51 +00:00
break ;
case MPH_AI :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received activation indication from AN of ISDN port %d. \n " , v5up - > nr ) ;
2022-12-04 16:56:51 +00:00
ph_socket_tx_msg ( & v5up - > ph_socket , 3 , PH_PRIM_ACT_IND , NULL , 0 ) ;
break ;
2022-12-26 13:45:13 +00:00
case MPH_AWI :
break ;
case MPH_DSAI :
break ;
2022-12-04 16:56:51 +00:00
case MPH_DI :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received deactivation indication from AN of ISDN port %d. \n " , v5up - > nr ) ;
2022-12-04 16:56:51 +00:00
ph_socket_tx_msg ( & v5up - > ph_socket , 3 , PH_PRIM_DACT_IND , NULL , 0 ) ;
break ;
2022-12-26 13:45:13 +00:00
case MPH_GI :
LOGP ( DV5MGMT , LOGL_INFO , " Received performance grading from AN for ISDN port %d: %s \n " , v5up - > nr ,
( perf_grading ) ? " Degraded " : " Normal grade " ) ;
break ;
2022-12-04 16:56:51 +00:00
default :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_INFO , " Received unknown prim %d from AN for %s port %d. \n " , prim , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
2022-12-04 16:56:51 +00:00
}
}
2022-12-26 13:45:13 +00:00
/* receive MDU primitives from PSTN protocol */
void v5x_le_pstn_mdu_rcv ( struct v5x_user_port * v5up , enum v5x_mgmt_prim prim )
{
switch ( prim ) {
case MDU_error_ind :
LOGP ( DV5MGMT , LOGL_NOTICE , " Received MDU-error_indication from PSTN protocol of port %d. \n " , v5up - > nr ) ;
break ;
case MDU_CTRL_port_restart_ack :
LOGP ( DV5MGMT , LOGL_INFO , " Received restart acknowledge from PSTN protocol of port %d. \n " , v5up - > nr ) ;
break ;
default :
LOGP ( DV5MGMT , LOGL_INFO , " Received unknown prim %d from PSTN protocol for port %d. \n " , prim , v5up - > nr ) ;
}
}
/* flush all channels from non-operational link */
static void flush_link ( struct v5x_link * v5l )
{
struct v5x_user_port * v5up ;
int t ;
for ( t = 1 ; t < = 31 ; t + + ) {
if ( ! v5l - > ts [ t ] . b_channel )
continue ;
if ( ( v5up = v5l - > ts [ t ] . v5up ) ) {
if ( v5up - > ts [ 0 ] = = & v5l - > ts [ t ] ) {
v5up - > ts [ 0 ] = NULL ;
2023-02-12 14:19:08 +00:00
ph_deactivate_req ( & v5l - > ts [ t ] ) ;
2022-12-26 13:45:13 +00:00
}
if ( v5up - > ts [ 1 ] = = & v5l - > ts [ t ] ) {
v5up - > ts [ 1 ] = NULL ;
2023-02-12 14:19:08 +00:00
ph_deactivate_req ( & v5l - > ts [ t ] ) ;
2022-12-26 13:45:13 +00:00
}
v5l - > ts [ t ] . v5up = NULL ;
}
}
}
/*
* LCP handling
*/
/* receive MDU primitives from LCP protocol */
void v52_le_lcp_mdu_rcv ( struct v5x_link * v5l , enum v5x_mgmt_prim prim )
{
switch ( prim ) {
case MDU_AI :
LOGP ( DV5MGMT , LOGL_INFO , " Link %d is active. \n " , v5l - > id ) ;
break ;
case MDU_DI :
LOGP ( DV5MGMT , LOGL_INFO , " Link %d is inactive. \n " , v5l - > id ) ;
break ;
case MDU_LAI :
LOGP ( DV5MGMT , LOGL_INFO , " Link %d becomes active in blocked state, try unblocking. \n " , v5l - > id ) ;
v52_le_lcp_mdu_snd ( v5l , MDU_LUBR ) ;
break ;
case MDU_IDReq :
LOGP ( DV5MGMT , LOGL_INFO , " Remote side perform link ID check of link %d, replying. \n " , v5l - > id ) ;
v52_le_lcp_mdu_snd ( v5l , MDU_IDAck ) ;
break ;
case MDU_IDAck :
break ;
case MDU_IDRel :
LOGP ( DV5MGMT , LOGL_INFO , " Remote side ID check done. \n " ) ;
break ;
case MDU_IDRej :
break ;
case MDU_EIg :
break ;
case MDU_LUBR :
LOGP ( DV5MGMT , LOGL_INFO , " Remote side unblocks link ID %d, replying. \n " , v5l - > id ) ;
v52_le_lcp_mdu_snd ( v5l , MDU_LUBR ) ;
break ;
case MDU_LUBI :
LOGP ( DV5MGMT , LOGL_INFO , " Remote side link ID %d is now unblocked. \n " , v5l - > id ) ;
break ;
case MDU_LBI :
LOGP ( DV5MGMT , LOGL_INFO , " LCP indicated blocked link ID %d. \n " , v5l - > id ) ;
flush_link ( v5l ) ;
break ;
case MDU_LBR :
case MDU_LBRN :
LOGP ( DV5MGMT , LOGL_INFO , " Remote request blocking of link link ID %d, replying. \n " , v5l - > id ) ;
flush_link ( v5l ) ;
v52_le_lcp_mdu_snd ( v5l , MDU_LBI ) ;
break ;
default :
LOGP ( DV5MGMT , LOGL_INFO , " Received unknown prim %d from LCP protocol for link ID %d. \n " , prim , v5l - > id ) ;
}
}
/*
* forwarding messages between PSTN and gateway application
*/
2022-12-04 16:56:51 +00:00
/* receive FE-message from NAT (PH-socket) and forward it to the PSTN protocol */
2022-12-26 13:45:13 +00:00
void v5x_le_nat_fe_rcv ( struct v5x_user_port * v5up , struct msgb * msg )
2022-12-04 16:56:51 +00:00
{
enum v5x_fe_prim prim ;
prim = * msg - > data ;
msgb_pull ( msg , 1 ) ;
2022-12-26 13:45:13 +00:00
if ( ! v5x_le_port_isdn_is_operational ( v5up - > port_fi ) ) {
LOGP ( DV5MGMT , LOGL_NOTICE , " Dropping (NAT->LE) message of non-operational PSTN port for L3Addr %d. \n " ,
v5up - > nr ) ;
msgb_free ( msg ) ;
return ;
}
LOGP ( DV5MGMT , LOGL_INFO , " FE message: NAT -> PSTN_LE of PSTN port %d. \n " , v5up - > nr ) ;
2022-12-16 17:57:05 +00:00
v5x_le_pstn_fe_snd ( v5up , prim , msg ) ;
2022-12-04 16:56:51 +00:00
}
/* receive FE-message from PSTN protocol and forward it to NAT (PH-socket) */
2022-12-26 13:45:13 +00:00
void v5x_le_pstn_fe_rcv ( struct v5x_user_port * v5up , enum v5x_fe_prim prim , struct msgb * msg )
2022-12-04 16:56:51 +00:00
{
* msgb_push ( msg , 1 ) = prim ;
2022-12-26 13:45:13 +00:00
if ( ! v5x_le_port_isdn_is_operational ( v5up - > port_fi ) ) {
LOGP ( DV5MGMT , LOGL_NOTICE , " Dropping (AN->NAT) message of non-operational PSTN port for L3Addr %d. \n " ,
v5up - > nr ) ;
msgb_free ( msg ) ;
return ;
}
LOGP ( DV5MGMT , LOGL_INFO , " FE message: PSTN_LE -> NAT of PSTN port %d. \n " , v5up - > nr ) ;
2022-12-04 16:56:51 +00:00
ph_socket_tx_msg ( & v5up - > ph_socket , 0 , PH_PRIM_DATA_IND , msg - > data , msg - > len ) ;
msgb_free ( msg ) ;
}
2022-12-26 13:45:13 +00:00
/*
2023-01-29 15:25:31 +00:00
* BCC channel handling , also activation / deactivation for V5 .1
2022-12-26 13:45:13 +00:00
*/
/* assign channel */
void v5x_le_channel_assign ( struct v5x_user_port * v5up , int channel )
{
struct v5x_interface * v5if = v5up - > interface ;
struct v5x_link * v5l = NULL ;
int found , t ;
OSMO_ASSERT ( channel > = 1 & & channel < = 2 ) ;
2023-01-29 15:25:31 +00:00
/* reset echo canceler state */
v5x_echo_reset ( & v5up - > ep [ channel - 1 ] , v5up - > echo_configured ) ;
2022-12-26 13:45:13 +00:00
/* the channels are pre-assigned with V5.1, so only activation state is set */
if ( v5if - > dialect = = V5X_DIALECT_V51 ) {
if ( ! v5up - > ts [ channel - 1 ] ) {
LOGP ( DV5MGMT , LOGL_ERROR , " Cannot activate channel, because no TS is assigned for %s port "
" %d. \n " , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5l - > id ) ;
return ;
}
2023-02-12 14:19:08 +00:00
if ( v5up - > ts [ channel - 1 ] - > b_activated )
2022-12-26 13:45:13 +00:00
return ;
LOGP ( DV5MGMT , LOGL_DEBUG , " Activating channel %d for %s port %d at TS %d of link %d. \n " ,
channel , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ,
v5up - > ts [ channel - 1 ] - > nr , v5up - > ts [ channel - 1 ] - > link - > id ) ;
2023-02-12 14:19:08 +00:00
ph_activate_req ( v5up - > ts [ channel - 1 ] ) ;
2022-12-26 13:45:13 +00:00
return ;
}
/* channel already assigned, just activate it, if not already */
if ( v5up - > ts [ channel - 1 ] ) {
2023-02-12 14:19:08 +00:00
ph_activate_req ( v5up - > ts [ channel - 1 ] ) ;
2022-12-26 13:45:13 +00:00
return ;
}
/* hunt for a channel */
found = 0 ;
llist_for_each_entry ( v5l , & v5if - > links , list ) {
if ( ! v52_le_lcp_is_operational ( v5l - > fi ) ) {
LOGP ( DV5MGMT , LOGL_NOTICE , " While searching for a bearer channel: Skipping link with ID %d, "
" because it is not operational. \n " , v5l - > id ) ;
continue ;
}
for ( t = 1 ; t < = 31 ; t + + ) {
if ( ! v5l - > ts [ t ] . b_channel )
continue ;
if ( ! v5l - > ts [ t ] . v5up ) {
found = 1 ;
break ;
}
}
if ( found )
break ;
}
if ( ! found ) {
LOGP ( DV5MGMT , LOGL_NOTICE , " No free channel found. \n " ) ;
return ;
}
/* assign channel */
v5l - > ts [ t ] . v5up = v5up ;
v5up - > ts [ channel - 1 ] = & v5l - > ts [ t ] ;
/* request BCC to allocate channel on AN */
v52_le_bcc_mdu_snd ( v5if , v5up - > nr , ( v5up - > type = = V5X_USER_TYPE_ISDN ) , v5up - > ts [ channel - 1 ] - > link - > id ,
v5up - > ts [ channel - 1 ] - > nr , 1 , channel , NULL , ( v5if - > use_capability ) ? & v5if - > capability : NULL ,
MDU_BCC_allocation_req ) ;
}
/* unassign channel */
void v5x_le_channel_unassign ( struct v5x_user_port * v5up , int channel )
{
struct v5x_interface * v5if = v5up - > interface ;
/* the channels are pre-assigned with V5.1, so only activation state is set */
if ( v5if - > dialect = = V5X_DIALECT_V51 ) {
if ( ! v5up - > ts [ channel - 1 ] ) {
LOGP ( DV5MGMT , LOGL_ERROR , " Cannot deactivate channel, because no TS is assigned for %s port "
" %d. \n " , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ) ;
return ;
}
2023-02-12 14:19:08 +00:00
if ( ! v5up - > ts [ channel - 1 ] - > b_activated )
return ;
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_DEBUG , " Deactivating channel %d for %s port %d at TS %d of link %d. \n " ,
channel , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr ,
v5up - > ts [ channel - 1 ] - > nr , v5up - > ts [ channel - 1 ] - > link - > id ) ;
2023-02-12 14:19:08 +00:00
ph_deactivate_req ( v5up - > ts [ channel - 1 ] ) ;
2022-12-26 13:45:13 +00:00
return ;
}
/* if not assigned */
if ( ! v5up - > ts [ channel - 1 ] )
return ;
2023-02-12 14:19:08 +00:00
/* deactivate */
ph_deactivate_req ( v5up - > ts [ channel - 1 ] ) ;
2022-12-26 13:45:13 +00:00
/* unassign or abort ongoing BCC allocation */
v52_le_bcc_mdu_snd ( v5if , v5up - > nr , v5up - > type = = V5X_USER_TYPE_ISDN , v5up - > ts [ channel - 1 ] - > link - > id ,
v5up - > ts [ channel - 1 ] - > nr , 1 , channel , NULL , 0 , MDU_BCC_deallocation_req ) ;
}
int v52_le_bcc_mdu_rcv ( struct v5x_interface * v5if , uint8_t link_id , uint8_t ts ,
uint8_t __attribute__ ( ( unused ) ) * isdn_multislot , enum v5x_mgmt_prim prim , const uint8_t * cause ,
uint8_t cause_len )
2022-12-04 16:56:51 +00:00
{
2022-12-26 13:45:13 +00:00
struct v5x_link * v5l ;
struct v5x_user_port * v5up ;
int channel = 0 ;
if ( ts > 31 ) {
LOGP ( DV5MGMT , LOGL_ERROR , " TS %d out of range. \n " , ts ) ;
return - EINVAL ;
}
v5l = v5x_link_find_id ( v5if , link_id ) ;
if ( ! v5l ) {
LOGP ( DV5MGMT , LOGL_ERROR , " Invalid link ID %d. \n " , link_id ) ;
return - EINVAL ;
}
v5up = v5l - > ts [ ts ] . v5up ;
if ( ! v5up ) {
LOGP ( DV5MGMT , LOGL_NOTICE , " TS %d of link ID %d is not assigned. \n " , ts , link_id ) ;
return 0 ;
}
if ( v5up - > ts [ 0 ] = = & v5l - > ts [ ts ] )
channel = 1 ;
if ( v5up - > ts [ 1 ] = = & v5l - > ts [ ts ] )
channel = 2 ;
OSMO_ASSERT ( channel ) ;
2022-12-04 16:56:51 +00:00
switch ( prim ) {
2022-12-26 13:45:13 +00:00
case MDU_BCC_allocation_conf :
LOGP ( DV5MGMT , LOGL_INFO , " Assigned channel %d for %s port %d at TS %d of link %d. \n " ,
channel , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr , ts , link_id ) ;
2023-02-12 14:19:08 +00:00
ph_activate_req ( v5up - > ts [ channel - 1 ] ) ;
2022-12-04 16:56:51 +00:00
break ;
2022-12-26 13:45:13 +00:00
case MDU_BCC_deallocation_conf :
LOGP ( DV5MGMT , LOGL_INFO , " Unassigned channel %d for %s port %d at TS %d of link %d. \n " ,
channel , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr , ts , link_id ) ;
v5l - > ts [ ts ] . v5up = NULL ;
v5up - > ts [ 0 ] = NULL ;
break ;
case MDU_BCC_allocation_reject_ind :
case MDU_BCC_deallocation_reject_ind :
if ( cause_len < 1 )
break ;
LOGP ( DV5MGMT , LOGL_ERROR , " Failed to (un)assign channel %d for %s port %d at TS %d of link %d: %s. \n " ,
channel , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr , ts , link_id ,
get_value_string ( v52_bcc_reject_cause_type_str ,
cause [ 0 ] & 0x7f ) ) ;
if ( cause_len > 1 )
LOGP ( DV5MGMT , LOGL_ERROR , " -> Diagnostic: %s \n " , osmo_hexdump ( cause + 1 , cause_len - 1 ) ) ;
break ;
case MDU_BCC_protocol_error_ind :
if ( cause_len < 1 )
break ;
LOGP ( DV5MGMT , LOGL_ERROR , " Failed to (un)assign channel %d for %s port %d at TS %d of link %d: %s. \n " ,
channel , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr , ts , link_id ,
get_value_string ( v5x_cause_type_str , cause [ 0 ] & 0x7f ) ) ;
if ( cause_len > 1 )
LOGP ( DV5MGMT , LOGL_ERROR , " -> Diagnostic: %s \n " , osmo_hexdump ( cause + 1 , cause_len - 1 ) ) ;
if ( cause_len > = 3 & & cause [ 1 ] = = 0x20 & & cause [ 2 ] = = 0x47 ) {
LOGP ( DV5MGMT , LOGL_ERROR , " AN rejects information-transfer-capability information element, "
" please disable via VTY! \n " ) ;
}
2022-12-04 16:56:51 +00:00
break ;
default :
2022-12-26 13:45:13 +00:00
LOGP ( DV5MGMT , LOGL_ERROR , " Failed to (un)assign channel %d for %s port %d at TS %d of link %d. \n " ,
channel , ( v5up - > type = = V5X_USER_TYPE_PSTN ) ? " PSTN " : " ISDN " , v5up - > nr , ts , link_id ) ;
}
return 0 ;
}
/*
* Protection protocol handling
*/
static void switchover_request_link ( struct v5x_link * v5l , uint8_t link_id , uint8_t ts )
{
LOGP ( DV5MGMT , LOGL_NOTICE , " Switch over request from AN to link %d and TS %d. \n " , link_id , ts ) ;
if ( ! v5l ) {
LOGP ( DV5MGMT , LOGL_ERROR , " -> Rejecting, because requested link is not primary, nor secondary. \n " ) ;
v52_le_pp_mdu_snd ( v5l - > interface , MDU_Protection_switch_over_rej , link_id , ts ,
V52_PP_REJECT_CAUSE_T_TARGET_CC_NOT_PROV ) ;
return ;
}
if ( ts ! = v5l - > c_channel [ 0 ] . ts - > nr ) {
LOGP ( DV5MGMT , LOGL_ERROR , " -> Rejecting, because requested TS is not a C-channel. \n " ) ;
v52_le_pp_mdu_snd ( v5l - > interface , MDU_Protection_switch_over_rej , link_id , ts ,
V52_PP_REJECT_CAUSE_T_TARGET_CC_NOT_PROV ) ;
return ;
2022-12-04 16:56:51 +00:00
}
2022-12-26 13:45:13 +00:00
if ( ! v52_le_lcp_is_operational ( v5l - > fi ) ) {
LOGP ( DV5MGMT , LOGL_ERROR , " -> Rejecting, because requested link is not operational. \n " ) ;
v52_le_pp_mdu_snd ( v5l - > interface , MDU_Protection_switch_over_rej , link_id , ts ,
V52_PP_REJECT_CAUSE_T_TARGET_CC_NOT_OPER ) ;
return ;
}
if ( v5l = = v5l - > interface - > cc_link ) {
LOGP ( DV5MGMT , LOGL_ERROR , " -> Rejecting, because requested allocation exists already. \n " ) ;
v52_le_pp_mdu_snd ( v5l - > interface , MDU_Protection_switch_over_rej , link_id , ts ,
V52_PP_REJECT_CAUSE_T_ALLOC_EXISTS_ALREADY ) ;
return ;
}
LOGP ( DV5MGMT , LOGL_NOTICE , " Sending switch over command to AN. \n " ) ;
v52_le_pp_mdu_snd ( v5l - > interface , MDU_Protection_switch_over_com , link_id , ts , 0 ) ;
}
static void switchover_request ( struct v5x_interface * v5if )
{
LOGP ( DV5MGMT , LOGL_NOTICE , " Switch over request from AN, due to link failure. \n " ) ;
if ( v5if - > primary_link = = v5if - > cc_link ) {
LOGP ( DV5MGMT , LOGL_NOTICE , " Sending switch over command to AN. (go to secondary link) \n " ) ;
v52_le_pp_mdu_snd ( v5if , MDU_Protection_switch_over_com , v5if - > secondary_link - > id , 16 , 0 ) ;
}
if ( v5if - > secondary_link = = v5if - > cc_link ) {
LOGP ( DV5MGMT , LOGL_NOTICE , " Sending switch over command to AN. (go to primary link) \n " ) ;
v52_le_pp_mdu_snd ( v5if , MDU_Protection_switch_over_com , v5if - > primary_link - > id , 16 , 0 ) ;
}
}
int v52_le_pp_mdu_rcv ( struct v5x_interface * v5if , enum v5x_mgmt_prim prim , uint8_t link_id , uint8_t ts ,
const uint8_t * cause , uint8_t cause_len )
{
struct v5x_link * v5l = NULL ;
/* get link from what the AN is talking about */
if ( link_id = = v5if - > primary_link - > id )
v5l = v5if - > primary_link ;
if ( link_id = = v5if - > secondary_link - > id )
v5l = v5if - > secondary_link ;
switch ( prim ) {
case MDU_Protection_switch_over_ack :
LOGP ( DV5MGMT , LOGL_NOTICE , " Switch over request from LE to link %d and TS %d was acked. \n " , link_id ,
ts ) ;
LOGP ( DV5MGMT , LOGL_NOTICE , " Performing switch over. \n " ) ;
if ( v5l )
v5if - > cc_link = v5l ;
break ;
case MDU_Protection_switch_over_req :
if ( ts )
switchover_request_link ( v5l , link_id , ts ) ;
else
switchover_request ( v5if ) ;
break ;
case MDU_Protection_switch_over_reject_ind :
if ( cause_len < 1 )
break ;
LOGP ( DV5MGMT , LOGL_ERROR , " Switch over to link %d and TS %d was rejected by AN: %s. \n " , link_id , ts ,
get_value_string ( v52_pp_reject_cause_type_str , cause [ 0 ] & 0x7f ) ) ;
break ;
case MDU_Protection_switch_over_error_ind :
LOGP ( DV5MGMT , LOGL_NOTICE , " Switch over request from LE to link %d and TS %d failed. \n " , link_id , ts ) ;
break ;
case MDU_Protection_reset_SN_ind :
LOGP ( DV5MGMT , LOGL_NOTICE , " AN resets serial numbers at Protection protocol. \n " ) ;
break ;
case MDU_Protection_reset_SN_com :
LOGP ( DV5MGMT , LOGL_NOTICE , " LE resets serial numbers at Protection protocol. \n " ) ;
break ;
case MDU_Protection_reset_SN_ack :
LOGP ( DV5MGMT , LOGL_NOTICE , " AN acknowledges reset serial numbers at Protection protocol. \n " ) ;
break ;
case MDU_Protection_reset_SN_error_ind :
LOGP ( DV5MGMT , LOGL_NOTICE , " Switch over request failed, due to serial numbers reset at Protection "
" protocol. \n " ) ;
break ;
case MDU_Protection_protocol_error_ind :
if ( cause_len < 1 )
break ;
LOGP ( DV5MGMT , LOGL_ERROR , " Protocol error: %s. \n " ,
get_value_string ( v5x_cause_type_str , cause [ 0 ] & 0x7f ) ) ;
if ( cause_len > 1 )
LOGP ( DV5MGMT , LOGL_ERROR , " -> Diagnostic: %s \n " , osmo_hexdump ( cause + 1 , cause_len - 1 ) ) ;
break ;
default :
LOGP ( DV5MGMT , LOGL_ERROR , " Unknown message primitive %d. \n " , prim ) ;
}
return 0 ;
2022-12-04 16:56:51 +00:00
}