#pragma once /* (C) 2021 by Harald Welte * (C) 2022 by Andreas Eversberg * * 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 #include #include #include #include #include #include "libecho/echo.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, }; 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 { 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 */ }; #define EC_BUFFER 1024 #define EC_TAPS 256 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 */ 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 blocking_enabled; /* we may only send blocking updates, if true */ bool le_unblocked; /* if port is not blocked by LE */ bool an_unblocked; /* if port is not blocked by AN */ int echo_configured; /* line echo canceler 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);