/* (C) 2021 by Harald Welte * * 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 #include "logging.h" #include "v5x_internal.h" #include "v5x_protocol.h" #include "v51_le_ctrl.h" #include "lapv5.h" const struct tlv_definition v51_ctrl_tlv_def = { .def = { /* single byte: PSTN / G.964 Table 17 */ [V51_CTRL_IEI_PULSE_NOTIFICATION] = { TLV_TYPE_SINGLE_TV }, [V51_CTRL_IEI_LINE_NOTIFICATION] = { TLV_TYPE_SINGLE_TV }, [V51_CTRL_IEI_STATE] = { TLV_TYPE_SINGLE_TV }, [V51_CTRL_IEI_AUTONOMOUS_SIG_SEQ] = { TLV_TYPE_SINGLE_TV }, [V51_CTRL_IEI_SEQUENCE_RESPONSE] = { TLV_TYPE_SINGLE_TV }, /* single byte: ISDN / G.964 Table 53 */ [V51_CTRL_IEI_PERFORMANCE_GRADING] = { TLV_TYPE_SINGLE_TV }, [V51_CTRL_IEI_REJECTION_CAUSE] = { TLV_TYPE_SINGLE_TV }, /* variable length: PSTN / G.964 Table 17 */ [V51_CTRL_IEI_SEQUENCE_NR] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_CADENCED_RINGING] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_PULSED_SIGNAL] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_STEADY_SIGNAL] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_DIGIT_SIGNAL] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_RECOGNITION_TIME] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_ENABLE_AUTONOMOUS_ACK] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_DISABLE_AUTONOMOUS_ACK] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_CAUSE] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_RESOURCE_UNAVAILABLE] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_ENABLE_METERING] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_METERING_REPORT] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_ATTENUATION] = { TLV_TYPE_TLV }, /* variable length: ISDN / G.964 Table 53 */ [V51_CTRL_IEI_CTRL_F_ELEMENT] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_CTRL_F_ID] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_VARIANT] = { TLV_TYPE_TLV }, [V51_CTRL_IEI_INTERFACE_ID] = { TLV_TYPE_TLV }, /* variable length: LCP / G.965 Table FIXME */ [V52_CTRL_IEI_LCP_LINK_CTRL_FUNCTION] = { TLV_TYPE_TLV }, /* variable length: BCC */ [V52_CTRL_IEI_BCC_USER_PORT_ID] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_BCC_ISDN_PORT_TS_ID] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_BCC_V5_TS_ID] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_BCC_MULTI_TS_MAP] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_BCC_REJECT_CAUSE] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_BCC_PROTOCOL_ERROR_CAUSE] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_BCC_CONNECTION_INCOMPLETE] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_BCC_INFO_TRANSFER_CAPABILITY] = { TLV_TYPE_TLV }, /* variable-length: Protection */ [V52_CTRL_IEI_PP_SEQUENCE_NR] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_PP_PHYSICAL_C_CHAN_ID] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_PP_REJECTION_CAUSE] = { TLV_TYPE_TLV }, [V52_CTRL_IEI_PP_PROTOCOL_ERROR_CAUSE] = { TLV_TYPE_TLV }, }, }; const struct value_string v51_ctrl_msg_typ_str[] = { { V51_CTRL_MSGT_ESTABLISH, "ESTABLISH" }, { V51_CTRL_MSGT_ESTABLISH_ACK, "ESTABLISH_ACK" }, { V51_CTRL_MSGT_SIGNAL, "SIGNAL" }, { V51_CTRL_MSGT_SIGNAL_ACK, "SIGNAL_ACK" }, { V51_CTRL_MSGT_DISCONNECT, "DISCONNECT" }, { V51_CTRL_MSGT_DISCONNECT_ACK, "DISCONNECT_ACK" }, { V51_CTRL_MSGT_STATUS_ENQUIRY, "STATUS_ENQUIRY" }, { V51_CTRL_MSGT_STATUS, "STATUS" }, { V51_CTRL_MSGT_PROTOCOL_PARAMETER, "PROTOCOL_PARAMETER" }, { V51_CTRL_MSGT_PORT_CTRL, "PORT_CTRL" }, { V51_CTRL_MSGT_PORT_CTRL_ACK, "PORT_CTRL_ACK" }, { V51_CTRL_MSGT_COMMON_CTRL, "COMMON_CTRL" }, { V51_CTRL_MSGT_COMMON_CTRL_ACK, "COMMON_CTRL_ACK" }, { V52_CTRL_MSGT_PP_SWITCH_OVER_REQ, "SWITCH_OVER_REQ" }, { V52_CTRL_MSGT_PP_SWITCH_OVER_COM, "SWITCH_OVER_COM" }, { V52_CTRL_MSGT_PP_OS_SWITCH_OVER_COM, "OS_SWITCH_OVER_COM" }, { V52_CTRL_MSGT_PP_SWITCH_OVER_ACK, "SWITCH_OVER_ACK" }, { V52_CTRL_MSGT_PP_SWITCH_OVER_REJECT, "SWITCH_OVER_REJECT" }, { V52_CTRL_MSGT_PP_PROTOCOL_ERROR, "PROTOCOL_ERROR" }, { V52_CTRL_MSGT_PP_RESET_SN_COM, "RESET_SN_COM" }, { V52_CTRL_MSGT_PP_RESET_SN_ACK, "RESET_SN_ACK" }, { V52_CTRL_MSGT_ALLOCATION, "ALLOCATION" }, { V52_CTRL_MSGT_ALLOCATION_COMPLETE, "ALLOCATION_COMPLETE" }, { V52_CTRL_MSGT_ALLOCATION_REJECT, "ALLOCATION_REJECT" }, { V52_CTRL_MSGT_DE_ALLOCATION, "DE_ALLOCATION" }, { V52_CTRL_MSGT_DE_ALLOCATION_COMPLETE, "DE_ALLOCATION_COMPLETE" }, { V52_CTRL_MSGT_DE_ALLOCATION_REJECT, "DE_ALLOCATION_REJECT" }, { V52_CTRL_MSGT_AUDIT, "AUDIT" }, { V52_CTRL_MSGT_AUDIT_COMPLETE, "AUDIT_COMPLETE" }, { V52_CTRL_MSGT_AN_FAULT, "AN_FAULT" }, { V52_CTRL_MSGT_AN_FAULT_ACK, "AN_FAULT_ACKNOWLEDGE" }, { V52_CTRL_MSGT_PROTOCOL_ERROR, "PROTOCOL_ERROR" }, { V52_CTRL_MSGT_LCP_LINK_CTRL, "LINK_CTRL" }, { V52_CTRL_MSGT_LCP_LINK_CTRL_ACK, "LINK_CTRL_ACK" }, { 0, NULL } }; const struct value_string v51_ctrl_iei_str[] = { { V51_CTRL_IEI_PULSE_NOTIFICATION, "PULSE_NOTIFICATION" }, { V51_CTRL_IEI_LINE_NOTIFICATION, "LINE_NOTIFICATION" }, { V51_CTRL_IEI_STATE, "STATE" }, { V51_CTRL_IEI_AUTONOMOUS_SIG_SEQ, "AUTONOMOUS_SIG_SEQ" }, { V51_CTRL_IEI_SEQUENCE_RESPONSE, "SEQUENCE_RESPONSE" }, { V51_CTRL_IEI_PERFORMANCE_GRADING, "PERFORMANCE_GRADING" }, { V51_CTRL_IEI_REJECTION_CAUSE, "REJECTION_CAUSE" }, { V51_CTRL_IEI_SEQUENCE_NR, "SEQUENCE_NR" }, { V51_CTRL_IEI_CADENCED_RINGING, "CADENCED_RINGING" }, { V51_CTRL_IEI_PULSED_SIGNAL, "PULSED_SIGNAL" }, { V51_CTRL_IEI_STEADY_SIGNAL, "STEADY_SIGNAL" }, { V51_CTRL_IEI_DIGIT_SIGNAL, "DIGIT_SIGNAL" }, { V51_CTRL_IEI_RECOGNITION_TIME, "RECOGNITION_TIME" }, { V51_CTRL_IEI_ENABLE_AUTONOMOUS_ACK, "ENABLE_AUTONOMOUS_ACK" }, { V51_CTRL_IEI_DISABLE_AUTONOMOUS_ACK, "DISABLE_AUTONOMOUS_ACK" }, { V51_CTRL_IEI_CAUSE, "CAUSE" }, { V51_CTRL_IEI_RESOURCE_UNAVAILABLE, "RESOURCE_UNAVAILABLE" }, { V51_CTRL_IEI_ENABLE_METERING, "ENABLE_METERING" }, { V51_CTRL_IEI_METERING_REPORT, "METERING_REPORT" }, { V51_CTRL_IEI_ATTENUATION, "ATTENUATION" }, { V51_CTRL_IEI_CTRL_F_ELEMENT, "CTRL_F_ELEMENT" }, { V51_CTRL_IEI_CTRL_F_ID, "CTRL_F_ID" }, { V51_CTRL_IEI_VARIANT, "VARIANT" }, { V51_CTRL_IEI_INTERFACE_ID, "INTERFACE_ID" }, { V52_CTRL_IEI_LCP_LINK_CTRL_FUNCTION, "LCP_LINK_CTRL_FUNCTION" }, { V52_CTRL_IEI_BCC_USER_PORT_ID, "BCC_USER_PORT_ID" }, { V52_CTRL_IEI_BCC_ISDN_PORT_TS_ID, "BCC_ISDN_PORT_TS_ID" }, { V52_CTRL_IEI_BCC_V5_TS_ID, "BCC_V5_TS_ID" }, { V52_CTRL_IEI_BCC_MULTI_TS_MAP, "BCC_MULTI_TS_MAP" }, { V52_CTRL_IEI_BCC_REJECT_CAUSE, "BCC_REJECT_CAUSE" }, { V52_CTRL_IEI_BCC_PROTOCOL_ERROR_CAUSE, "BCC_PROTOCOL_ERROR_CAUSE" }, { V52_CTRL_IEI_BCC_CONNECTION_INCOMPLETE, "BCC_CONNECTION_INCOMPLETE" }, { V52_CTRL_IEI_BCC_INFO_TRANSFER_CAPABILITY, "BCC_INFO_TRANSFER_CAPABILITY" }, { V52_CTRL_IEI_PP_SEQUENCE_NR, "PP_SEQUENCE_NR" }, { V52_CTRL_IEI_PP_PHYSICAL_C_CHAN_ID, "PP_PHYSICAL_C_CHAN_ID" }, { V52_CTRL_IEI_PP_REJECTION_CAUSE, "PP_REJECTION_CAUSE" }, { V52_CTRL_IEI_PP_PROTOCOL_ERROR_CAUSE, "PP_PROTOCOL_ERROR_CAUSE" }, { 0, NULL } }; const struct value_string v51_ctrl_func_el_str[] = { { V51_CTRL_FE101_ACTIVATE_ACCESS, "FE101_ACTIVATE_ACCESS" }, { V51_CTRL_FE102_ACT_INIT_BY_USER, "FE102_ACT_INIT_BY_USER" }, { V51_CTRL_FE103_DS_ACTIVATED, "FE103_DS_ACTIVATED" }, { V51_CTRL_FE104_ACCESS_ACTIVATED, "FE104_ACCESS_ACTIVATED" }, { V51_CTRL_FE105_DEACTIVATE_ACCESS, "FE105_DEACTIVATE_ACCESS" }, { V51_CTRL_FE106_ACCESS_DEACTIVATED, "FE106_ACCESS_DEACTIVATED" }, { V51_CTRL_FE201_UNBLOCK, "FE201_UNBLOCK" }, { V51_CTRL_FE203_BLOCK, "FE203_BLOCK" }, { V51_CTRL_FE205_BLOCK_REQ, "FE205_BLOCK_REQ" }, { V51_CTRL_FE206_PERFORMANCE_GRADING, "FE206_PERFORMANCE_GRADING" }, { V51_CTRL_FE207_D_CHANNEL_BLOCK, "FE207_D_CHANNEL_BLOCK" }, { V51_CTRL_FE208_D_CHANNEL_UNBLOCK, "FE208_D_CHANNEL_UNBLOCK" }, { 0, NULL } }; const struct value_string v51_ctrl_func_id_str[] = { { V51_CTRL_ID_VERIFY_RE_PROVISIONING, "VERIFY_RE_PROVISIONING" }, { V51_CTRL_ID_READY_FOR_RE_PROVISIONING, "READY_FOR_RE_PROVISIONING" }, { V51_CTRL_ID_NOT_READY_FOR_RE_PROVISIONING, "NOT_READY_FOR_RE_PROVISIONING" }, { V51_CTRL_ID_SWITCH_OVER_TO_NEW_VARIANT, "SWITCH_OVER_TO_NEW_VARIANT" }, { V51_CTRL_ID_RE_PROVISIONING_STARTED, "RE_PROVISIONING_STARTED" }, { V51_CTRL_ID_CANNOT_RE_PROVISION, "CANNOT_RE_PROVISION" }, { V51_CTRL_ID_REQUEST_VARIANT_AND_INTERFACE_ID, "REQUEST_VARIANT_AND_INTERFACE_ID" }, { V51_CTRL_ID_VARIANT_AND_INTERFACE_ID, "VARIANT_AND_INTERFACE_ID" }, { V51_CTRL_ID_BLOCKING_STARTED, "BLOCKING_STARTED" }, { V51_CTRL_ID_RESTART_REQUEST, "RESTART_REQUEST" }, { V51_CTRL_ID_RESTART_COMPLETE, "RESTART_COMPLETE" }, { 0, NULL } }; const struct value_string v51_cause_type_str[] = { { V51_CTRL_CAUSE_T_RESP_TO_STATUS_ENQ, "RESP_TO_STATUS_ENQ" }, { V51_CTRL_CAUSE_T_L3_ADDRESS_ERROR, "L3_ADDRESS_ERROR" }, { V51_CTRL_CAUSE_T_MSG_TYPE_UNRECOGNIZED, "MSG_TYPE_UNRECOGNIZED" }, { V51_CTRL_CAUSE_T_OUT_OF_SEQUENCE_IE, "OUT_OF_SEQUENCE_IE" }, { V51_CTRL_CAUSE_T_REPEATED_OPT_IE, "REPEATED_OPT_IE" }, { V51_CTRL_CAUSE_T_MAND_IE_MISSING, "MAND_IE_MISSING" }, { V51_CTRL_CAUSE_T_UNRECOGNIZED_IE, "UNRECOGNIZED_IE" }, { V51_CTRL_CAUSE_T_MAND_IE_CONTENT_ERROR, "MAND_IE_CONTENT_ERROR" }, { V51_CTRL_CAUSE_T_OPT_IE_CONTENT_ERROR, "OPT_IE_CONTENT_ERROR" }, { V51_CTRL_CAUSE_T_MSG_INCOMP_PATH_STATE, "MSG_INCOMP_PATH_STATE" }, { V51_CTRL_CAUSE_T_REPEATED_MAND_IE, "REPEATED_MAND_IE" }, { V51_CTRL_CAUSE_T_TOO_MANY_IE, "TOO_MANY_IE" }, { 0, NULL } }; static const uint8_t signal_mand_ies[] = { V51_CTRL_IEI_SEQUENCE_NR }; static const uint8_t signal_ack_mand_ies[] = { V51_CTRL_IEI_SEQUENCE_NR }; static const uint8_t status_mand_ies[] = { V51_CTRL_IEI_STATE, V51_CTRL_IEI_CAUSE }; static const uint8_t prot_par_mand_ies[] = { V51_CTRL_IEI_SEQUENCE_NR }; static const uint8_t port_ctrl_mand_ies[] = { V51_CTRL_IEI_CTRL_F_ELEMENT }; static const uint8_t common_ctrl_mand_ies[] = { V51_CTRL_IEI_CTRL_F_ID }; static const uint8_t lcp_mand_ies[] = { V52_CTRL_IEI_LCP_LINK_CTRL_FUNCTION }; static const uint8_t alloc_mand_ies[] = { V52_CTRL_IEI_BCC_USER_PORT_ID }; static const uint8_t alloc_rej_mand_ies[] = { V52_CTRL_IEI_BCC_REJECT_CAUSE }; static const uint8_t prot_err_mand_ies[] = { V52_CTRL_IEI_BCC_PROTOCOL_ERROR_CAUSE }; static const uint8_t pp_swo_mand_ies[] = { V52_CTRL_IEI_PP_SEQUENCE_NR, V52_CTRL_IEI_PP_PHYSICAL_C_CHAN_ID }; static const uint8_t pp_swo_rej_mand_ies[] = { V52_CTRL_IEI_PP_SEQUENCE_NR, V52_CTRL_IEI_PP_PHYSICAL_C_CHAN_ID, V52_CTRL_IEI_PP_REJECTION_CAUSE, }; static const uint8_t pp_perr_mand_ies[] = { V52_CTRL_IEI_PP_SEQUENCE_NR, V52_CTRL_IEI_PP_PROTOCOL_ERROR_CAUSE, }; const struct osmo_tlv_prot_def v51_ctrl_msg_tlv = { .name = "V51_CTRL", .tlv_def = &v51_ctrl_tlv_def, .msg_def = { /* G.964 Section 13.3 */ [V51_CTRL_MSGT_ESTABLISH] = MSG_DEF("ESTABLISH", NULL, 0), [V51_CTRL_MSGT_ESTABLISH_ACK] = MSG_DEF("ESTABLISH", NULL, 0), [V51_CTRL_MSGT_SIGNAL] = MSG_DEF("SIGNAL", signal_mand_ies, 0), [V51_CTRL_MSGT_SIGNAL_ACK] = MSG_DEF("SIGNAL_ACK", signal_ack_mand_ies, 0), [V51_CTRL_MSGT_STATUS] = MSG_DEF("STATUS", status_mand_ies, 0), [V51_CTRL_MSGT_STATUS_ENQUIRY] = MSG_DEF("STATUS_ENQUIRY", NULL, 0), [V51_CTRL_MSGT_DISCONNECT] = MSG_DEF("DISCONNECT", NULL, 0), [V51_CTRL_MSGT_DISCONNECT_ACK] = MSG_DEF("DISCONNECT_ACK", NULL, 0), [V51_CTRL_MSGT_PROTOCOL_PARAMETER] = MSG_DEF("PROTOCOL_PARAMETER", prot_par_mand_ies, 0), /* G.964 Section 14.4 */ [V51_CTRL_MSGT_PORT_CTRL] = MSG_DEF("PORT_CTRL", port_ctrl_mand_ies, 0), [V51_CTRL_MSGT_PORT_CTRL_ACK] = MSG_DEF("PORT_CTRL_ACK", port_ctrl_mand_ies, 0), [V51_CTRL_MSGT_COMMON_CTRL] = MSG_DEF("COMMON_CTRL", common_ctrl_mand_ies, 0), [V51_CTRL_MSGT_COMMON_CTRL_ACK] = MSG_DEF("COMMON_CTRL_ACK", common_ctrl_mand_ies, 0), /* G.965 Section 16.3 LCP */ [V52_CTRL_MSGT_LCP_LINK_CTRL] = MSG_DEF("LINK_CONTROL", lcp_mand_ies, 0), [V52_CTRL_MSGT_LCP_LINK_CTRL_ACK] = MSG_DEF("LINK_CONTROL_ACK", lcp_mand_ies, 0), /* G.965 Section 17.3 BCC */ [V52_CTRL_MSGT_ALLOCATION] = MSG_DEF("ALLOCATION", alloc_mand_ies, 0), [V52_CTRL_MSGT_ALLOCATION_COMPLETE] = MSG_DEF("ALLOCATION_COMPLETE", NULL, 0), [V52_CTRL_MSGT_ALLOCATION_REJECT] = MSG_DEF("ALLOCATION_REJECT", alloc_rej_mand_ies, 0), [V52_CTRL_MSGT_DE_ALLOCATION] = MSG_DEF("DE_ALLOCATION", alloc_mand_ies, 0), [V52_CTRL_MSGT_DE_ALLOCATION_COMPLETE] = MSG_DEF("DE_ALLOCATION_COMPLETE", NULL, 0), [V52_CTRL_MSGT_DE_ALLOCATION_REJECT] = MSG_DEF("DE_ALLOCATION_REJECT", alloc_rej_mand_ies, 0), [V52_CTRL_MSGT_AUDIT] = MSG_DEF("AUDIT", NULL, 0), [V52_CTRL_MSGT_AUDIT_COMPLETE] = MSG_DEF("AUDIT_COMPLETE", NULL, 0), [V52_CTRL_MSGT_AN_FAULT] = MSG_DEF("AN_FAULT", NULL, 0), [V52_CTRL_MSGT_AN_FAULT_ACK] = MSG_DEF("AN_FAULT_ACK", NULL, 0), [V52_CTRL_MSGT_PROTOCOL_ERROR] = MSG_DEF("PROTOCOL_ERROR", prot_err_mand_ies, 0), /* G.965 Section 18.3 PP */ [V52_CTRL_MSGT_PP_SWITCH_OVER_REQ] = MSG_DEF("SWITCH_OVER_REQ", pp_swo_mand_ies, 0), [V52_CTRL_MSGT_PP_SWITCH_OVER_COM] = MSG_DEF("SWITCH_OVER_COM", pp_swo_mand_ies, 0), [V52_CTRL_MSGT_PP_OS_SWITCH_OVER_COM] = MSG_DEF("OS_SWITCH_OVER_COM", pp_swo_mand_ies, 0), [V52_CTRL_MSGT_PP_SWITCH_OVER_ACK] = MSG_DEF("SWITCH_OVER_ACK", pp_swo_mand_ies, 0), [V52_CTRL_MSGT_PP_SWITCH_OVER_REJECT] = MSG_DEF("SWITCH_OVER_REJECT", pp_swo_rej_mand_ies, 0), [V52_CTRL_MSGT_PP_PROTOCOL_ERROR] = MSG_DEF("PROTOCOL_ERROR", pp_perr_mand_ies, 0), [V52_CTRL_MSGT_PP_RESET_SN_COM] = MSG_DEF("RESET_SN_COM", NULL, 0), [V52_CTRL_MSGT_PP_RESET_SN_ACK] = MSG_DEF("RESET_SN_ACK", NULL, 0), }, .ie_def = { /* single byte, only upper nibble matches IEI */ [V51_CTRL_IEI_PULSE_NOTIFICATION] = { 0, "PULSE_NOTIFICATION" }, [V51_CTRL_IEI_LINE_NOTIFICATION] = { 0, "LINE_NOTIFICATION" }, [V51_CTRL_IEI_STATE] = { 0, "STATE" }, [V51_CTRL_IEI_AUTONOMOUS_SIG_SEQ] = { 0, "AUTONOMOUS_SIG_SEQ" }, [V51_CTRL_IEI_SEQUENCE_RESPONSE] = { 0, "SEQUENCE_RESPONSE" }, /* single byte: ISDN */ [V51_CTRL_IEI_PERFORMANCE_GRADING] = { 0, "PERFORMANCE_GRADING" }, [V51_CTRL_IEI_REJECTION_CAUSE] = { 0, "REJECTION_CAUSE" }, /* variable length: PSTN */ [V51_CTRL_IEI_SEQUENCE_NR] = { 1, "SEQUENCE_NR" }, [V51_CTRL_IEI_CADENCED_RINGING] = { 1, "CADENCED_RINGING" }, [V51_CTRL_IEI_PULSED_SIGNAL] = { 2, "PULSED_SIGNAL" }, [V51_CTRL_IEI_STEADY_SIGNAL] = { 1, "STEADY_SIGNAL" }, [V51_CTRL_IEI_DIGIT_SIGNAL] = { 1, "DIGIT_SIGNAL" }, [V51_CTRL_IEI_RECOGNITION_TIME] = { 2, "RECOGNITION_TIME" }, [V51_CTRL_IEI_ENABLE_AUTONOMOUS_ACK] = { 2, "ENABLE_AUTONOMOUS_ACK" }, [V51_CTRL_IEI_DISABLE_AUTONOMOUS_ACK] = { 1, "DISABLE_AUTONOMOUS_ACK" }, [V51_CTRL_IEI_CAUSE] = { 2, "CAUSE" }, [V51_CTRL_IEI_RESOURCE_UNAVAILABLE] = { 1, "RESOURCE_UNAVAILABLE" }, [V51_CTRL_IEI_ENABLE_METERING] = { 1, "ENABLE_METERING" }, [V51_CTRL_IEI_METERING_REPORT] = { 2, "METERING_REPORT" }, [V51_CTRL_IEI_ATTENUATION] = { 1, "ATTENUATION" }, /* variable length: ISDN */ [V51_CTRL_IEI_CTRL_F_ELEMENT] = { 1, "CTRL_F_ELEMENT" }, [V51_CTRL_IEI_CTRL_F_ID] = { 1, "CTRL_F_ID" }, [V51_CTRL_IEI_VARIANT] = { 1, "VARIANT" }, [V51_CTRL_IEI_INTERFACE_ID] = { 3, "INTERFACE_ID" }, /* variable length: LCP */ [V52_CTRL_IEI_LCP_LINK_CTRL_FUNCTION] = { 1, "LINK_CTRL_FUNCTION" }, /* variable length: BCC */ [V52_CTRL_IEI_BCC_USER_PORT_ID] = { 2, "USER_PORT_ID" }, [V52_CTRL_IEI_BCC_ISDN_PORT_TS_ID] = { 1, "ISDN_PORT_TS_ID" }, [V52_CTRL_IEI_BCC_V5_TS_ID] = { 2, "V5_TS_ID" }, [V52_CTRL_IEI_BCC_MULTI_TS_MAP] = { 9, "MULTI_TS_MAP" }, [V52_CTRL_IEI_BCC_REJECT_CAUSE] = { 1, "REJECT_CAUSE" }, [V52_CTRL_IEI_BCC_PROTOCOL_ERROR_CAUSE] = { 1, "PROTOCOL_ERR_CAUSE" }, [V52_CTRL_IEI_BCC_CONNECTION_INCOMPLETE]= { 1, "CONNECTION_INCOMPLETE" }, [V52_CTRL_IEI_BCC_INFO_TRANSFER_CAPABILITY] = { 1, "INFO_TRANSFER_CAPABILITY" }, /* variable length: PP */ [V52_CTRL_IEI_PP_SEQUENCE_NR] = { 1, "SEQUENCE_NR" }, [V52_CTRL_IEI_PP_PHYSICAL_C_CHAN_ID] = { 2, "PHYSICAL_C_CHAN_ID" }, [V52_CTRL_IEI_PP_REJECTION_CAUSE] = { 1, "REJECTION_CAUSE" }, [V52_CTRL_IEI_PP_PROTOCOL_ERROR_CAUSE] = { 1, "PROTOCOL_ERR_CAUSE" }, }, .msgt_names = v51_ctrl_msg_typ_str, }; static int v51_rcv_pstn(struct v5x_user_port *v5up, uint16_t l3_addr, uint8_t msg_type, const struct tlv_parsed *tp) { return 0; } static int v52_rcv_pp(struct v5x_interface *v5if, uint16_t l3_addr, uint8_t msg_type, const struct tlv_parsed *tp) { return 0; } static int v52_rcv_bcc(struct v5x_interface *v5if, uint16_t l3_addr, uint8_t msg_type, const struct tlv_parsed *tp) { return 0; } static int v52_rcv_lcp(struct v5x_interface *v5if, uint16_t l3_addr, uint8_t msg_type, const struct tlv_parsed *tp) { return 0; } /* main entry point for received V5 messages */ int v5x_rcv(struct osmo_dlsap_prim *odp, uint16_t dladdr, void *rx_cbdata) { struct v5x_interface *v5if = rx_cbdata; struct msgb *msg = odp->oph.msg; struct v51_l3_hdr *l3h; struct tlv_parsed tp; uint16_t l3_addr; struct v5x_user_port *v5up; int rc; // FIXME: switch (odp->oph.primitive) { case PRIM_DL_DATA: LOGP(DV5, LOGL_DEBUG, "DL-DATA indication received\n"); break; case PRIM_DL_EST: LOGP(DV5, LOGL_DEBUG, "DL-EST indication received\n"); v51_start_ctrl(v5if->control.ctrl); llist_for_each_entry(v5up, &v5if->user_ports, list) v51_start_ctrl(v5up->ctrl); goto out; case PRIM_DL_REL: LOGP(DV5, LOGL_DEBUG, "DL-REL indication received\n"); v51_stop_ctrl(v5if->control.ctrl); llist_for_each_entry(v5up, &v5if->user_ports, list) v51_stop_ctrl(v5up->ctrl); goto out; default: LOGP(DV5, LOGL_NOTICE, "Unhandled prim=%d\n", odp->oph.primitive); rc = -EINVAL; goto out; } l3h = msgb_l3(msg); if (msgb_l3len(msg) < sizeof(*l3h)) { LOGP(DV5, LOGL_ERROR, "Received short message (%u bytes < %lu)\n", msgb_l3len(msg), sizeof(*l3h)); rc = -EINVAL; goto out; } if (l3h->pdisc != V51_CTRL_PDISC) { LOGP(DV5, LOGL_ERROR, "Received unsupported protocol discriminator 0x%02x\n", l3h->pdisc); rc = -EINVAL; goto out; } rc = osmo_tlv_prot_parse(&v51_ctrl_msg_tlv, &tp, 1, l3h->msg_type, msgb_l3(msg) + sizeof(*l3h), msgb_l3len(msg) - sizeof(*l3h), 0, 0, DV5, __func__); if (rc < 0) goto out; l3_addr = v51_l3_addr_dec(ntohs(l3h->l3_addr), NULL); LOGP(DV5, LOGL_DEBUG, "Received message from AN with l3_addr = %d and msg_type %d\n", l3_addr, l3h->msg_type); switch (dladdr) { case V51_DLADDR_PSTN: /* PSTN signaling protocol */ switch (l3h->msg_type) { case V51_CTRL_MSGT_ESTABLISH: case V51_CTRL_MSGT_ESTABLISH_ACK: case V51_CTRL_MSGT_SIGNAL: case V51_CTRL_MSGT_SIGNAL_ACK: case V51_CTRL_MSGT_DISCONNECT: case V51_CTRL_MSGT_DISCONNECT_ACK: case V51_CTRL_MSGT_STATUS_ENQUIRY: case V51_CTRL_MSGT_STATUS: case V51_CTRL_MSGT_PROTOCOL_PARAMETER: /* look-up user port based on L3 addr? */ v5up = v5x_user_port_find(v5if, l3_addr); if (!v5up) { rc = -ENODEV; break; } rc = v51_rcv_pstn(v5up, l3_addr, l3h->msg_type, &tp); break; default: rc = -ENOTSUP; LOGP(DV5, LOGL_ERROR, "Received unsupported PSTN message type %s\n", osmo_tlv_prot_msg_name(&v51_ctrl_msg_tlv, l3h->msg_type)); } break; case V51_DLADDR_CTRL: /* control protocol (Section 14 G.964) */ switch (l3h->msg_type) { case V51_CTRL_MSGT_PORT_CTRL: case V51_CTRL_MSGT_PORT_CTRL_ACK: case V51_CTRL_MSGT_COMMON_CTRL: case V51_CTRL_MSGT_COMMON_CTRL_ACK: rc = v51_rcv_ctrl(v5if, l3_addr, l3h->msg_type, &tp); break; default: rc = -ENOTSUP; LOGP(DV5, LOGL_ERROR, "Received unsupported CTRL message type %s\n", osmo_tlv_prot_msg_name(&v51_ctrl_msg_tlv, l3h->msg_type)); } break; case V52_DLADDR_BCC: /* protection protocol (Section 18 G.965) */ switch (l3h->msg_type) { case V52_CTRL_MSGT_PP_SWITCH_OVER_REQ: case V52_CTRL_MSGT_PP_SWITCH_OVER_COM: case V52_CTRL_MSGT_PP_OS_SWITCH_OVER_COM: case V52_CTRL_MSGT_PP_SWITCH_OVER_ACK: case V52_CTRL_MSGT_PP_SWITCH_OVER_REJECT: case V52_CTRL_MSGT_PP_PROTOCOL_ERROR: case V52_CTRL_MSGT_PP_RESET_SN_COM: case V52_CTRL_MSGT_PP_RESET_SN_ACK: rc = v52_rcv_pp(v5if, l3_addr, l3h->msg_type, &tp); break; default: rc = -ENOTSUP; LOGP(DV5, LOGL_ERROR, "Received unsupported BCC message type %s\n", osmo_tlv_prot_msg_name(&v51_ctrl_msg_tlv, l3h->msg_type)); } break; case V52_DLADDR_PROTECTION: /* BCC protocol (Section 17 G.965) */ switch (l3h->msg_type) { case V52_CTRL_MSGT_ALLOCATION: case V52_CTRL_MSGT_ALLOCATION_COMPLETE: case V52_CTRL_MSGT_ALLOCATION_REJECT: case V52_CTRL_MSGT_DE_ALLOCATION: case V52_CTRL_MSGT_DE_ALLOCATION_COMPLETE: case V52_CTRL_MSGT_DE_ALLOCATION_REJECT: case V52_CTRL_MSGT_AUDIT: case V52_CTRL_MSGT_AUDIT_COMPLETE: case V52_CTRL_MSGT_AN_FAULT: case V52_CTRL_MSGT_AN_FAULT_ACK: case V52_CTRL_MSGT_PROTOCOL_ERROR: rc = v52_rcv_bcc(v5if, l3_addr, l3h->msg_type, &tp); break; default: rc = -ENOTSUP; LOGP(DV5, LOGL_ERROR, "Received unsupported PROTECTION message type %s\n", osmo_tlv_prot_msg_name(&v51_ctrl_msg_tlv, l3h->msg_type)); } break; case V52_DLADDR_LCP: /* Link control protocol (Section 16 G.965) */ switch (l3h->msg_type) { case V52_CTRL_MSGT_LCP_LINK_CTRL: case V52_CTRL_MSGT_LCP_LINK_CTRL_ACK: rc = v52_rcv_lcp(v5if, l3_addr, l3h->msg_type, &tp); break; default: rc = -ENOTSUP; LOGP(DV5, LOGL_ERROR, "Received unsupported LCP message type %s\n", osmo_tlv_prot_msg_name(&v51_ctrl_msg_tlv, l3h->msg_type)); } break; default: rc = -ENOTSUP; LOGP(DV5, LOGL_ERROR, "Received unsupported message type %s\n", osmo_tlv_prot_msg_name(&v51_ctrl_msg_tlv, l3h->msg_type)); } out: if (msg) msgb_free(msg); return rc; } /* send V5 messages to DL instance, given by dladdr */ int v5x_snd(struct v5x_interface *v5if, uint16_t dladdr, struct msgb *msg) { struct lapv5_instance *li; switch (dladdr) { case V51_DLADDR_PSTN: li = v5if->pstn.li; break; case V51_DLADDR_CTRL: li = v5if->control.li; break; case V52_DLADDR_BCC: li = v5if->bcc.li; break; case V52_DLADDR_PROTECTION: li = v5if->protection[0].li; break; case V52_DLADDR_LCP: li = v5if->lcp.li; break; } if (!li) { LOGP(DV5, LOGL_ERROR, "No instance for dladdr %d.\n", dladdr); msgb_free(msg); return -EINVAL; } return lapv5_dl_data_req(li, dladdr, msg); } // FIXME #define V5_MSGB_SIZE 128 #define V5_MSGB_HEADROOM 56 struct msgb *msgb_alloc_v5x(void) { struct msgb *msg; msg = msgb_alloc_headroom(V5_MSGB_SIZE, V5_MSGB_HEADROOM, "V5 MSG"); if (!msg) return NULL; msg->l3h = msg->data; return msg; }