336 lines
11 KiB
C
336 lines
11 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 "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 */
|
|
};
|
|
|
|
/* 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 */
|
|
int e1_line; /* E1 line to use or -1 if not */
|
|
};
|
|
|
|
/* 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 */
|
|
};
|
|
|
|
/* 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 */
|
|
uint8_t ts_activated[2]; /* set if data stream is active */
|
|
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 */
|
|
};
|
|
|
|
/* 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);
|
|
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);
|
|
struct v5x_link *v5x_link_find_e1_line(struct v5x_interface *v5if, uint8_t id);
|