osmo-v5/src/v5x_internal.h

398 lines
13 KiB
C

#pragma once
/* (C) 2021 by Harald Welte <laforge@gnumonks.org>
* (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.
*
*/
#include <stdint.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/fsm.h>
#include <osmocom/core/select.h>
#include <osmocom/gsm/lapd_core.h>
#include <osmocom/abis/e1_input.h>
#include "libecho/echo_cancel.h"
#include "libecho/echo_suppress.h"
#include "libecho/answertone.h"
#include "ph_socket.h"
/* Table 35/G.964 */
enum v5x_mph_prim {
MPH_UBR, /* Unblock (req) */
MPH_UBI, /* Unblock (ind) */
MPH_BR, /* Block (req) */
MPH_BI, /* Block (ind) */
MPH_AR, /* Activate (req) */
MPH_AI, /* Activate (ind) */
MPH_AWI, /* Access activation by user (ind) */
MPH_DSAI, /* DS Activated (ind) */
MPH_DR, /* Deactivate (req) */
MPH_DI, /* Deactivate (ind) */
MPH_GI, /* Grading Information */
MPH_DB, /* Block D-Channel from user port */
MPH_DU, /* Unblock D-Channel from user port */
MPH_ID, /* Identity Sa7=0 signal request (TX) */
MPH_NOR, /* Normal Sa7=1 signal request (TX) */
MPH_IDR, /* Request Sa7 signal (RX) */
MPH_IDI, /* Indicate Sa7=0 signal (RX) */
MPH_EIg, /* Indicate Sa7=1 singal (RX) */
MPH_EIa, /* Indicate LOS */
MPH_EIb, /* RAI */
MPH_EIc, /* AIS */
MPH_EId, /* Internal failure */
MPH_EIe, /* CRC received */
MPH_EIf, /* E-bit received */
MPH_stop, /* See L1 FSM */
MPH_proceed, /* See L1 FSM */
MPH_EIbr, /* See L1 FSM */
MPH_EIdr, /* See L1 FSM */
};
/* Table 3/G.964 */
enum v5x_fe_prim {
FE_establish_req = 0x00,
FE_establish_ack_ind = 0x03,
FE_establish_ind = 0x01,
FE_establish_ack_req = 0x02,
FE_line_signal_req = 0x10,
FE_line_signal_ind = 0x11,
FE_protocol_param_req = 0x20,
FE_disconnect_req = 0x30,
FE_disconnect_compl_req = 0x32,
FE_disconnect_compl_ind = 0x33,
};
enum v5x_mgmt_prim {
/* Table 3/G.964 */
MDU_CTRL_port_blocked,
MDU_CTRL_port_unblocked,
MDU_CTRL_port_restart_req,
MDU_CTRL_port_restart_ack,
MDU_CTRL_port_restart_compl,
MDU_error_ind,
/* Table 14/G.965 */
MDU_AI,
MDU_DI,
MDU_LAI,
MDU_IDReq,
MDU_IDAck,
MDU_IDRel,
MDU_IDRej,
MDU_EIg,
MDU_LUBR,
MDU_LUBI,
MDU_LBI,
MDU_LBR,
MDU_LBRN,
/* Table 26/G.965 */
MDU_BCC_allocation_req,
MDU_BCC_allocation_conf,
MDU_BCC_allocation_reject_ind,
MDU_BCC_allocation_error_ind,
MDU_BCC_deallocation_req,
MDU_BCC_deallocation_conf,
MDU_BCC_deallocation_reject_ind,
MDU_BCC_deallocation_error_ind,
MDU_BCC_audit_req,
MDU_BCC_audit_conf,
MDU_BCC_audit_error_ind,
MDU_BCC_AN_fault_ind,
MDU_BCC_protocol_error_ind,
/* Table 50/G.965 */
MDU_Protection_switch_over_com,
MDU_Protection_OS_switch_over_com,
MDU_Protection_switch_over_ack,
MDU_Protection_switch_over_rej,
MDU_Protection_switch_over_req,
MDU_Protection_switch_over_reject_ind,
MDU_Protection_switch_over_error_ind,
MDU_Protection_reset_SN_ind,
MDU_Protection_reset_SN_com,
MDU_Protection_reset_SN_req,
MDU_Protection_reset_SN_ack,
MDU_Protection_reset_SN_error_ind,
MDU_Protection_protocol_error_ind,
/* Figure 11/G.964 */
MDL_ESTABLISH_req,
MDL_ESTABLISH_cnf,
MDL_ESTABLISH_ind,
MDL_RELEASE_ind,
MDL_ERROR_ind,
MDL_LAYER_1_FAILURE_ind,
};
struct osmo_fsm_inst;
enum v5x_dialect {
V5X_DIALECT_V51 = 1,
V5X_DIALECT_V52 = 2,
};
enum v5x_user_type {
V5X_USER_TYPE_ISDN = 1,
V5X_USER_TYPE_PSTN = 2,
};
enum v5x_ctrl_type {
V5X_CTRL_TYPE_COMMON = 1,
V5X_CTRL_TYPE_PORT = 2,
V5X_CTRL_TYPE_LINK = 3,
};
/* forward-declarations */
struct v5x_interface;
struct v5x_instance;
struct v5x_user_port;
struct v5x_link;
struct v5x_l1_proto;
struct v52_pp_proto;
/* A C-channel is a 64k timeslot used for signalling */
struct v5x_c_channel {
struct v5x_link *link; /* back-pointer */
struct v5x_timeslot *ts; /* E1 link timeslot. NULL = C-channel doesn't exist */
bool active; /* false == standby */
};
/* one physical E1 timeslot used on an E1 interface part of a V5.2 interface */
struct v5x_timeslot {
uint8_t nr;
struct v5x_link *link; /* back-pointer */
struct v5x_user_port *v5up; /* user port that this TS is assigned to */
bool b_channel; /* channel can be used as b-channel */
bool b_activated; /* activated (b-channel) at libosmo-abis */
};
/* one physical E1 interface used within a V5.2 interface */
struct v5x_link {
struct llist_head list; /* interface.links */
uint8_t id;
struct v5x_interface *interface; /* back-pointer */
struct v5x_timeslot ts[32]; /* 32 E1 slots; 0 not available */
struct v5x_c_channel c_channel[3]; /* 64k signaling possible on TS16, TS15 and TS31 */
struct v5x_l1_proto *l1; /* Layer 1 Link FSM protocol */
struct v5x_ctrl_proto *ctrl; /* Link control protocol instance */
struct osmo_fsm_inst *fi; /* Link Control FSM instance */
struct e1inp_line *e1_line; /* E1 line to use or NULL if not */
struct e1inp_line_ops e1_line_ops; /* use e1pinp_line->ops to point back to v5x_link */
};
/* one V5.x interface between AN (Access Network) and LE (Local Exchange) */
struct v5x_interface {
struct llist_head list; /* instance.interfaces */
struct v5x_instance *instance; /* back-pointer */
enum v5x_dialect dialect;
uint32_t id_local, id_remote; /* interface id */
uint8_t variant_local, variant_remote; /* provitioning variant */
bool id_remote_valid;
bool variant_remote_valid;
bool use_capability; /* use bearer transfer capability */
uint8_t capability; /* bearer transfer capability */
struct v5x_mgmt_proto *mgmt; /* management prococol states */
struct {
struct v5x_ctrl_proto *ctrl; /* common control protocol instance */
struct lapv5_instance *li; /* Control data link */
bool established; /* track if link is up or down */
} control;
struct {
struct lapv5_instance *li; /* Link control data link */
bool established; /* track if link is up or down */
} lcp;
struct {
struct lapv5_instance *li; /* PSTN data link */
bool established; /* track if link is up or down */
} pstn;
struct {
struct lapv5_instance *li; /* BCC data link */
bool established; /* track if link is up or down */
} bcc;
struct {
uint16_t cc_id; /* CC-ID of protected C-channel */
struct v52_pp_proto *pp; /* protection protocol instance */
struct lapv5_instance *li[2]; /* Protection data link 1 + 2 */
bool established[2]; /* track if link is up or down */
} protection;
struct llist_head links; /* list of v5x_link */
struct v5x_link *primary_link; /* primary link */
struct v5x_link *secondary_link; /* standby link */
struct v5x_link *cc_link; /* currently used link for signaling (primary on startup) */
struct llist_head user_ports; /* list of v5x_user_port */
struct llist_head bcc_procs; /* list of v52_bcc_procs */
};
struct v5x_l1_proto {
struct v5x_link *v5l; /* back pointer */
struct osmo_fsm_inst *fi; /* L1 FSM */
int los, rai, ais, sa7; /* RX signal states */
};
struct v5x_ctrl_proto {
enum v5x_ctrl_type type; /* type of control protocol: common/port/link */
void *priv; /* back pointer to the user */
struct osmo_fsm_inst *fi; /* control FSM */
struct llist_head tx_queue; /* list of message to be transmitted */
struct msgb *tx_msg; /* copy of unacked message, for second try */
};
struct v5x_pstn_proto {
struct v5x_user_port *v5up; /* back pointer, if port control is used */
struct osmo_fsm_inst *fi; /* control FSM */
uint8_t S_s, S_a, S_r; /* sequence numbers */
struct msgb *tx_msg; /* copy of unacked message, for repitition */
int timeout_event; /* event when timer times out */
int timeout_count; /* how many times the timer was started/timed out */
struct osmo_timer_list timer_Tr; /* extra timer for receive sequence ack */
struct osmo_timer_list timer_Tt; /* extra timer for transmit sequence ack */
};
/* indexes of blocking/unblocking instances */
#define UNBLK_ALL_PSTN_ISDN 0
#define UNBLK_ALL_PSTN 1
#define UNBLK_ALL_ISDN 2
#define BLK_ALL_PSTN 3
#define BLK_ALL_ISDN 4
struct v5x_mgmt_proto {
struct v5x_interface *interface; /* back-pointer to instance we're part of */
bool auto_restart; /* restart automatically after TC8/TC9 timeout */
bool pstn_rs_pending; /* pending restart flag */
bool do_est; /* actively establish datalinks */
bool do_align; /* actively perform alignment */
bool acc_align; /* use accellerated alignment */
struct osmo_fsm_inst *system_fi; /* system startup FSM */
struct osmo_fsm_inst *pstn_dl_fi; /* PSTN DL startup FSM */
struct osmo_fsm_inst *pstn_rs_fi; /* PSTN restart FSM */
struct osmo_fsm_inst *unblk_all_fi[5]; /* unblock/block all FSM (5 instances) */
struct osmo_timer_list timer_system; /* delayed start, so sockets can connect first */
struct osmo_timer_list timer_tr1; /* see Table C.1/G.965 */
struct osmo_timer_list timer_tr2;
struct osmo_timer_list timer_tc1;
struct osmo_timer_list timer_tc2;
struct osmo_timer_list timer_tc3;
struct osmo_timer_list timer_tc7;
struct osmo_timer_list timer_tc8;
struct osmo_timer_list timer_tc9;
struct osmo_timer_list timer_tv1;
};
#define EC_BUFFER 1024
#define EC_TAPS 256
#define USE_ECHO_CANCELER 1
#define USE_ECHO_SUPPRESSOR 2
struct v5x_echo_proc {
struct v5x_user_port *port; /* back pointer to user port */
int enabled; /* line echo canceler enabled (configured and not disabled by ANS) */
echo_can_state_t *ec; /* echo canceler state */
echo_sup_state_t *es; /* echo suppressor state */
int16_t tx_buffer[EC_BUFFER]; /* buffer to store TX audio */
int tx_buffer_in; /* next pos to write to buffer */
int tx_buffer_out; /* next pos to read from buffer */
struct answer_tone at; /* answer tone detector process */
};
/* one user-facing port (subscriber line) */
struct v5x_user_port {
struct llist_head list; /* part of v5x_instance.ports */
struct v5x_interface *interface; /* back-pointer to instance we're part of */
uint16_t nr; /* port-number in decoded form (0..32767) */
char ifname[64]; /* name of interface, also used for PH-socket */
enum v5x_user_type type; /* type of port (ISDN/PSTN) */
struct v5x_ctrl_proto *ctrl; /* port control protocol instance */
struct osmo_fsm_inst *port_fi; /* port FSM */
struct v5x_timeslot *ts[2]; /* two time slots */
struct {
} isdn;
struct {
struct v5x_pstn_proto *proto;
} pstn;
ph_socket_t ph_socket; /* unix socket to connect port to */
bool le_unblocked; /* if port is not blocked by LE */
bool an_unblocked; /* if port is not blocked by AN */
int use_line_echo; /* line echo canceler/suppressor is configured */
struct v5x_echo_proc ep[2]; /* echo canceler process */
};
/* BCC process */
struct v52_bcc_proc {
struct llist_head list; /* part of v5x_instance.ports */
struct v5x_interface *interface; /* back-pointer to instance we're part of */
struct osmo_fsm_inst *fi; /* BCC FSM */
uint16_t ref; /* reference of this process */
uint8_t source_id; /* reference source */
int timer; /* timer used */
int expired; /* number of timeouts */
uint16_t user_port_id; /* port ID */
bool is_isdn; /* user port type */
uint8_t link_id; /* link ID */
uint8_t ts; /* TS nr */
uint8_t override; /* override assigned channel */
uint8_t isdn_slot; /* channel on ISDN interface */
uint8_t *isdn_multislot; /* multiple slot assignment */
bool use_capability; /* use bearer transfer capability */
uint8_t capability; /* bearer transfer capability */
};
struct v52_pp_mgmt_info {
uint8_t link_id;
uint8_t ts;
uint8_t cause;
};
/* PP process */
struct v52_pp_proto {
struct v5x_interface *interface; /* back pointer, if port control is used */
struct osmo_fsm_inst *fi; /* PP FSM */
uint8_t vp_s, vp_r; /* sequence numbers */
bool vp_r_set; /* if we ever received a sequence number */
struct v52_pp_mgmt_info info; /* keep management info for resend after timeout */
int timeout_event; /* event when timer times out */
int timeout_count; /* how many times the timer was started/timed out */
};
struct v5x_instance {
struct llist_head list; /* part of global list of instances */
struct llist_head interfaces; /* v5x_interface.list */
};
struct v5x_instance *v5x_instance_alloc(void *ctx);
void v5x_instance_free(struct v5x_instance *v5i);
struct v5x_interface *v5x_interface_alloc(struct v5x_instance *v5i, enum v5x_dialect dialect);
struct v5x_user_port *v5x_user_port_create(struct v5x_interface *v5if, uint16_t nr, enum v5x_user_type,
uint8_t ts1, uint8_t ts2);
void v5x_interface_free(struct v5x_interface *v5if);
struct v5x_user_port *v5x_user_port_find(struct v5x_interface *v5if, uint16_t nr, bool is_isdn);
void v5x_user_port_destroy(struct v5x_user_port *v5up);
void v5x_echo_reset(struct v5x_echo_proc *ep, int enable);
struct v5x_link *v5x_link_create(struct v5x_interface *v5if, uint8_t id);
int v5x_link_destroy(struct v5x_link *v5l);
int v5x_link_count(struct v5x_interface *v5if);
struct v5x_link *v5x_link_find_id(struct v5x_interface *v5if, uint8_t id);